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