diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 5590014a4..8f6ea9769 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -135,27 +135,41 @@ void per10ms() #if defined(ROTARY_ENCODER_NAVIGATION) if (IS_ROTARY_ENCODER_NAVIGATION_ENABLE()) { static rotenc_t rePreviousValue; + static bool cw = false; rotenc_t reNewValue = (ROTARY_ENCODER_NAVIGATION_VALUE / ROTARY_ENCODER_GRANULARITY); - int8_t scrollRE = reNewValue - rePreviousValue; + rotenc_t scrollRE = reNewValue - rePreviousValue; if (scrollRE) { + static uint32_t lastEvent; rePreviousValue = reNewValue; - putEvent(scrollRE < 0 ? EVT_ROTARY_LEFT : EVT_ROTARY_RIGHT); - } + + bool new_cw = (scrollRE < 0) ? false : true; + if ((g_tmr10ms - lastEvent >= 10) || (cw == new_cw)) { // 100ms + + putEvent(new_cw ? EVT_ROTARY_RIGHT : EVT_ROTARY_LEFT); + #if defined(CPUARM) - // rotary encoder navigation speed (acceleration) detection/calculation - if (scrollRE) { - static uint32_t lastTick = 0; - static uint32_t delay = 0; - delay = (((get_tmr10ms() - lastTick) << 3) + delay) >> 1; // Modified moving average filter used for smoother change of speed - lastTick = get_tmr10ms(); - if (delay < ROTENC_DELAY_HIGHSPEED) - rotencSpeed = ROTENC_HIGHSPEED; - else if (delay < ROTENC_DELAY_MIDSPEED) - rotencSpeed = ROTENC_MIDSPEED; - else - rotencSpeed = ROTENC_LOWSPEED; - } + // rotary encoder navigation speed (acceleration) detection/calculation + static uint32_t delay = 2*ROTENC_DELAY_MIDSPEED; + + if (new_cw == cw) { + // Modified moving average filter used for smoother change of speed + delay = (((g_tmr10ms - lastEvent) << 3) + delay) >> 1; + } + else { + delay = 2*ROTENC_DELAY_MIDSPEED; + } + + if (delay < ROTENC_DELAY_HIGHSPEED) + rotencSpeed = ROTENC_HIGHSPEED; + else if (delay < ROTENC_DELAY_MIDSPEED) + rotencSpeed = ROTENC_MIDSPEED; + else + rotencSpeed = ROTENC_LOWSPEED; #endif + cw = new_cw; + lastEvent = g_tmr10ms; + } + } } #endif diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 59bcf05ae..1ae35521d 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -769,6 +769,8 @@ int getTrimValue(uint8_t phase, uint8_t idx); #define ROTARY_ENCODER_GRANULARITY (1) #elif defined(PCBSKY9X) #define ROTARY_ENCODER_GRANULARITY (2 << g_eeGeneral.rotarySteps) +#elif defined(PCBHORUS) + #define ROTARY_ENCODER_GRANULARITY (1) #else #define ROTARY_ENCODER_GRANULARITY (2) #endif diff --git a/radio/src/targets/horus/keys_driver.cpp b/radio/src/targets/horus/keys_driver.cpp index ce843e0ca..1a4b96830 100644 --- a/radio/src/targets/horus/keys_driver.cpp +++ b/radio/src/targets/horus/keys_driver.cpp @@ -20,7 +20,63 @@ #include "opentx.h" -uint32_t rotencPosition; +/* + * Rotary encoder handling based on state table: + * Copyright (C) by Ben Buxton + * + * This includes the state table definition bellow + * as well as the implementation of checkRotaryEncoder(). + * + * The below state table has, for each state (row), the new state + * to set based on the next encoder output. From left to right in, + * the table, the encoder outputs are 00, 01, 10, 11, and the value + * in that position is the new state to set. + */ + +#define R_START 0x0 +#define DIR_CW 0x10 +#define DIR_CCW 0x20 + +// Use the half-step state table (emits a code at 00 and 11) +#define R_CCW_BEGIN 0x1 +#define R_CW_BEGIN 0x2 +#define R_START_M 0x3 +#define R_CW_BEGIN_M 0x4 +#define R_CCW_BEGIN_M 0x5 +const unsigned char rotenc_table[6][4] = { + // R_START (00) + {R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START}, + // R_CCW_BEGIN + {R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START}, + // R_CW_BEGIN + {R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START}, + // R_START_M (11) + {R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START}, + // R_CW_BEGIN_M + {R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW}, + // R_CCW_BEGIN_M + {R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW}, +}; + +void checkRotaryEncoder() +{ + static uint8_t state = 0; + uint32_t pins = ROTARY_ENCODER_POSITION(); + + state = rotenc_table[state & 0x0F][pins]; + if ((state & 0x30) && !keyState(KEY_ENTER)) { + if ((state & 0x30) == DIR_CW) { + --rotencValue[0]; + } + else { + ++rotencValue[0]; + } + } +} + +/* + * End of the rotary encoder handler code + */ uint32_t readKeys() { @@ -91,20 +147,6 @@ uint8_t keyDown() return readKeys(); } -void checkRotaryEncoder() -{ - uint32_t newpos = ROTARY_ENCODER_POSITION(); - if (newpos != rotencPosition && !keyState(KEY_ENTER)) { - if ((rotencPosition & 0x01) ^ ((newpos & 0x02) >> 1)) { - --rotencValue[0]; - } - else { - ++rotencValue[0]; - } - rotencPosition = newpos; - } -} - /* TODO common to ARM */ void readKeysAndTrims() { @@ -239,6 +281,4 @@ void keysInit() GPIO_InitStructure.GPIO_Pin = KEYS_GPIOJ_PINS; GPIO_Init(GPIOJ, &GPIO_InitStructure); - - rotencPosition = ROTARY_ENCODER_POSITION(); }