feat: Further improve rotary encoder acceleration (#2584)

* Improve rotary encoder acceleration

Fixes #2417

* Further improvement

* Fix simu compilation
This commit is contained in:
Raphael Coeffic
2022-10-19 20:36:29 +10:00
committed by GitHub
parent c8d6a50685
commit ba713b6b8d
9 changed files with 98 additions and 56 deletions
+26 -16
View File
@@ -232,16 +232,18 @@ extern "C" void touchDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data)
}
#if defined(ROTARY_ENCODER_NAVIGATION)
extern volatile uint32_t rotencDt;
static int8_t _rotary_enc_accel = 0;
static void rotaryDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
static rotenc_t prevPos = 0;
static int8_t prevDir = 0;
static int8_t accel = 0;
static tmr10ms_t lastEvent = 0;
static uint32_t lastDt = 0;
rotenc_t newPos = (ROTARY_ENCODER_NAVIGATION_VALUE / ROTARY_ENCODER_GRANULARITY);
auto diff = newPos - prevPos;
prevPos = newPos;
rotenc_t newPos = ROTARY_ENCODER_NAVIGATION_VALUE;
rotenc_t diff = (newPos - prevPos) / ROTARY_ENCODER_GRANULARITY;
prevPos += diff * ROTARY_ENCODER_GRANULARITY;
data->enc_diff = (int16_t)diff;
data->state = LV_INDEV_STATE_RELEASED;
@@ -264,23 +266,31 @@ static void rotaryDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data)
else if (diff > 0) dir = 1;
if (use_accel && (dir == prevDir)) {
auto speed = (g_tmr10ms - lastEvent) / abs(diff);
if (speed <= ROTENC_DELAY_HIGHSPEED/2) { // 80 ms
// below ROTENC_DELAY_HIGHSPEED btw. events: accelerate
accel = min((int8_t)(accel + 1), (int8_t)25);
} else if (speed >= ROTENC_DELAY_MIDSPEED/2) { // 160 ms
// above ROTENC_DELAY_MIDSPEED btw. events: normal speed
accel = 0;
auto dt = rotencDt - lastDt;
auto dx_dt = (abs(diff) * 50) / max(dt, (uint32_t)1);
_rotary_enc_accel = (int8_t)dx_dt;
if (_rotary_enc_accel > 0) {
data->enc_diff = (int16_t)diff * (int16_t)_rotary_enc_accel;
}
lastEvent = g_tmr10ms;
data->enc_diff = (int16_t)diff * max((int16_t)accel, (int16_t)1);
} else {
accel = 0;
_rotary_enc_accel = 0;
}
prevDir = dir;
lastDt = rotencDt;
}
}
#endif
// libopenui_depends.h
int8_t rotaryEncoderGetAccel() { return _rotary_enc_accel; }
#else // !defined(ROTARY_ENCODER_NAVIGATION)
// libopenui_depends.h
int8_t rotaryEncoderGetAccel() { return 0; }
#endif // defined(ROTARY_ENCODER_NAVIGATION)
/**
* Helper function to translate a colorFlags value to a lv_color_t suitable
+10
View File
@@ -74,12 +74,22 @@ void ColorBar::on_key(lv_event_t* e)
uint32_t key = *(uint32_t*)lv_event_get_param(e);
if (key == LV_KEY_LEFT) {
if (bar->value > 0) {
auto accel = rotaryEncoderGetAccel();
bar->value--;
if (accel > 0) {
if (accel > bar->value) bar->value = 0;
else bar->value -= accel;
}
lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr);
}
} else if (key == LV_KEY_RIGHT) {
if (bar->value < bar->maxValue) {
auto accel = rotaryEncoderGetAccel();
bar->value++;
if (accel > 0) {
if (accel < bar->maxValue - bar->value) bar->value += accel;
else bar->value = bar->maxValue;
}
lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr);
}
}
+3
View File
@@ -40,6 +40,9 @@ class GVarNumberEdit : public Window
void switchGVarMode();
void setSuffix(std::string value);
void setFastStep(int value) { num_field->setFastStep(value); }
void setAccelFactor(int value) { num_field->setAccelFactor(value); }
protected:
Choice* gvar_field = nullptr;
NumberEdit* num_field = nullptr;
+3
View File
@@ -301,6 +301,7 @@ void GVarEditWindow::buildBody(FormWindow * window)
setProperties();
}
);
min->setAccelFactor(16);
grid.nextLine();
new StaticText(window, grid.getLabelSlot(), STR_MAX, 0, COLOR_THEME_PRIMARY1);
@@ -312,6 +313,7 @@ void GVarEditWindow::buildBody(FormWindow * window)
setProperties();
}
);
max->setAccelFactor(16);
grid.nextLine();
char flightModeName[16];
FlightModeData * fmData;
@@ -337,6 +339,7 @@ void GVarEditWindow::buildBody(FormWindow * window)
values[flightMode] = new NumberEdit(window, grid.getFieldSlot(2, 1), GVAR_MIN + gvar->min, GVAR_MAX + MAX_FLIGHT_MODES - 1,
GET_SET_DEFAULT(fmData->gvars[index]));
values[flightMode]->setAccelFactor(16);
grid.nextLine();
}
+14 -6
View File
@@ -137,8 +137,10 @@ void OutputEditWindow::buildBody(FormWindow* form)
// Offset
new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_SUBTRIM, 0,
COLOR_THEME_PRIMARY1);
new GVarNumberEdit(line, rect_t{}, -LIMIT_STD_MAX, +LIMIT_STD_MAX,
GET_SET_DEFAULT(output->offset), PREC1);
auto off = new GVarNumberEdit(line, rect_t{}, -LIMIT_STD_MAX, +LIMIT_STD_MAX,
GET_SET_DEFAULT(output->offset), PREC1);
off->setFastStep(20);
off->setAccelFactor(8);
// Min
line = form->newLine(&grid);
@@ -146,12 +148,16 @@ void OutputEditWindow::buildBody(FormWindow* form)
minEdit = new GVarNumberEdit(line, rect_t{}, -limit, 0, GET_SET_DEFAULT(output->min),
PREC1, -LIMIT_STD_MAX);
minText->setBackgroundColor(COLOR_THEME_ACTIVE);
minEdit->setFastStep(20);
minEdit->setAccelFactor(16);
// Max
maxText = new StaticText(line, rect_t{}, TR_MAX, 0, COLOR_THEME_PRIMARY1);
maxEdit = new GVarNumberEdit(line, rect_t{}, 0, +limit, GET_SET_DEFAULT(output->max),
PREC1, +LIMIT_STD_MAX);
maxText->setBackgroundColor(COLOR_THEME_ACTIVE);
maxEdit->setFastStep(20);
maxEdit->setAccelFactor(16);
// Direction
line = form->newLine(&grid);
@@ -177,10 +183,12 @@ void OutputEditWindow::buildBody(FormWindow* form)
lv_label_set_long_mode(label->getLvObj(), LV_LABEL_LONG_WRAP);
lv_obj_set_style_grid_cell_x_align(label->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
new NumberEdit(line, rect_t{}, PPM_CENTER - PPM_CENTER_MAX,
PPM_CENTER + PPM_CENTER_MAX,
GET_VALUE(output->ppmCenter + PPM_CENTER),
SET_VALUE(output->ppmCenter, newValue - PPM_CENTER));
auto center = new NumberEdit(line, rect_t{}, PPM_CENTER - PPM_CENTER_MAX,
PPM_CENTER + PPM_CENTER_MAX,
GET_VALUE(output->ppmCenter + PPM_CENTER),
SET_VALUE(output->ppmCenter, newValue - PPM_CENTER));
center->setFastStep(20);
center->setAccelFactor(8);
// Subtrims mode
label = new StaticText(line, rect_t{}, TR_LIMITS_HEADERS_SUBTRIMMODE, 0,
+1
View File
@@ -94,6 +94,7 @@ TimerWindow::TimerWindow(uint8_t timer) : Page(ICON_STATS_TIMERS)
auto timerValue =
new TimeEdit(line, rect_t{}, 0, TIMER_MAX, GET_DEFAULT(p_timer->start),
timerValueUpdater(timer));
timerValue->setAccelFactor(16);
// Timer direction
auto timerDirLine = form->newLine(&grid);
@@ -28,13 +28,11 @@
#include "opentx.h"
#endif
static uint8_t rotencPosition;
volatile rotenc_t rotencValue;
volatile rotenc_t rotencValue = 0;
volatile uint32_t rotencDt = 0;
void rotaryEncoderInit()
{
rotencPosition = ROTARY_ENCODER_POSITION();
ROTARY_ENCODER_TIMER->ARR = 99; // 100uS
ROTARY_ENCODER_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS
ROTARY_ENCODER_TIMER->CCER = 0;
@@ -90,50 +88,58 @@ void rotaryEncoderInit()
void rotaryEncoderCheck()
{
#if (defined(RADIO_FAMILY_T16) && !defined(RADIO_T18)) || defined(RADIO_TX12)
static uint8_t state = 0;
uint8_t pins = ROTARY_ENCODER_POSITION();
#if (defined(RADIO_FAMILY_T16) && !defined(RADIO_T18)) || defined(RADIO_TX12)
if (pins != (state & 0x03) && !(readKeys() & (1 << KEY_ENTER))) {
if ((pins ^ (state & 0x03)) == 0x03)
{
if (pins == 3)
{
rotencValue += INC_ROT_2;
}
else
{
rotencValue -= INC_ROT_2;
}
}
else
{
if ((state & 0x01) ^ ((pins & 0x02) >> 1))
{
rotencValue -= INC_ROT;
}
else
{
rotencValue += INC_ROT;
}
}
if ((pins ^ (state & 0x03)) == 0x03) {
if (pins == 3) {
rotencValue += INC_ROT_2;
} else {
rotencValue -= INC_ROT_2;
}
} else {
if ((state & 0x01) ^ ((pins & 0x02) >> 1)) {
rotencValue -= INC_ROT;
} else {
rotencValue += INC_ROT;
}
}
state &= ~0x03;
state |= pins;
}
#else
uint8_t newPosition = ROTARY_ENCODER_POSITION();
if (newPosition != rotencPosition && !(readKeys() & (1 << KEY_ENTER))) {
if (pins != state && !(readKeys() & (1 << KEY_ENTER))) {
#if defined(RADIO_ZORRO) || defined(RADIO_TX12MK2) // def. rotation dir is inverse of other radios
if (!(rotencPosition & 0x01) ^ ((newPosition & 0x02) >> 1)) {
if (!(state & 0x01) ^ ((pins & 0x02) >> 1)) {
#else
if ((rotencPosition & 0x01) ^ ((newPosition & 0x02) >> 1)) {
if ((state & 0x01) ^ ((pins & 0x02) >> 1)) {
#endif
rotencValue -= INC_ROT;
} else {
rotencValue += INC_ROT;
}
rotencPosition = newPosition;
#endif
state = pins;
}
#endif
#if !defined(BOOT) && defined(COLORLCD)
static uint32_t last_tick = 0;
static rotenc_t last_value = 0;
rotenc_t value = rotencValue;
rotenc_t diff = (value - last_value) / ROTARY_ENCODER_GRANULARITY;
if (diff != 0) {
uint32_t now = RTOS_GET_MS();
uint32_t dt = now - last_tick;
// pre-compute accumulated dt (dx/dt is done later in LVGL driver)
rotencDt += dt;
last_tick = now;
last_value += diff * ROTARY_ENCODER_GRANULARITY;
}
#endif
}
void rotaryEncoderStartDelay()
+1
View File
@@ -49,6 +49,7 @@ uint32_t telemetryErrors = 0;
typedef int32_t rotenc_t;
volatile rotenc_t rotencValue = 0;
volatile uint32_t rotencDt = 0;
// TODO: remove all STM32 defs
GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj;