feat: Further improve rotary encoder acceleration (#2584)
* Improve rotary encoder acceleration Fixes #2417 * Further improvement * Fix simu compilation
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
Vendored
+1
-1
Submodule radio/src/thirdparty/libopenui updated: 804ecd0e64...895e21d3f2
Reference in New Issue
Block a user