kopia lustrzana https://github.com/OpenRTX/OpenRTX
Add support for encoder knob on MD-UV380
Added: qdec, a header only quadrature encoder library Added: EXTI15_10_IRQHandler to handle the encoder knob Changed: platform_init() for the MD-UV380 now configures the EXTI15_10 interrupt. Changed: platform_getChSelector now returns signed int8 Changed: size of settings_t.valid went from 6 to 7 Without this change, pressing the macro button crashes the radio, I haven't investigated and I don't remember how I found that solution. Changed: meson.build includes the qdec libraryreplace/3348d2a8f3f43dc876bb0adbc3a32025541de502
rodzic
b6eab0fde7
commit
e5c5ee90f2
|
@ -0,0 +1,60 @@
|
|||
enum QDECODER_EVENT {
|
||||
QDECODER_EVENT_NONE = 0x00u,
|
||||
QDECODER_EVENT_CW = 0x80u,
|
||||
QDECODER_EVENT_CCW = 0x40u,
|
||||
};
|
||||
|
||||
// state is internal... needs never be exposed to callers
|
||||
enum QDECODER_STATE {
|
||||
QDECODER_STATE_START = 0x00u,
|
||||
QDECODER_STATE_CW_A = 0x01u,
|
||||
QDECODER_STATE_CW_B = 0x02u,
|
||||
QDECODER_STATE_CW_C = 0x03u,
|
||||
QDECODER_STATE_MID = 0x04u,
|
||||
QDECODER_STATE_CCW_A = 0x05u,
|
||||
QDECODER_STATE_CCW_B = 0x06u,
|
||||
QDECODER_STATE_CCW_C = 0x07u,
|
||||
};
|
||||
|
||||
const uint8_t QDECODER_EVENT_BITMASK = 0xC0; // events are the most significant two bits
|
||||
const uint8_t QDECODER_STATE_BITMASK = 0x07; // states are in the least significant three bits
|
||||
|
||||
const uint8_t HALF_STEP_STATE_TRANSITIONS[8][4] = {
|
||||
// 0 = start
|
||||
{QDECODER_STATE_MID, QDECODER_STATE_CW_A, QDECODER_STATE_CCW_A, QDECODER_STATE_START },
|
||||
// 1 = CW_A
|
||||
{QDECODER_EVENT_CW |
|
||||
QDECODER_STATE_MID, QDECODER_STATE_CW_A, QDECODER_STATE_START, QDECODER_STATE_START },
|
||||
// 2 = CW_B (unused in half-step mode)
|
||||
{QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START },
|
||||
// 3 = CW_C
|
||||
{QDECODER_STATE_MID, QDECODER_STATE_MID, QDECODER_STATE_CW_C, QDECODER_STATE_START | QDECODER_EVENT_CW },
|
||||
// 4 = mid
|
||||
{QDECODER_STATE_MID, QDECODER_STATE_CCW_C, QDECODER_STATE_CW_C, QDECODER_STATE_START },
|
||||
// 5 = CCW_A
|
||||
{QDECODER_EVENT_CCW |
|
||||
QDECODER_STATE_MID, QDECODER_STATE_START, QDECODER_STATE_CCW_A, QDECODER_STATE_START },
|
||||
// 6 = CCW_B (unused in half-step mode)
|
||||
{QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START },
|
||||
// 7 = CCW_C
|
||||
{QDECODER_STATE_MID, QDECODER_STATE_CCW_C, QDECODER_STATE_MID, QDECODER_STATE_START | QDECODER_EVENT_CCW},
|
||||
};
|
||||
|
||||
const uint8_t FULL_STEP_STATE_TRANSITIONS[8][4] = {
|
||||
// 0 = start
|
||||
{QDECODER_STATE_START, QDECODER_STATE_CW_A, QDECODER_STATE_CCW_A, QDECODER_STATE_START },
|
||||
// 1 = CW_A
|
||||
{QDECODER_STATE_CW_B, QDECODER_STATE_CW_A, QDECODER_STATE_START, QDECODER_STATE_START },
|
||||
// 2 = CW_B
|
||||
{QDECODER_STATE_CW_B, QDECODER_STATE_CW_A, QDECODER_STATE_CW_C, QDECODER_STATE_START },
|
||||
// 3 = CW_C
|
||||
{QDECODER_STATE_CW_B, QDECODER_STATE_START, QDECODER_STATE_CW_C, QDECODER_STATE_START | QDECODER_EVENT_CW },
|
||||
// 4 = mid (unused in full step mode ...)
|
||||
{QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START, QDECODER_STATE_START },
|
||||
// 5 = CCW_A
|
||||
{QDECODER_STATE_CCW_B, QDECODER_STATE_START, QDECODER_STATE_CCW_A, QDECODER_STATE_START },
|
||||
// 6 = CCW_B
|
||||
{QDECODER_STATE_CCW_B, QDECODER_STATE_CCW_C, QDECODER_STATE_CCW_A, QDECODER_STATE_START },
|
||||
// 7 = CCW_C
|
||||
{QDECODER_STATE_CCW_B, QDECODER_STATE_CCW_C, QDECODER_STATE_START, QDECODER_STATE_START | QDECODER_EVENT_CCW },
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 SimpleHacks ("Simple hacks for a simple life")
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,2 @@
|
|||
This is a plain C header library lightly adapted from the SimpleHacks QDEC library.
|
||||
Find the original source here: https://github.com/SimpleHacks/QDEC
|
|
@ -55,8 +55,12 @@ minmea_src = ['lib/minmea/minmea.c']
|
|||
|
||||
minmea_inc = ['lib/minmea/include']
|
||||
|
||||
## QDEC, a very simple, header only, quadrature decoding library
|
||||
|
||||
qdec_inc = ['lib/qdec/include']
|
||||
|
||||
src = openrtx_src + minmea_src
|
||||
inc = openrtx_inc + rtos_inc + minmea_inc
|
||||
inc = openrtx_inc + rtos_inc + minmea_inc + qdec_inc
|
||||
|
||||
##
|
||||
## Definitions
|
||||
|
|
|
@ -101,7 +101,7 @@ float platform_getVolumeLevel();
|
|||
/**
|
||||
* This function reads and returns the current channel selector level.
|
||||
*/
|
||||
uint8_t platform_getChSelector();
|
||||
int8_t platform_getChSelector();
|
||||
|
||||
/**
|
||||
* This function reads and returns the current PTT status.
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t valid[6]; // Should contain "OPNRTX" in a valid settings_t
|
||||
uint8_t valid[7]; // Should contain "OPNRTX" in a valid settings_t
|
||||
uint8_t brightness;
|
||||
uint8_t contrast;
|
||||
int8_t utc_timezone;
|
||||
|
|
|
@ -53,14 +53,22 @@ keyboard_t kbd_getKeys()
|
|||
keyboard_t keys = 0;
|
||||
|
||||
/* Use absolute position knob to emulate left and right buttons */
|
||||
static uint8_t old_pos = 0;
|
||||
uint8_t new_pos = platform_getChSelector();
|
||||
static int8_t old_pos = 0;
|
||||
int8_t new_pos = platform_getChSelector();
|
||||
if (old_pos != new_pos)
|
||||
{
|
||||
if (new_pos < old_pos)
|
||||
int8_t diff = old_pos - new_pos;
|
||||
if (diff < 0)
|
||||
keys |= KEY_LEFT;
|
||||
else
|
||||
else if (diff > 0)
|
||||
keys |= KEY_RIGHT;
|
||||
else
|
||||
{
|
||||
if (old_pos < 0)
|
||||
keys |= KEY_LEFT;
|
||||
else
|
||||
keys |= KEY_RIGHT;
|
||||
}
|
||||
old_pos = new_pos;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,11 @@
|
|||
#include <calibInfo_MDx.h>
|
||||
#include <interfaces/nvmem.h>
|
||||
#include <interfaces/rtc.h>
|
||||
#include <qdec.h>
|
||||
|
||||
mduv3x0Calib_t calibration;
|
||||
hwInfo_t hwInfo;
|
||||
static int8_t knob_pos = 0;
|
||||
|
||||
#ifdef ENABLE_BKLIGHT_DIMMING
|
||||
void _Z29TIM1_TRG_COM_TIM11_IRQHandlerv()
|
||||
|
@ -46,6 +48,42 @@ void _Z29TIM1_TRG_COM_TIM11_IRQHandlerv()
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note that this interrupt handler currently assumes only the encoder will
|
||||
* ever cause this interrupt to fire
|
||||
*/
|
||||
void _Z20EXTI15_10_IRQHandlerv()
|
||||
{
|
||||
/* State storage */
|
||||
static uint8_t last_state = 0;
|
||||
|
||||
/* Read curent pin state */
|
||||
uint8_t pin_state = gpio_readPin(CH_SELECTOR_1)<<1 | gpio_readPin(CH_SELECTOR_0);
|
||||
/* Look up next state */
|
||||
uint8_t next_state = HALF_STEP_STATE_TRANSITIONS[last_state][pin_state];
|
||||
/* update state for next call */
|
||||
last_state = next_state & QDECODER_STATE_BITMASK;
|
||||
|
||||
/* Mask out events to switch on */
|
||||
uint8_t event = next_state & QDECODER_EVENT_BITMASK;
|
||||
|
||||
/* Update file global knob_pos variable */
|
||||
switch (event)
|
||||
{
|
||||
case QDECODER_EVENT_CW:
|
||||
knob_pos++;
|
||||
break;
|
||||
case QDECODER_EVENT_CCW:
|
||||
knob_pos--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear pin change flags */
|
||||
EXTI->PR = EXTI_PR_PR11 | EXTI_PR_PR14;
|
||||
}
|
||||
|
||||
void platform_init()
|
||||
{
|
||||
/* Configure GPIOs */
|
||||
|
@ -55,8 +93,19 @@ void platform_init()
|
|||
gpio_setMode(LCD_BKLIGHT, OUTPUT);
|
||||
gpio_clearPin(LCD_BKLIGHT);
|
||||
|
||||
gpio_setMode(CH_SELECTOR_0, INPUT);
|
||||
gpio_setMode(CH_SELECTOR_1, INPUT);
|
||||
gpio_setMode(CH_SELECTOR_0, INPUT_PULL_UP);
|
||||
gpio_setMode(CH_SELECTOR_1, INPUT_PULL_UP);
|
||||
|
||||
EXTI->IMR |= EXTI_IMR_MR11 | EXTI_IMR_MR14;
|
||||
EXTI->RTSR |= EXTI_RTSR_TR11 | EXTI_RTSR_TR14;
|
||||
EXTI->FTSR |= EXTI_FTSR_TR11 | EXTI_FTSR_TR14;
|
||||
|
||||
SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI11_PB;
|
||||
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR4_EXTI14_PE;
|
||||
|
||||
NVIC_ClearPendingIRQ(EXTI15_10_IRQn);
|
||||
NVIC_SetPriority(EXTI15_10_IRQn, 15);
|
||||
NVIC_EnableIRQ(EXTI15_10_IRQn);
|
||||
|
||||
gpio_setMode(PTT_SW, INPUT_PULL_UP);
|
||||
|
||||
|
@ -150,13 +199,13 @@ float platform_getVolumeLevel()
|
|||
return adc1_getMeasurement(1);
|
||||
}
|
||||
|
||||
uint8_t platform_getChSelector()
|
||||
int8_t platform_getChSelector()
|
||||
{
|
||||
static const uint8_t rsPositions[] = { 1, 4, 2, 3};
|
||||
int pos = gpio_readPin(CH_SELECTOR_0)
|
||||
| (gpio_readPin(CH_SELECTOR_1) << 1);
|
||||
|
||||
return rsPositions[pos];
|
||||
/*
|
||||
* The knob_pos variable is set in the EXTI15_10 interrupt handler
|
||||
* this is safe because interrupt nesting is not allowed.
|
||||
*/
|
||||
return knob_pos;
|
||||
}
|
||||
|
||||
bool platform_getPttStatus()
|
||||
|
|
Ładowanie…
Reference in New Issue