diff --git a/meson.build b/meson.build
index 54a4d36c..910ab78c 100644
--- a/meson.build
+++ b/meson.build
@@ -34,6 +34,7 @@ openrtx_inc = ['openrtx/include',
'platform/drivers/tones',
'platform/drivers/baseband',
'platform/drivers/backlight',
+ 'platform/drivers/chSelector',
'openrtx/include/fonts/adafruit']
# Add to sources either the main executable or a platform test
@@ -218,6 +219,7 @@ mduv3x0_src = src + mdx_src + stm32f405_src + ['platform/drivers/NVM/nvmem_MDUV3
'platform/targets/MD-UV3x0/platform.c',
'platform/drivers/keyboard/keyboard_MD3x.c',
'platform/drivers/display/HX8353_MD3x.cpp',
+ 'platform/drivers/chSelector/chSelector_UV3x0.c',
'platform/drivers/baseband/radio_UV3x0.c',
'platform/drivers/baseband/AT1846S_UV3x0.c',
'platform/drivers/baseband/HR_C6000_UV3x0.c',
@@ -232,6 +234,7 @@ mduv3x0_def = def + stm32f405_def + {'PLATFORM_MDUV3x0': '', 'timegm': 'mktime'}
md9600_src = src + mdx_src + stm32f405_src + ['platform/targets/MD-9600/platform.c',
'platform/drivers/display/ST7567_MD9600.c',
'platform/drivers/keyboard/keyboard_MD9600.c',
+ 'platform/drivers/chSelector/chSelector_MD9600.c',
'platform/drivers/baseband/radio_MD9600.c',
'platform/drivers/NVM/nvmem_MD9600.c',
'platform/drivers/NVM/spiFlash_MD9600.c']
diff --git a/platform/drivers/chSelector/chSelector.h b/platform/drivers/chSelector/chSelector.h
new file mode 100644
index 00000000..30d4f573
--- /dev/null
+++ b/platform/drivers/chSelector/chSelector.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Caleb Jamison *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef CH_SELECTOR_H
+#define CH_SELECTOR_H
+
+/**
+ * Low-level driver for correct handling of channel selector knobs connected to
+ * a quadrature encoder.
+ * This header file only provides the API for driver initialisation and shutdown,
+ * while the readout of current encoder position is provided by target-specific
+ * sources by implementating platform_getChSelector().
+ */
+
+/**
+ * Initialise channel selector driver.
+ */
+void chSelector_init();
+
+/**
+ * Terminate channel selector driver.
+ */
+void chSelector_terminate();
+
+#endif /* CH_SELECTOR_H */
diff --git a/platform/drivers/chSelector/chSelector_MD9600.c b/platform/drivers/chSelector/chSelector_MD9600.c
new file mode 100644
index 00000000..b8a4e8b4
--- /dev/null
+++ b/platform/drivers/chSelector/chSelector_MD9600.c
@@ -0,0 +1,105 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+#include "chSelector.h"
+
+static uint8_t last_state = 0; /* State storage */
+static int8_t knob_pos = 0; /* Knob position */
+
+
+/* Name of interrupt handler is mangled for C++ compatibility */
+void _Z20EXTI15_10_IRQHandlerv()
+{
+ if(EXTI->PR & (EXTI_PR_PR10 | EXTI_PR_PR11))
+ {
+ /* Clear interrupt flags */
+ EXTI->PR = EXTI_PR_PR10 | EXTI_PR_PR11;
+
+ /* 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 knob_pos variable */
+ switch(event)
+ {
+ case QDECODER_EVENT_CW:
+ knob_pos++;
+ break;
+ case QDECODER_EVENT_CCW:
+ knob_pos--;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+void chSelector_init()
+{
+ gpio_setMode(CH_SELECTOR_0, INPUT_PULL_UP);
+ gpio_setMode(CH_SELECTOR_1, INPUT_PULL_UP);
+
+ /*
+ * Configure GPIO interrupts: encoder signal is on PB10 and PB11
+ */
+ EXTI->IMR |= EXTI_IMR_MR10 | EXTI_IMR_MR11;
+ EXTI->RTSR |= EXTI_RTSR_TR10 | EXTI_RTSR_TR11;
+ EXTI->FTSR |= EXTI_FTSR_TR10 | EXTI_FTSR_TR11;
+
+ SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI10_PB
+ | SYSCFG_EXTICR3_EXTI11_PB;
+
+ NVIC_ClearPendingIRQ(EXTI15_10_IRQn);
+ NVIC_SetPriority(EXTI15_10_IRQn, 15);
+ NVIC_EnableIRQ(EXTI15_10_IRQn);
+}
+
+void chSelector_terminate()
+{
+ EXTI->IMR &= ~(EXTI_IMR_MR10 | EXTI_IMR_MR11);
+ NVIC_DisableIRQ(EXTI15_10_IRQn);
+}
+
+
+/*
+ * This function is defined in platform.h
+ */
+int8_t platform_getChSelector()
+{
+ /*
+ * The knob_pos variable is set in the EXTI15_10 interrupt handler
+ * this is safe because interrupt nesting is not allowed.
+ */
+ return knob_pos;
+}
diff --git a/platform/drivers/chSelector/chSelector_UV3x0.c b/platform/drivers/chSelector/chSelector_UV3x0.c
new file mode 100644
index 00000000..85cd6a53
--- /dev/null
+++ b/platform/drivers/chSelector/chSelector_UV3x0.c
@@ -0,0 +1,105 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+#include "chSelector.h"
+
+static uint8_t last_state = 0; /* State storage */
+static int8_t knob_pos = 0; /* Knob position */
+
+
+/* Name of interrupt handler is mangled for C++ compatibility */
+void _Z20EXTI15_10_IRQHandlerv()
+{
+ if(EXTI->PR & (EXTI_PR_PR11 | EXTI_PR_PR14))
+ {
+ /* Clear interrupt flags */
+ EXTI->PR = EXTI_PR_PR11 | EXTI_PR_PR14;
+
+ /* 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 knob_pos variable */
+ switch(event)
+ {
+ case QDECODER_EVENT_CW:
+ knob_pos++;
+ break;
+ case QDECODER_EVENT_CCW:
+ knob_pos--;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+void chSelector_init()
+{
+ gpio_setMode(CH_SELECTOR_0, INPUT_PULL_UP);
+ gpio_setMode(CH_SELECTOR_1, INPUT_PULL_UP);
+
+ /*
+ * Configure GPIO interrupts: encoder signal is on PB11 and PE14
+ */
+ 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);
+}
+
+void chSelector_terminate()
+{
+ EXTI->IMR &= ~(EXTI_IMR_MR1 | EXTI_IMR_MR14);
+ NVIC_DisableIRQ(EXTI15_10_IRQn);
+}
+
+
+/*
+ * This function is defined in platform.h
+ */
+int8_t platform_getChSelector()
+{
+ /*
+ * The knob_pos variable is set in the EXTI15_10 interrupt handler
+ * this is safe because interrupt nesting is not allowed.
+ */
+ return knob_pos;
+}
diff --git a/platform/targets/MD-9600/platform.c b/platform/targets/MD-9600/platform.c
index 861f3d6e..0ac0fdf7 100644
--- a/platform/targets/MD-9600/platform.c
+++ b/platform/targets/MD-9600/platform.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
hwInfo_t hwInfo;
@@ -76,6 +77,7 @@ void platform_init()
toneGen_init(); /* Initialise tone generator */
rtc_init(); /* Initialise RTC */
backlight_init(); /* Initialise backlight driver */
+ chSelector_init(); /* Initialise channel selector handler */
}
void platform_terminate()
@@ -87,6 +89,7 @@ void platform_terminate()
adc1_terminate();
toneGen_terminate();
rtc_terminate();
+ chSelector_terminate();
/* Finally, remove power supply */
gpio_clearPin(PWR_SW);
@@ -112,15 +115,6 @@ float platform_getVolumeLevel()
return 0.0f;
}
-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];
-}
-
bool platform_getPttStatus()
{
/* PTT line has a pullup resistor with PTT switch closing to ground */
@@ -160,6 +154,12 @@ const hwInfo_t *platform_getHwInfo()
return &hwInfo;
}
+/*
+ * NOTE: implementation of this API function is provided in
+ * platform/drivers/chSelector/chSelector_MD9600.c
+ */
+// int8_t platform_getChSelector()
+
/*
* NOTE: implementation of this API function is provided in
* platform/drivers/backlight/backlight_MDx.c
diff --git a/platform/targets/MD-UV3x0/platform.c b/platform/targets/MD-UV3x0/platform.c
index 440e8f9e..216a4dd7 100644
--- a/platform/targets/MD-UV3x0/platform.c
+++ b/platform/targets/MD-UV3x0/platform.c
@@ -25,7 +25,7 @@
#include
#include
#include
-#include
+#include
#ifdef ENABLE_BKLIGHT_DIMMING
#include
@@ -33,43 +33,6 @@
mduv3x0Calib_t calibration;
hwInfo_t hwInfo;
-static int8_t knob_pos = 0;
-
-/*
- * 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()
{
@@ -77,20 +40,6 @@ void platform_init()
gpio_setMode(GREEN_LED, OUTPUT);
gpio_setMode(RED_LED, OUTPUT);
- 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);
gpio_setMode(PWR_SW, OUTPUT);
@@ -108,6 +57,7 @@ void platform_init()
nvm_readCalibData(&calibration); /* Load calibration data */
nvm_loadHwInfo(&hwInfo); /* Load hardware information data */
rtc_init(); /* Initialise RTC */
+ chSelector_init(); /* Initialise channel selector handler */
#ifdef ENABLE_BKLIGHT_DIMMING
backlight_init(); /* Initialise backlight driver */
@@ -134,6 +84,7 @@ void platform_terminate()
adc1_terminate();
nvm_terminate();
rtc_terminate();
+ chSelector_terminate();
/* Finally, remove power supply */
gpio_clearPin(PWR_SW);
@@ -159,15 +110,6 @@ float platform_getVolumeLevel()
return adc1_getMeasurement(ADC_VOL_CH);
}
-int8_t platform_getChSelector()
-{
- /*
- * 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()
{
/* PTT line has a pullup resistor with PTT switch closing to ground */
@@ -229,6 +171,12 @@ const hwInfo_t *platform_getHwInfo()
return &hwInfo;
}
+/*
+ * NOTE: implementation of this API function is provided in
+ * platform/drivers/chSelector/chSelector_MDUV3x0.c
+ */
+// int8_t platform_getChSelector()
+
/*
* NOTE: when backligth dimming is enabled, the implementation of this API
* function is provided in platform/drivers/backlight/backlight_MDx.c to avoid