diff --git a/bootloader/import.mk b/bootloader/import.mk index 3577504fab..cede4b9a1c 100644 --- a/bootloader/import.mk +++ b/bootloader/import.mk @@ -1,5 +1,5 @@ BOOTLOADER_MODULE_PATH ?= $(PROJECT_ROOT)/bootloader -BOOTLOADER_VERSION ?= 8 +BOOTLOADER_VERSION ?= 9 BOOTLOADER_BUILD_PATH_EXT = $(BUILD_TARGET_PLATFORM) # bring in the include folders from inc and src/ is includes diff --git a/bootloader/src/core/button.c b/bootloader/src/core/button.c new file mode 100644 index 0000000000..b7906ed95d --- /dev/null +++ b/bootloader/src/core/button.c @@ -0,0 +1,16 @@ +#include "button.h" + +extern __IO uint16_t BUTTON_DEBOUNCED_TIME[]; + +void BUTTON_Init_Ext() { + if (BUTTON_Is_Pressed(BUTTON1)) + TIM_ITConfig(TIM1, TIM_IT_CC4, ENABLE); +} + +uint8_t BUTTON_Is_Pressed(Button_TypeDef button) { + return BUTTON_GetState(BUTTON1) == BUTTON1_PRESSED; +} + +uint16_t BUTTON_Pressed_Time(Button_TypeDef button) { + return BUTTON_DEBOUNCED_TIME[BUTTON1]; +} diff --git a/bootloader/src/core/button.h b/bootloader/src/core/button.h new file mode 100644 index 0000000000..790c8f7186 --- /dev/null +++ b/bootloader/src/core/button.h @@ -0,0 +1,18 @@ +#ifndef __BUTTON_H +#define __BUTTON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hw_config.h" + +void BUTTON_Init_Ext(); +uint8_t BUTTON_Is_Pressed(Button_TypeDef button); +uint16_t BUTTON_Pressed_Time(Button_TypeDef button); + +#ifdef __cplusplus +} +#endif + +#endif /* __BUTTON_H */ diff --git a/bootloader/src/main.c b/bootloader/src/main.c index 7812036dfa..a81c15fee9 100644 --- a/bootloader/src/main.c +++ b/bootloader/src/main.c @@ -29,6 +29,7 @@ #include "dfu_hal.h" #include "hw_config.h" #include "rgbled.h" +#include "button.h" void platform_startup(); @@ -110,6 +111,7 @@ int main(void) // Configure the MODE button //-------------------------------------------------------------------------- Set_System(); + BUTTON_Init_Ext(); //-------------------------------------------------------------------------- @@ -261,7 +263,7 @@ int main(void) //-------------------------------------------------------------------------- // Check if BUTTON1 is pressed and determine the status //-------------------------------------------------------------------------- - if (BUTTON_GetState(BUTTON1) == BUTTON1_PRESSED && (features & BL_BUTTON_FEATURES)) + if (BUTTON_Is_Pressed(BUTTON1) && (features & BL_BUTTON_FEATURES)) { #define TIMING_SAFE_MODE 1000 #define TIMING_DFU_MODE 3000 @@ -273,23 +275,23 @@ int main(void) TimingBUTTON = TIMING_ALL; uint8_t factory_reset = 0; - while (BUTTON_GetState(BUTTON1) == BUTTON1_PRESSED && TimingBUTTON) + while (BUTTON_Is_Pressed(BUTTON1) && TimingBUTTON) { - if(TimingBUTTON < (TIMING_ALL-TIMING_RESET_MODE)) + if(BUTTON_Pressed_Time(BUTTON1) > TIMING_RESET_MODE) { // if pressed for 10 sec, enter Factory Reset Mode // This tells the WLAN setup to clear the WiFi user profiles on bootup LED_SetRGBColor(RGB_COLOR_WHITE); SYSTEM_FLAG(NVMEM_SPARK_Reset_SysFlag) = 0x0001; } - else if(!factory_reset && TimingBUTTON <= (TIMING_ALL-TIMING_RESTORE_MODE)) + else if(!factory_reset && BUTTON_Pressed_Time(BUTTON1) > TIMING_RESTORE_MODE) { // if pressed for > 6.5 sec, enter firmware reset LED_SetRGBColor(RGB_COLOR_GREEN); SYSTEM_FLAG(NVMEM_SPARK_Reset_SysFlag) = 0x0000; factory_reset = 1; } - else if(!USB_DFU_MODE && TimingBUTTON <= (TIMING_ALL-TIMING_DFU_MODE)) + else if(!USB_DFU_MODE && BUTTON_Pressed_Time(BUTTON1) >= TIMING_DFU_MODE) { // if pressed for > 3 sec, enter USB DFU Mode if (features&BL_FEATURE_DFU_MODE) { @@ -299,7 +301,7 @@ int main(void) if (!factory_reset_available) break; } - else if(!SAFE_MODE && TimingBUTTON <= TIMING_ALL-TIMING_SAFE_MODE) + else if(!SAFE_MODE && BUTTON_Pressed_Time(BUTTON1) >= TIMING_SAFE_MODE) { OTA_FLASH_AVAILABLE = 0; REFLASH_FROM_BACKUP = 0; diff --git a/bootloader/src/stm32f2xx/button.c b/bootloader/src/stm32f2xx/button.c new file mode 100644 index 0000000000..9c9c409565 --- /dev/null +++ b/bootloader/src/stm32f2xx/button.c @@ -0,0 +1,102 @@ +#include "button.h" +#include "dct.h" +#include "hal_irq_flag.h" +#include + +/** + * @brief This function handles BUTTON EXTI Handler. + * @param None + * @retval None + */ +void BUTTON_Irq_Handler(uint16_t exti) +{ + if (EXTI_GetITStatus(exti) != RESET) + { + /* Clear the EXTI line pending bit */ + EXTI_ClearITPendingBit(exti); + + BUTTON_Check_Irq(BUTTON1, exti); + BUTTON_Check_Irq(BUTTON1_MIRROR, exti); + } +} + +void BUTTON_Check_Irq(uint16_t button, uint16_t exti) { + if (HAL_Buttons[button].exti_line == exti) + { + HAL_Buttons[button].debounce_time = 0x00; + HAL_Buttons[button].active = 1; + + /* Disable button Interrupt */ + BUTTON_EXTI_Config(button, DISABLE); + + /* Enable TIM2 CC1 Interrupt */ + TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE); + } +} + +void BUTTON_Check_State(uint16_t button, uint8_t pressed) { + if (HAL_Buttons[button].exti_line && BUTTON_GetState(button) == pressed) + { + if (!HAL_Buttons[button].active) + HAL_Buttons[button].active = 1; + HAL_Buttons[button].debounce_time += BUTTON_DEBOUNCE_INTERVAL; + } + else if (HAL_Buttons[button].active) + { + HAL_Buttons[button].active = 0; + /* Enable button Interrupt */ + BUTTON_EXTI_Config(button, ENABLE); + } +} + +int BUTTON_Debounce() { + BUTTON_Check_State(BUTTON1, BUTTON1_PRESSED); + BUTTON_Check_State(BUTTON1_MIRROR, HAL_Buttons[BUTTON1_MIRROR].exti_trigger == EXTI_Trigger_Rising ? 1 : 0); + + int pressed = HAL_Buttons[BUTTON1].active + HAL_Buttons[BUTTON1_MIRROR].active; + if (pressed == 0) { + /* Disable TIM2 CC1 Interrupt */ + TIM_ITConfig(TIM2, TIM_IT_CC1, DISABLE); + } + + return pressed; +} + +void BUTTON_Init_Ext() { + const button_config_t* conf = (const button_config_t*)dct_read_app_data(DCT_MODE_BUTTON_MIRROR_OFFSET); + + if (conf->active == 0xAA && conf->debounce_time == 0xBBCC) { + int32_t state = HAL_disable_irq(); + memcpy((void*)&HAL_Buttons[BUTTON1_MIRROR], (void*)conf, sizeof(button_config_t)); + HAL_Buttons[BUTTON1_MIRROR].active = 0; + HAL_Buttons[BUTTON1_MIRROR].debounce_time = 0; + BUTTON_Init(BUTTON1_MIRROR, BUTTON_MODE_EXTI); + HAL_enable_irq(state); + } + + if (BUTTON_Debounce()) + TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE); +} + +uint8_t BUTTON_Is_Pressed(Button_TypeDef button) { + uint8_t pressed = 0; + pressed = HAL_Buttons[button].active; + + if (button == BUTTON1 && HAL_Buttons[BUTTON1_MIRROR].exti_line) { + pressed |= BUTTON_Is_Pressed(BUTTON1_MIRROR); + } + + return pressed; +} + +uint16_t BUTTON_Pressed_Time(Button_TypeDef button) { + uint16_t pressed = 0; + + pressed = HAL_Buttons[button].debounce_time; + if (button == BUTTON1 && HAL_Buttons[BUTTON1_MIRROR].exti_line) { + if (BUTTON_Pressed_Time(BUTTON1_MIRROR) > pressed) + pressed = BUTTON_Pressed_Time(BUTTON1_MIRROR); + } + + return pressed; +} diff --git a/bootloader/src/stm32f2xx/button.h b/bootloader/src/stm32f2xx/button.h new file mode 100644 index 0000000000..76dedc14ea --- /dev/null +++ b/bootloader/src/stm32f2xx/button.h @@ -0,0 +1,24 @@ +#ifndef __BUTTON_H +#define __BUTTON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hw_config.h" + +void BUTTON_Init_Ext(); +uint8_t BUTTON_Is_Pressed(Button_TypeDef button); +uint16_t BUTTON_Pressed_Time(Button_TypeDef button); + + +void BUTTON_Irq_Handler(uint16_t exti); +void BUTTON_Check_Irq(uint16_t button, uint16_t exti); +void BUTTON_Check_State(uint16_t button, uint8_t pressed); +int BUTTON_Debounce(); + +#ifdef __cplusplus +} +#endif + +#endif /* __BUTTON_H */ diff --git a/bootloader/src/stm32f2xx/hal_irq_flag.c b/bootloader/src/stm32f2xx/hal_irq_flag.c new file mode 100644 index 0000000000..3204720c6e --- /dev/null +++ b/bootloader/src/stm32f2xx/hal_irq_flag.c @@ -0,0 +1 @@ +#include "../src/stm32f2xx/hal_irq_flag.c" diff --git a/bootloader/src/stm32f2xx/stm32_it.c b/bootloader/src/stm32f2xx/stm32_it.c index 0e1cbc00e1..5382ed546e 100644 --- a/bootloader/src/stm32f2xx/stm32_it.c +++ b/bootloader/src/stm32f2xx/stm32_it.c @@ -33,6 +33,7 @@ #include "usb_conf.h" #include "usbd_dfu_core.h" #include "hw_config.h" +#include "button.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ @@ -41,7 +42,6 @@ /* Private function prototypes -----------------------------------------------*/ /* Extern variables and function prototypes ----------------------------------*/ -extern __IO uint16_t BUTTON_DEBOUNCED_TIME[]; extern void Timing_Decrement(void); extern USB_OTG_CORE_HANDLE USB_OTG_dev; @@ -152,28 +152,6 @@ void SysTick_Handler(void) Timing_Decrement(); } -/** - * @brief This function handles BUTTON EXTI Handler. - * @param None - * @retval None - */ -void BUTTON1_EXTI_IRQ_HANDLER(void) -{ - if (EXTI_GetITStatus(BUTTON1_EXTI_LINE) != RESET) - { - /* Clear the EXTI line pending bit */ - EXTI_ClearITPendingBit(BUTTON1_EXTI_LINE); - - BUTTON_DEBOUNCED_TIME[BUTTON1] = 0x00; - - /* Disable BUTTON1 Interrupt */ - BUTTON_EXTI_Config(BUTTON1, DISABLE); - - /* Enable TIM2 CC1 Interrupt */ - TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE); - } -} - /** * @brief This function handles TIM2 Handler. * @param None @@ -185,18 +163,7 @@ void TIM2_IRQHandler(void) { TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); - if (BUTTON_GetState(BUTTON1) == BUTTON1_PRESSED) - { - BUTTON_DEBOUNCED_TIME[BUTTON1] += BUTTON_DEBOUNCE_INTERVAL; - } - else - { - /* Disable TIM2 CC1 Interrupt */ - TIM_ITConfig(TIM2, TIM_IT_CC1, DISABLE); - - /* Enable BUTTON1 Interrupt */ - BUTTON_EXTI_Config(BUTTON1, ENABLE); - } + BUTTON_Debounce(); } } @@ -271,3 +238,96 @@ void OTG_HS_IRQHandler(void) /*void PPP_IRQHandler(void) { }*/ + +/******************************************************************************* + * Function Name : EXTI0_IRQHandler + * Description : This function handles EXTI0 interrupt request. + * Input : None + * Output : None + * Return : None + *******************************************************************************/ +void EXTI0_IRQHandler(void) +{ + BUTTON_Irq_Handler(EXTI_Line0); +} + +/******************************************************************************* + * Function Name : EXTI1_IRQHandler + * Description : This function handles EXTI1 interrupt request. + * Input : None + * Output : None + * Return : None + *******************************************************************************/ +void EXTI1_IRQHandler(void) +{ + BUTTON_Irq_Handler(EXTI_Line1); +} + +/******************************************************************************* + * Function Name : EXTI2_IRQHandler + * Description : This function handles EXTI2 interrupt request. + * Input : None + * Output : None + * Return : None + *******************************************************************************/ +void EXTI2_IRQHandler(void) +{ + BUTTON_Irq_Handler(EXTI_Line2); +} + +/******************************************************************************* + * Function Name : EXTI3_IRQHandler + * Description : This function handles EXTI3 interrupt request. + * Input : None + * Output : None + * Return : None + *******************************************************************************/ +void EXTI3_IRQHandler(void) +{ + BUTTON_Irq_Handler(EXTI_Line3); +} + +/******************************************************************************* + * Function Name : EXTI4_IRQHandler + * Description : This function handles EXTI4 interrupt request. + * Input : None + * Output : None + * Return : None + *******************************************************************************/ +void EXTI4_IRQHandler(void) +{ + BUTTON_Irq_Handler(EXTI_Line4); +} + +/******************************************************************************* + * Function Name : EXTI9_5_IRQHandler + * Description : This function handles EXTI9_5 interrupt request. + * Input : None + * Output : None + * Return : None + *******************************************************************************/ +void EXTI9_5_IRQHandler(void) +{ + BUTTON_Irq_Handler(EXTI_Line5); + BUTTON_Irq_Handler(EXTI_Line6); + BUTTON_Irq_Handler(EXTI_Line7); + BUTTON_Irq_Handler(EXTI_Line8); + BUTTON_Irq_Handler(EXTI_Line9); +} + +/******************************************************************************* + * Function Name : EXTI15_10_IRQHandler + * Description : This function handles EXTI15_10 interrupt request. + * Input : None + * Output : None + * Return : None + *******************************************************************************/ +void EXTI15_10_IRQHandler(void) +{ + BUTTON_Irq_Handler(EXTI_Line10); + BUTTON_Irq_Handler(EXTI_Line11); + BUTTON_Irq_Handler(EXTI_Line12); + BUTTON_Irq_Handler(EXTI_Line13); + BUTTON_Irq_Handler(EXTI_Line14); + BUTTON_Irq_Handler(EXTI_Line15); +} diff --git a/docs/reference/firmware.md b/docs/reference/firmware.md index ca8a52258b..7c64af0c27 100644 --- a/docs/reference/firmware.md +++ b/docs/reference/firmware.md @@ -8058,6 +8058,56 @@ Disables the system flag. Returns `true` if the system flag is enabled. +{{#unless core}} +### buttonMirror() + +*Since 0.7.0* + +Allows a pin to mirror the functionality of the SETUP/MODE button. + +```C++ +// SYNTAX +System.buttonMirror(D1, RISING); +System.buttonMirror(D1, FALLING, true); +``` +Parameters: + + * `pin`: the pin number + * `mode`: defines the condition that signifies a button press: + - RISING to trigger when the pin goes from low to high, + - FALLING for when the pin goes from high to low. + * `bootloader`: (optional) if `true`, the mirror pin configuration is saved in DCT and pin mirrors the SETUP/MODE button functionality while in bootloader as well. If `false`, any previously stored configuration is removed from the DCT and pin only mirrors the SETUP/MODE button while running the firmware (default). + +See also [`System.disableButtonMirror()`](#disablebuttonmirror-). + +```cpp +// EXAMPLE +// Mirror SETUP/MODE button on D1 pin. Button pressed state - LOW +STARTUP(System.buttonMirror(D1, FALLING)); + +// EXAMPLE +// Mirror SETUP/MODE button on D1 pin. Button pressed state - HIGH +// Works in both firmware and bootloader +STARTUP(System.buttonMirror(D1, RISING, true)); +``` + +***NOTE:*** Pins `D0` and `A5` will disable normal SETUP button operation. Pins `D0` and `A5` also can not be used in bootloader, the configuration will not be saved in DCT. + +### disableButtonMirror() + +*Since 0.7.0* + +Disables SETUP button mirroring on a pin. + +```C++ +// SYNTAX +System.disableButtonMirror(); +System.disableButtonMirror(false); +``` +Parameters: + * `bootloader`: (optional) if `true`, the mirror pin configuration is cleared from the DCT, disabling the feature in bootloader (default). + +{{/unless}} ## OTA Updates diff --git a/hal/inc/core_hal.h b/hal/inc/core_hal.h index 06ffdad464..c96a8ec13f 100644 --- a/hal/inc/core_hal.h +++ b/hal/inc/core_hal.h @@ -111,6 +111,7 @@ typedef enum System_Reset_Reason /* Exported functions --------------------------------------------------------*/ #include "watchdog_hal.h" #include "core_subsys_hal.h" +#include "interrupts_hal.h" #ifdef __cplusplus extern "C" { @@ -120,7 +121,7 @@ void HAL_Core_Init(void); void HAL_Core_Config(void); bool HAL_Core_Validate_User_Module(void); bool HAL_Core_Mode_Button_Pressed(uint16_t pressedMillisDuration); -void HAL_Core_Mode_Button_Reset(void); +void HAL_Core_Mode_Button_Reset(uint16_t button); void HAL_Core_System_Reset(void); void HAL_Core_Factory_Reset(void); @@ -238,6 +239,9 @@ extern void module_user_init_hook(void); int HAL_System_Backup_Save(size_t offset, const void* buffer, size_t length, void* reserved); int HAL_System_Backup_Restore(size_t offset, void* buffer, size_t max_length, size_t* length, void* reserved); +void HAL_Core_Button_Mirror_Pin(uint16_t pin, InterruptMode mode, uint8_t bootloader, uint8_t button, void* reserved); +void HAL_Core_Button_Mirror_Pin_Disable(uint8_t bootloader, uint8_t button, void* reserved); + #ifdef __cplusplus } #endif diff --git a/hal/inc/hal_dynalib_core.h b/hal/inc/hal_dynalib_core.h index 6f205b1658..3fd267161a 100644 --- a/hal/inc/hal_dynalib_core.h +++ b/hal/inc/hal_dynalib_core.h @@ -45,7 +45,7 @@ DYNALIB_FN(0, hal_core, HAL_core_subsystem_version, int(char*, int)) DYNALIB_FN(1, hal_core, HAL_Core_Init, void(void)) DYNALIB_FN(2, hal_core, HAL_Core_Config, void(void)) DYNALIB_FN(3, hal_core, HAL_Core_Mode_Button_Pressed, bool(uint16_t)) -DYNALIB_FN(4, hal_core, HAL_Core_Mode_Button_Reset, void(void)) +DYNALIB_FN(4, hal_core, HAL_Core_Mode_Button_Reset, void(uint16_t)) DYNALIB_FN(5, hal_core, HAL_Core_System_Reset, void(void)) DYNALIB_FN(6, hal_core, HAL_Core_Factory_Reset, void(void)) DYNALIB_FN(7, hal_core, HAL_Core_Enter_Bootloader, void(bool)) @@ -70,6 +70,8 @@ DYNALIB_FN(24, hal_core, HAL_Feature_Get, bool(HAL_Feature)) DYNALIB_FN(25, hal_core, HAL_Feature_Set, int(HAL_Feature, bool)) DYNALIB_FN(26, hal_core, HAL_Core_System_Reset_Ex, void(int, uint32_t, void*)) DYNALIB_FN(27, hal_core, HAL_Core_Get_Last_Reset_Info, int(int*, uint32_t*, void*)) +DYNALIB_FN(28, hal_core, HAL_Core_Button_Mirror_Pin, void(uint16_t, InterruptMode, uint8_t, uint8_t, void*)) +DYNALIB_FN(29, hal_core, HAL_Core_Button_Mirror_Pin_Disable, void(uint8_t, uint8_t, void*)) DYNALIB_END(hal_core) diff --git a/hal/inc/hal_irq_flag.h b/hal/inc/hal_irq_flag.h new file mode 100644 index 0000000000..cd43c15491 --- /dev/null +++ b/hal/inc/hal_irq_flag.h @@ -0,0 +1,13 @@ +#ifndef __HAL_IRQ_FLAG_H +#define __HAL_IRQ_FLAG_H + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +int HAL_disable_irq(); +void HAL_enable_irq(int mask); +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __HAL_IRQ_FLAG_H diff --git a/hal/inc/interrupts_hal.h b/hal/inc/interrupts_hal.h index 9552b1bd8c..028bcc80d8 100644 --- a/hal/inc/interrupts_hal.h +++ b/hal/inc/interrupts_hal.h @@ -30,6 +30,7 @@ /* Includes ------------------------------------------------------------------*/ #include "pinmap_hal.h" #include "interrupts_irq.h" +#include "hal_irq_flag.h" /* Exported types ------------------------------------------------------------*/ typedef enum InterruptMode { @@ -88,9 +89,6 @@ uint8_t HAL_Set_System_Interrupt_Handler(hal_irq_t irq, const HAL_InterruptCallb uint8_t HAL_Get_System_Interrupt_Handler(hal_irq_t irq, HAL_InterruptCallback* callback, void* reserved); void HAL_System_Interrupt_Trigger(hal_irq_t irq, void* reserved); -int HAL_disable_irq(); -void HAL_enable_irq(int mask); - #ifdef USE_STDPERIPH_DRIVER #if defined(STM32F10X_MD) || defined(STM32F10X_HD) #include "stm32f10x.h" diff --git a/hal/src/core/core_hal.c b/hal/src/core/core_hal.c index 38d5f9437e..56926b5766 100644 --- a/hal/src/core/core_hal.c +++ b/hal/src/core/core_hal.c @@ -200,7 +200,7 @@ bool HAL_Core_Mode_Button_Pressed(uint16_t pressedMillisDuration) return pressedState; } -void HAL_Core_Mode_Button_Reset(void) +void HAL_Core_Mode_Button_Reset(uint16_t button) { /* Disable TIM1 CC4 Interrupt */ @@ -619,4 +619,10 @@ int HAL_Ssystem_Backup_Restore(size_t offset, void* buffer, size_t max_length, s return -1; } +void HAL_Core_Button_Mirror_Pin_Disable(uint8_t bootloader, uint8_t button, void* reserved) +{ +} +void HAL_Core_Button_Mirror_Pin(uint16_t pin, InterruptMode mode, uint8_t bootloader, uint8_t button, void *reserved) +{ +} diff --git a/hal/src/core/stm32_it.c b/hal/src/core/stm32_it.c index 09e4b921dc..f8c112659c 100644 --- a/hal/src/core/stm32_it.c +++ b/hal/src/core/stm32_it.c @@ -533,7 +533,7 @@ void TIM1_CC_IRQHandler(void) } else { - HAL_Core_Mode_Button_Reset(); + HAL_Core_Mode_Button_Reset(BUTTON1); } } diff --git a/hal/src/electron/core_hal.c b/hal/src/electron/core_hal.c index bfb9c4656f..461de93765 100644 --- a/hal/src/electron/core_hal.c +++ b/hal/src/electron/core_hal.c @@ -510,7 +510,7 @@ void EXTI9_5_IRQHandler(void) if (EXTI_GetITStatus(EXTI_Line7) != RESET) { - Handle_Mode_Button_EXTI_irq(); + Handle_Mode_Button_EXTI_irq(BUTTON1); } if (EXTI_GetITStatus(EXTI_Line8) != RESET) diff --git a/hal/src/gcc/core_hal.cpp b/hal/src/gcc/core_hal.cpp index 48f8c12b6f..4aecd7670e 100644 --- a/hal/src/gcc/core_hal.cpp +++ b/hal/src/gcc/core_hal.cpp @@ -437,3 +437,11 @@ uint32_t HAL_Core_Read_Backup_Register(uint32_t BKP_DR) { return 0xFFFFFFFF; } + +void HAL_Core_Button_Mirror_Pin_Disable(uint8_t bootloader, uint8_t button, void* reserved) +{ +} + +void HAL_Core_Button_Mirror_Pin(uint16_t pin, InterruptMode mode, uint8_t bootloader, uint8_t button, void *reserved) +{ +} diff --git a/hal/src/photon/core_hal.c b/hal/src/photon/core_hal.c index c137330922..39c309c1a9 100644 --- a/hal/src/photon/core_hal.c +++ b/hal/src/photon/core_hal.c @@ -142,7 +142,7 @@ void Mode_Button_EXTI_irq(void) { void (*chain)(void) = (void (*)(void))((uint32_t*)&link_interrupt_vectors_location)[ButtonExtiIndex]; - Handle_Mode_Button_EXTI_irq(); + Handle_Mode_Button_EXTI_irq(BUTTON1); chain(); } diff --git a/hal/src/stm32f2xx/core_hal_stm32f2xx.c b/hal/src/stm32f2xx/core_hal_stm32f2xx.c index 21735dbf9e..b6d3d1a320 100644 --- a/hal/src/stm32f2xx/core_hal_stm32f2xx.c +++ b/hal/src/stm32f2xx/core_hal_stm32f2xx.c @@ -51,6 +51,7 @@ #include "usb_hal.h" #include "usart_hal.h" #include "deviceid_hal.h" +#include "pinmap_impl.h" #if PLATFORM_ID==PLATFORM_P1 #include "wwd_management.h" @@ -193,6 +194,8 @@ typedef enum Feature_Flag { static Last_Reset_Info last_reset_info = { RESET_REASON_NONE, 0 }; /* Private function prototypes -----------------------------------------------*/ +extern uint32_t HAL_Interrupts_Pin_IRQn(pin_t pin); + void (*HAL_TIM1_Handler)(void); void (*HAL_TIM3_Handler)(void); void (*HAL_TIM4_Handler)(void); @@ -287,7 +290,6 @@ static bool Read_Feature_Flag(uint32_t flag) } /* Extern variables ----------------------------------------------------------*/ -extern __IO uint16_t BUTTON_DEBOUNCED_TIME[]; /******************************************************************************* @@ -433,6 +435,10 @@ bool HAL_Core_Mode_Button_Pressed(uint16_t pressedMillisDuration) { pressedState = true; } + if(BUTTON_GetDebouncedTime(BUTTON1_MIRROR) >= pressedMillisDuration) + { + pressedState = true; + } return pressedState; } @@ -440,17 +446,29 @@ bool HAL_Core_Mode_Button_Pressed(uint16_t pressedMillisDuration) /** * Force the button in the unpressed state. */ -void HAL_Core_Mode_Button_Reset(void) +void HAL_Core_Mode_Button_Reset(uint16_t button) { - /* Disable TIM2 CC1 Interrupt */ - TIM_ITConfig(TIM2, TIM_IT_CC1, DISABLE); + HAL_Buttons[button].debounce_time = 0x00; - BUTTON_DEBOUNCED_TIME[BUTTON1] = 0x00; + if (HAL_Buttons[BUTTON1].active + HAL_Buttons[BUTTON1_MIRROR].active == 0) { + /* Disable TIM2 CC1 Interrupt */ + TIM_ITConfig(TIM2, TIM_IT_CC1, DISABLE); + } - HAL_Notify_Button_State(BUTTON1, false); + HAL_Notify_Button_State((Button_TypeDef)button, false); - /* Enable BUTTON1 Interrupt */ - BUTTON_EXTI_Config(BUTTON1, ENABLE); + /* Enable Button Interrupt */ + if (button != BUTTON1_MIRROR) { + BUTTON_EXTI_Config((Button_TypeDef)button, ENABLE); + } else { + HAL_InterruptExtraConfiguration irqConf = {0}; + irqConf.version = HAL_INTERRUPT_EXTRA_CONFIGURATION_VERSION_2; + irqConf.IRQChannelPreemptionPriority = 0; + irqConf.IRQChannelSubPriority = 0; + irqConf.keepHandler = 1; + irqConf.keepPriority = 1; + HAL_Interrupts_Attach(HAL_Buttons[button].hal_pin, NULL, NULL, HAL_Buttons[button].interrupt_mode, &irqConf); + } } @@ -774,17 +792,21 @@ void SysTickOverride(void) * @param None * @retval None */ -void Handle_Mode_Button_EXTI_irq(void) +void Handle_Mode_Button_EXTI_irq(Button_TypeDef button) { - if (EXTI_GetITStatus(BUTTON1_EXTI_LINE) != RESET) + if (button == BUTTON1_MIRROR || EXTI_GetITStatus(HAL_Buttons[button].exti_line) != RESET) { /* Clear the EXTI line pending bit (cleared in WICED GPIO IRQ handler) */ - EXTI_ClearITPendingBit(BUTTON1_EXTI_LINE); + EXTI_ClearITPendingBit(HAL_Buttons[button].exti_line); - BUTTON_DEBOUNCED_TIME[BUTTON1] = 0x00; + HAL_Buttons[button].debounce_time = 0x00; + HAL_Buttons[button].active = 1; /* Disable BUTTON1 Interrupt */ - BUTTON_EXTI_Config(BUTTON1, DISABLE); + if (button != BUTTON1_MIRROR) + BUTTON_EXTI_Config(button, DISABLE); + else + HAL_Interrupts_Detach_Ext(HAL_Buttons[button].hal_pin, 1, NULL); /* Enable TIM2 CC1 Interrupt */ TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE); @@ -828,18 +850,34 @@ void TIM2_irq(void) { if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) { - if (BUTTON_GetState(BUTTON1) == BUTTON1_PRESSED) + if (HAL_Buttons[BUTTON1].active && BUTTON_GetState(BUTTON1) == BUTTON1_PRESSED) { - if (!BUTTON_DEBOUNCED_TIME[BUTTON1]) + if (!HAL_Buttons[BUTTON1].debounce_time) { - BUTTON_DEBOUNCED_TIME[BUTTON1] += BUTTON_DEBOUNCE_INTERVAL; + HAL_Buttons[BUTTON1].debounce_time += BUTTON_DEBOUNCE_INTERVAL; HAL_Notify_Button_State(BUTTON1, true); + } + HAL_Buttons[BUTTON1].debounce_time += BUTTON_DEBOUNCE_INTERVAL; } - BUTTON_DEBOUNCED_TIME[BUTTON1] += BUTTON_DEBOUNCE_INTERVAL; + else if (HAL_Buttons[BUTTON1].active) + { + HAL_Buttons[BUTTON1].active = 0; + HAL_Core_Mode_Button_Reset(BUTTON1); } - else + + if (HAL_Buttons[BUTTON1_MIRROR].port && HAL_Buttons[BUTTON1_MIRROR].active && + BUTTON_GetState(BUTTON1_MIRROR) == (HAL_Buttons[BUTTON1_MIRROR].interrupt_mode == RISING ? 1 : 0)) { + if (!HAL_Buttons[BUTTON1_MIRROR].debounce_time) + { + HAL_Buttons[BUTTON1_MIRROR].debounce_time += BUTTON_DEBOUNCE_INTERVAL; + HAL_Notify_Button_State(BUTTON1_MIRROR, true); + } + HAL_Buttons[BUTTON1_MIRROR].debounce_time += BUTTON_DEBOUNCE_INTERVAL; + } + else if (HAL_Buttons[BUTTON1_MIRROR].port && HAL_Buttons[BUTTON1_MIRROR].active) { - HAL_Core_Mode_Button_Reset(); + HAL_Buttons[BUTTON1_MIRROR].active = 0; + HAL_Core_Mode_Button_Reset(BUTTON1_MIRROR); } } @@ -1229,6 +1267,146 @@ bool HAL_Feature_Get(HAL_Feature feature) return false; } +void HAL_Core_Mode_Button_Mirror_Pressed(void* param) { + Handle_Mode_Button_EXTI_irq(BUTTON1_MIRROR); +} + +static void BUTTON_Mirror_Init() { + if (HAL_Buttons[BUTTON1_MIRROR].port) { + PinMode pinMode = INPUT_PULLUP; + switch(HAL_Buttons[BUTTON1_MIRROR].interrupt_mode) + { + case RISING: + pinMode = INPUT_PULLDOWN; + break; + case FALLING: + pinMode = INPUT_PULLUP; + break; + } + + int32_t state = HAL_disable_irq(); + HAL_Pin_Mode(HAL_Buttons[BUTTON1_MIRROR].hal_pin, pinMode); + HAL_Interrupts_Attach(HAL_Buttons[BUTTON1_MIRROR].hal_pin, HAL_Core_Mode_Button_Mirror_Pressed, NULL, HAL_Buttons[BUTTON1_MIRROR].interrupt_mode, NULL); + if (HAL_Buttons[BUTTON1_MIRROR].exti_line == HAL_Buttons[BUTTON1].exti_line) { + HAL_Buttons[BUTTON1].exti_port_source = HAL_Buttons[BUTTON1_MIRROR].exti_port_source; + HAL_Buttons[BUTTON1].exti_pin_source = HAL_Buttons[BUTTON1_MIRROR].exti_pin_source; + HAL_Buttons[BUTTON1].port = HAL_Buttons[BUTTON1_MIRROR].port; + } + HAL_enable_irq(state); + } +} + +static void BUTTON_Mirror_Persist(button_config_t* conf) { + const button_config_t* saved_config = (const button_config_t*)dct_read_app_data(DCT_MODE_BUTTON_MIRROR_OFFSET); + + if (conf) { + if (saved_config->active == 0xFF || memcmp((void*)conf, (void*)saved_config, sizeof(button_config_t))) + { + dct_write_app_data((void*)conf, DCT_MODE_BUTTON_MIRROR_OFFSET, sizeof(button_config_t)); + } + } else { + if (saved_config->active != 0xFF) { + button_config_t tmp; + memset((void*)&tmp, 0xff, sizeof(button_config_t)); + dct_write_app_data((void*)&tmp, DCT_MODE_BUTTON_MIRROR_OFFSET, sizeof(button_config_t)); + } + } +} + +void HAL_Core_Button_Mirror_Pin_Disable(uint8_t bootloader, uint8_t button, void* reserved) { + (void)button; // unused + int32_t state = HAL_disable_irq(); + if (HAL_Buttons[BUTTON1_MIRROR].port) { + HAL_Interrupts_Detach_Ext(HAL_Buttons[BUTTON1_MIRROR].hal_pin, 1, NULL); + HAL_Buttons[BUTTON1_MIRROR].active = 0; + HAL_Buttons[BUTTON1_MIRROR].port = 0; + } + HAL_enable_irq(state); + + if (bootloader) { + BUTTON_Mirror_Persist(NULL); + } +} + +void HAL_Core_Button_Mirror_Pin(uint16_t pin, InterruptMode mode, uint8_t bootloader, uint8_t button, void *reserved) { + (void)button; // unused + STM32_Pin_Info* pinmap = HAL_Pin_Map(); + if (pin > TOTAL_PINS) + return; + + if (mode != RISING && mode != FALLING) + return; + + uint8_t gpio_port_source = 0; + uint32_t gpio_clk = 0x00; + switch((uint32_t)pinmap[pin].gpio_peripheral) { + case (uint32_t)GPIOA: + gpio_port_source = 0; + gpio_clk = RCC_AHB1Periph_GPIOA; + break; + case (uint32_t)GPIOB: + gpio_port_source = 1; + gpio_clk = RCC_AHB1Periph_GPIOB; + break; + case (uint32_t)GPIOC: + gpio_port_source = 2; + gpio_clk = RCC_AHB1Periph_GPIOC; + break; + case (uint32_t)GPIOD: + gpio_port_source = 3; + gpio_clk = RCC_AHB1Periph_GPIOD; + break; + } + + button_config_t conf = { + .port = pinmap[pin].gpio_peripheral, + .pin = pinmap[pin].gpio_pin, + .hal_pin = pin, + .debounce_time = 0, + .interrupt_mode = mode, + + .exti_line = pinmap[pin].gpio_pin, + .exti_pin_source = pinmap[pin].gpio_pin_source, + .exti_port_source = gpio_port_source, + .exti_trigger = mode == RISING ? EXTI_Trigger_Rising : EXTI_Trigger_Falling + }; + + HAL_Buttons[BUTTON1_MIRROR] = conf; + + BUTTON_Mirror_Init(); + + if (pinmap[pin].gpio_pin == HAL_Buttons[BUTTON1].pin) { + LOG(WARN, "Pin %d shares the same EXTI as SETUP/MODE button", pin); + BUTTON_Mirror_Persist(NULL); + return; + } + + if (!bootloader) { + BUTTON_Mirror_Persist(NULL); + return; + } + + // Construct button_config_t for bootloader + button_config_t bootloader_conf = { + .active = 0xAA, + .port = pinmap[pin].gpio_peripheral, + .pin = pinmap[pin].gpio_pin, + .clk = gpio_clk, + .mode = GPIO_Mode_IN, + .pupd = mode == RISING ? GPIO_PuPd_DOWN : GPIO_PuPd_UP, + .debounce_time = 0xBBCC, + + .exti_line = pinmap[pin].gpio_pin, + .exti_port_source = gpio_port_source, + .exti_pin_source = pinmap[pin].gpio_pin_source, + .exti_irqn = HAL_Interrupts_Pin_IRQn(pin), + .exti_irq_prio = HAL_Buttons[BUTTON1].exti_irq_prio, + .exti_trigger = mode == RISING ? EXTI_Trigger_Rising : EXTI_Trigger_Falling + }; + + BUTTON_Mirror_Persist(&bootloader_conf); +} + #if HAL_PLATFORM_CLOUD_UDP #include "dtls_session_persist.h" diff --git a/hal/src/stm32f2xx/core_hal_stm32f2xx.h b/hal/src/stm32f2xx/core_hal_stm32f2xx.h index e779a88bb0..b20311c64e 100644 --- a/hal/src/stm32f2xx/core_hal_stm32f2xx.h +++ b/hal/src/stm32f2xx/core_hal_stm32f2xx.h @@ -1,5 +1,7 @@ #pragma once +#include "hw_config.h" + /** * Called by HAL_Core_Config() to setup SysTick_Configuration() if necessary. */ @@ -103,7 +105,7 @@ void RTC_Alarm_irq(void); /** * A shared handler for the EXTI interrupt to process presses of the mode button. */ -void Handle_Mode_Button_EXTI_irq(void); +void Handle_Mode_Button_EXTI_irq(Button_TypeDef button); /** * Handle short and generic tasks for the device HAL on 1ms ticks diff --git a/hal/src/stm32f2xx/hal_irq_flag.c b/hal/src/stm32f2xx/hal_irq_flag.c index 22fbd33727..5dbbdd9e85 100644 --- a/hal/src/stm32f2xx/hal_irq_flag.c +++ b/hal/src/stm32f2xx/hal_irq_flag.c @@ -1,5 +1,4 @@ - -#include "interrupts_hal.h" +#include "stm32f2xx.h" int HAL_disable_irq() { diff --git a/hal/src/stm32f2xx/interrupts_hal.c b/hal/src/stm32f2xx/interrupts_hal.c index 063be4530d..60cd3a4c62 100644 --- a/hal/src/stm32f2xx/interrupts_hal.c +++ b/hal/src/stm32f2xx/interrupts_hal.c @@ -28,6 +28,7 @@ #include "gpio_hal.h" #include "pinmap_impl.h" #include "stm32f2xx.h" +#include "service_debug.h" #include /* Private typedef -----------------------------------------------------------*/ @@ -262,6 +263,11 @@ void HAL_Interrupts_Restore(void) { EXTI->FTSR = exti_saved_state.ftsr; } +uint32_t HAL_Interrupts_Pin_IRQn(pin_t pin) { + STM32_Pin_Info* PIN_MAP = HAL_Pin_Map(); + return GPIO_IRQn[PIN_MAP[pin].gpio_pin]; +} + /******************************************************************************* * Function Name : HAL_EXTI_Handler (Declared as weak in WICED - platform_gpio.c) * Description : This function is called by any of the interrupt handlers. It diff --git a/hal/src/template/core_hal.cpp b/hal/src/template/core_hal.cpp index 0004ba01b2..a1602f3b6f 100644 --- a/hal/src/template/core_hal.cpp +++ b/hal/src/template/core_hal.cpp @@ -158,3 +158,11 @@ uint32_t HAL_Core_Read_Backup_Register(uint32_t BKP_DR) { return 0xFFFFFFFF; } + +void HAL_Core_Button_Mirror_Pin_Disable(uint8_t bootloader, uint8_t button, void* reserved) +{ +} + +void HAL_Core_Button_Mirror_Pin(uint16_t pin, InterruptMode mode, uint8_t bootloader, uint8_t button, void *reserved) +{ +} diff --git a/platform/MCU/STM32F1xx/SPARK_Firmware_Driver/inc/hw_config.h b/platform/MCU/STM32F1xx/SPARK_Firmware_Driver/inc/hw_config.h index a38a581834..e14e187e97 100644 --- a/platform/MCU/STM32F1xx/SPARK_Firmware_Driver/inc/hw_config.h +++ b/platform/MCU/STM32F1xx/SPARK_Firmware_Driver/inc/hw_config.h @@ -53,7 +53,7 @@ enum SpiBusOwner { /* Exported types ------------------------------------------------------------*/ typedef enum { - BUTTON1 = 0, BUTTON2 = 1 + BUTTON1 = 0, BUTTON2 = 1, BUTTON1_MIRROR = 2 } Button_TypeDef; typedef enum diff --git a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/dct.h b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/dct.h index ea71a91bf7..fe54a456ce 100644 --- a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/dct.h +++ b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/dct.h @@ -27,6 +27,7 @@ extern "C" { #include "platform_flash_modules.h" #include "static_assert.h" #include "stddef.h" // for offsetof in C +#include "hw_config.h" // for button_config_t #define MAX_MODULES_SLOT 5 //Max modules #define FAC_RESET_SLOT 0 //Factory reset module index @@ -79,7 +80,8 @@ typedef struct __attribute__((packed)) application_dct { uint8_t alt_server_address[DCT_SERVER_ADDRESS_SIZE]; // server address info uint8_t device_id[12]; // the STM32 device ID uint8_t radio_flags; // xxxxxx10 means disable the wifi powersave testmode signal on P1. Any other values in the lower 2 bits means enabled. - uint8_t reserved2[627]; + button_config_t mode_button_mirror; // SETUP/MODE button mirror pin, to be used by bootloader + uint8_t reserved2[595]; // safe to add more data here or use up some of the reserved space to keep the end where it is uint8_t end[0]; } application_dct_t; @@ -108,6 +110,7 @@ typedef struct __attribute__((packed)) application_dct { #define DCT_ALT_SERVER_ADDRESS_OFFSET (offsetof(application_dct_t, alt_server_address)) #define DCT_DEVICE_ID_OFFSET (offsetof(application_dct_t, device_id)) #define DCT_RADIO_FLAGS_OFFSET (offsetof(application_dct_t, radio_flags)) +#define DCT_MODE_BUTTON_MIRROR_OFFSET (offsetof(application_dct_t, mode_button_mirror)) #define DCT_SYSTEM_FLAGS_SIZE (sizeof(application_dct_t::system_flags)) #define DCT_DEVICE_PRIVATE_KEY_SIZE (sizeof(application_dct_t::device_private_key)) @@ -131,6 +134,7 @@ typedef struct __attribute__((packed)) application_dct { #define DCT_ALT_SERVER_ADDRESS_SIZE (sizeof(application_dct_t::alt_server_address)) #define DCT_DEVICE_ID_SIZE (sizeof(application_dct_t::device_id)) #define DCT_RADIO_FLAGS_SIZE (sizeof(application_dct_t::radio_flags)) +#define DCT_MODE_BUTTON_MIRROR_SIZE (sizeof(application_dct_t::mode_button_mirror)) #define STATIC_ASSERT_DCT_OFFSET(field, expected) STATIC_ASSERT( dct_##field, offsetof(application_dct_t, field)==expected) #define STATIC_ASSERT_FLAGS_OFFSET(field, expected) STATIC_ASSERT( dct_sysflag_##field, offsetof(platform_system_flags_t, field)==expected) @@ -164,9 +168,10 @@ STATIC_ASSERT_DCT_OFFSET(alt_server_public_key, 3298 /* 3106 + 192 */); STATIC_ASSERT_DCT_OFFSET(alt_server_address, 3490 /* 3298 + 192 */); STATIC_ASSERT_DCT_OFFSET(device_id, 3618 /* 3490 + 128 */); STATIC_ASSERT_DCT_OFFSET(radio_flags, 3630 /* 3618 + 12 */); +STATIC_ASSERT_DCT_OFFSET(mode_button_mirror, 3631 /* 3630 + 1 */); -STATIC_ASSERT_DCT_OFFSET(reserved2, 3631 /* 3630 + 1 */); -STATIC_ASSERT_DCT_OFFSET(end, 4258 /* 3631 + 627 */); +STATIC_ASSERT_DCT_OFFSET(reserved2, 3663 /* 3631 + 32 */); +STATIC_ASSERT_DCT_OFFSET(end, 4258 /* 3663 + 595 */); STATIC_ASSERT_FLAGS_OFFSET(Bootloader_Version_SysFlag, 4); STATIC_ASSERT_FLAGS_OFFSET(NVMEM_SPARK_Reset_SysFlag, 6); diff --git a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/hw_config.h b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/hw_config.h index f7e65a3118..53b82d3ee5 100644 --- a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/hw_config.h +++ b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/hw_config.h @@ -48,7 +48,8 @@ extern "C" { /* Exported types ------------------------------------------------------------*/ typedef enum { - BUTTON1 = 0 + BUTTON1 = 0, + BUTTON1_MIRROR = 1 } Button_TypeDef; typedef enum @@ -56,6 +57,30 @@ typedef enum BUTTON_MODE_GPIO = 0, BUTTON_MODE_EXTI = 1 } ButtonMode_TypeDef; +typedef struct { + __IO uint8_t active; + GPIO_TypeDef* port; + uint16_t pin; + union { + uint16_t clk; + uint16_t hal_pin; + }; + union { + GPIOMode_TypeDef mode; + uint16_t interrupt_mode; + }; + GPIOPuPd_TypeDef pupd; + __IO uint16_t debounce_time; + uint16_t exti_line; + uint16_t exti_port_source; + uint16_t exti_pin_source; + uint16_t exti_irqn; + uint16_t exti_irq_prio; + EXTITrigger_TypeDef exti_trigger; +} button_config_t; + +extern button_config_t HAL_Buttons[]; + /* Exported constants --------------------------------------------------------*/ /* Exported macros ------------------------------------------------------------*/ diff --git a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/platform_config.h b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/platform_config.h index 72ed6f8fb1..77bca8631d 100644 --- a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/platform_config.h +++ b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/platform_config.h @@ -92,6 +92,7 @@ #define BUTTON1_EXTI_IRQ_PRIORITY 7 #define BUTTON1_EXTI_IRQ_INDEX 24 #define BUTTON1_EXTI_TRIGGER EXTI_Trigger_Falling +#define BUTTON1_MIRROR_SUPPORTED 1 #elif PLATFORM_TEACUP_PIGTAIL_DEV == PLATFORM_ID || \ PLATFORM_PHOTON_PRODUCTION == PLATFORM_ID || \ PLATFORM_TEACUP_PIGTAIL_PRODUCTION == PLATFORM_ID || \ @@ -111,6 +112,7 @@ #define BUTTON1_EXTI_IRQ_PRIORITY 7 #define BUTTON1_EXTI_IRQ_INDEX 39 #define BUTTON1_EXTI_TRIGGER EXTI_Trigger_Falling +#define BUTTON1_MIRROR_SUPPORTED 1 #endif #define UI_TIMER_FREQUENCY 100 /* 100Hz -> 10ms */ diff --git a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/src/hw_config.c b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/src/hw_config.c index 7377c6b167..24cb5728b2 100644 --- a/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/src/hw_config.c +++ b/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/src/hw_config.c @@ -50,19 +50,30 @@ const uint32_t LED_GPIO_CLK[] = {LED1_GPIO_CLK, LED2_GPIO_CLK, LED3_GPIO_CLK, LE const uint8_t LED_GPIO_PIN_SOURCE[] = {LED1_GPIO_PIN_SOURCE, LED2_GPIO_PIN_SOURCE, LED3_GPIO_PIN_SOURCE, LED4_GPIO_PIN_SOURCE}; const uint8_t LED_GPIO_AF_TIM[] = {LED1_GPIO_AF_TIM, LED2_GPIO_AF_TIM, LED3_GPIO_AF_TIM, LED4_GPIO_AF_TIM}; -GPIO_TypeDef* BUTTON_GPIO_PORT[] = {BUTTON1_GPIO_PORT}; -const uint16_t BUTTON_GPIO_PIN[] = {BUTTON1_GPIO_PIN}; -const uint32_t BUTTON_GPIO_CLK[] = {BUTTON1_GPIO_CLK}; -GPIOMode_TypeDef BUTTON_GPIO_MODE[] = {BUTTON1_GPIO_MODE}; -GPIOPuPd_TypeDef BUTTON_GPIO_PUPD[] = {BUTTON1_GPIO_PUPD}; -__IO uint16_t BUTTON_DEBOUNCED_TIME[] = {0}; - -const uint16_t BUTTON_EXTI_LINE[] = {BUTTON1_EXTI_LINE}; -const uint16_t BUTTON_EXTI_PORT_SOURCE[] = {BUTTON1_EXTI_PORT_SOURCE}; -const uint16_t BUTTON_EXTI_PIN_SOURCE[] = {BUTTON1_EXTI_PIN_SOURCE}; -const uint16_t BUTTON_EXTI_IRQn[] = {BUTTON1_EXTI_IRQn}; -const uint8_t BUTTON_EXTI_IRQ_PRIORITY[] = {BUTTON1_EXTI_IRQ_PRIORITY}; -EXTITrigger_TypeDef BUTTON_EXTI_TRIGGER[] = {BUTTON1_EXTI_TRIGGER}; +button_config_t HAL_Buttons[] = { + { + .active = 0, + .port = BUTTON1_GPIO_PORT, + .pin = BUTTON1_GPIO_PIN, + .clk = BUTTON1_GPIO_CLK, + .mode = BUTTON1_GPIO_MODE, + .pupd = BUTTON1_GPIO_PUPD, + .debounce_time = 0, + + .exti_line = BUTTON1_EXTI_LINE, + .exti_port_source = BUTTON1_EXTI_PORT_SOURCE, + .exti_pin_source = BUTTON1_EXTI_PIN_SOURCE, + .exti_irqn = BUTTON1_EXTI_IRQn, + .exti_irq_prio = BUTTON1_EXTI_IRQ_PRIORITY, + .exti_trigger = BUTTON1_EXTI_TRIGGER + }, + { + .active = 0, + .port = NULL, + .debounce_time = 0, + .exti_line = 0 + } +}; /* Extern variables ----------------------------------------------------------*/ extern USB_OTG_CORE_HANDLE USB_OTG_dev; @@ -378,36 +389,36 @@ void BUTTON_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode) NVIC_InitTypeDef NVIC_InitStructure; /* Enable the BUTTON Clock */ - RCC_AHB1PeriphClockCmd(BUTTON_GPIO_CLK[Button], ENABLE); + RCC_AHB1PeriphClockCmd(HAL_Buttons[Button].clk, ENABLE); /* Configure Button pin */ - GPIO_InitStructure.GPIO_Pin = BUTTON_GPIO_PIN[Button]; - GPIO_InitStructure.GPIO_Mode = BUTTON_GPIO_MODE[Button]; - GPIO_InitStructure.GPIO_PuPd = BUTTON_GPIO_PUPD[Button]; - GPIO_Init(BUTTON_GPIO_PORT[Button], &GPIO_InitStructure); + GPIO_InitStructure.GPIO_Pin = HAL_Buttons[Button].pin; + GPIO_InitStructure.GPIO_Mode = HAL_Buttons[Button].mode; + GPIO_InitStructure.GPIO_PuPd = HAL_Buttons[Button].pupd; + GPIO_Init(HAL_Buttons[Button].port, &GPIO_InitStructure); if (Button_Mode == BUTTON_MODE_EXTI) { /* Disable TIM2 CC1 Interrupt */ TIM_ITConfig(TIM2, TIM_IT_CC1, DISABLE); - /* Enable the TIM2 Interrupt */ - NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TIM2_IRQ_PRIORITY; + /* Enable the Button EXTI Interrupt */ + NVIC_InitStructure.NVIC_IRQChannel = HAL_Buttons[Button].exti_irqn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = HAL_Buttons[Button].exti_irq_prio; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + BUTTON_EXTI_Config(Button, ENABLE); + NVIC_Init(&NVIC_InitStructure); - /* Enable the Button EXTI Interrupt */ - NVIC_InitStructure.NVIC_IRQChannel = BUTTON_EXTI_IRQn[Button]; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = BUTTON_EXTI_IRQ_PRIORITY[Button]; + /* Enable the TIM2 Interrupt */ + NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TIM2_IRQ_PRIORITY; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); - - BUTTON_EXTI_Config(Button, ENABLE); } } @@ -416,17 +427,20 @@ void BUTTON_EXTI_Config(Button_TypeDef Button, FunctionalState NewState) EXTI_InitTypeDef EXTI_InitStructure; /* Connect Button EXTI Line to Button GPIO Pin */ - SYSCFG_EXTILineConfig(BUTTON_EXTI_PORT_SOURCE[Button], BUTTON_EXTI_PIN_SOURCE[Button]); + SYSCFG_EXTILineConfig(HAL_Buttons[Button].exti_port_source, HAL_Buttons[Button].exti_pin_source); /* Clear the EXTI line pending flag */ - EXTI_ClearFlag(BUTTON_EXTI_LINE[Button]); + EXTI_ClearITPendingBit(HAL_Buttons[Button].exti_line); /* Configure Button EXTI line */ - EXTI_InitStructure.EXTI_Line = BUTTON_EXTI_LINE[Button]; + EXTI_InitStructure.EXTI_Line = HAL_Buttons[Button].exti_line; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; - EXTI_InitStructure.EXTI_Trigger = BUTTON_EXTI_TRIGGER[Button]; + EXTI_InitStructure.EXTI_Trigger = HAL_Buttons[Button].exti_trigger; EXTI_InitStructure.EXTI_LineCmd = NewState; EXTI_Init(&EXTI_InitStructure); + + /* Clear the EXTI line pending flag */ + EXTI_ClearITPendingBit(HAL_Buttons[Button].exti_line); } /** @@ -438,7 +452,7 @@ void BUTTON_EXTI_Config(Button_TypeDef Button, FunctionalState NewState) */ uint8_t BUTTON_GetState(Button_TypeDef Button) { - return GPIO_ReadInputDataBit(BUTTON_GPIO_PORT[Button], BUTTON_GPIO_PIN[Button]); + return GPIO_ReadInputDataBit(HAL_Buttons[Button].port, HAL_Buttons[Button].pin); } /** @@ -450,12 +464,12 @@ uint8_t BUTTON_GetState(Button_TypeDef Button) */ uint16_t BUTTON_GetDebouncedTime(Button_TypeDef Button) { - return BUTTON_DEBOUNCED_TIME[Button]; + return HAL_Buttons[Button].debounce_time; } void BUTTON_ResetDebouncedState(Button_TypeDef Button) { - BUTTON_DEBOUNCED_TIME[Button] = 0; + HAL_Buttons[Button].debounce_time = 0; } #ifdef HAS_SERIAL_FLASH diff --git a/platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/src/usb_core.c b/platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/src/usb_core.c index 2645e40177..c10f602225 100644 --- a/platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/src/usb_core.c +++ b/platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/src/usb_core.c @@ -26,6 +26,7 @@ */ /* Includes ------------------------------------------------------------------*/ +#include "usb_conf.h" #include "usb_core.h" #include "usb_bsp.h" diff --git a/system/src/main.cpp b/system/src/main.cpp index d0f77b4231..02aaa57cb9 100644 --- a/system/src/main.cpp +++ b/system/src/main.cpp @@ -226,7 +226,11 @@ void handle_button_click(uint16_t depressed_duration) // this is called on multiple threads - ideally need a mutex void HAL_Notify_Button_State(uint8_t button, uint8_t pressed) { +#ifdef BUTTON1_MIRROR_SUPPORTED + if (button==0 || button == BUTTON1_MIRROR) +#else if (button==0) +#endif { if (pressed) { diff --git a/user/tests/wiring/api/system.cpp b/user/tests/wiring/api/system.cpp index 05ab5d599f..875805f0d3 100644 --- a/user/tests/wiring/api/system.cpp +++ b/user/tests/wiring/api/system.cpp @@ -231,3 +231,14 @@ test(backup_ram) } #endif // defined(USER_BACKUP_RAM) + +test(system_mode_button) +{ + API_COMPILE(System.buttonMirror(D1, RISING)); + API_COMPILE(System.buttonMirror(D1, FALLING)); + API_COMPILE(System.buttonMirror(D1, RISING, true)); + API_COMPILE(System.buttonMirror(D1, FALLING, true)); + + API_COMPILE(System.disableButtonMirror()); + API_COMPILE(System.disableButtonMirror(false)); +} \ No newline at end of file diff --git a/user/tests/wiring/no_fixture/system.cpp b/user/tests/wiring/no_fixture/system.cpp index e5f93ab934..d57bbc0c31 100644 --- a/user/tests/wiring/no_fixture/system.cpp +++ b/user/tests/wiring/no_fixture/system.cpp @@ -75,4 +75,40 @@ test(SYSTEM_03_user_backup_ram) assertTrue(int(&app_ram)<0x40024000); } -#endif // defined(USER_BACKUP_RAM) \ No newline at end of file +#endif // defined(USER_BACKUP_RAM) + +#if defined(BUTTON1_MIRROR_SUPPORTED) +static int s_button_clicks = 0; +static void onButtonClick(system_event_t ev, int data) { + s_button_clicks = data; +} +test(SYSTEM_04_button_mirror) +{ + System.buttonMirror(D1, FALLING, false); + auto pinmap = HAL_Pin_Map(); + System.on(button_click, onButtonClick); + + // First click + pinMode(D1, INPUT_PULLDOWN); + // Just in case manually trigger EXTI interrupt + EXTI_GenerateSWInterrupt(pinmap[D1].gpio_pin); + delay(300); + pinMode(D1, INPUT_PULLUP); + delay(100); + + // Second click + pinMode(D1, INPUT_PULLDOWN); + // Just in case manually trigger EXTI interrupt + EXTI_GenerateSWInterrupt(pinmap[D1].gpio_pin); + delay(300); + pinMode(D1, INPUT_PULLUP); + delay(300); + + assertEqual(s_button_clicks, 2); +} + +test(SYSTEM_05_button_mirror_disable) +{ + System.disableButtonMirror(false); +} +#endif // defined(BUTTON1_MIRROR_SUPPORTED) \ No newline at end of file diff --git a/wiring/inc/spark_wiring_system.h b/wiring/inc/spark_wiring_system.h index a42838465e..dc88be6741 100644 --- a/wiring/inc/spark_wiring_system.h +++ b/wiring/inc/spark_wiring_system.h @@ -281,6 +281,16 @@ class SystemClass { return data; } + void buttonMirror(pin_t pin, InterruptMode mode, bool bootloader=false) const + { + HAL_Core_Button_Mirror_Pin(pin, mode, (uint8_t)bootloader, 0, NULL); + } + + void disableButtonMirror(bool bootloader=true) const + { + HAL_Core_Button_Mirror_Pin_Disable((uint8_t)bootloader, 0, NULL); + } + private: static inline uint8_t get_flag(system_flag_t flag)