#include "nrf_gpio.h" #include "nrf_gpiote.h" #include "nrfx_gpiote.h" #include "nrf_log.h" #include "elite_board.h" #include "led_drv.h" #include "FreeRTOS.h" #include "semphr.h" #include "task.h" #if (DEF_BTN_ENABLED) #define TIME_DEBOUNCE pdMS_TO_TICKS(25) #define TIME_CLICK_INTERVAL pdMS_TO_TICKS(200) #define TIME_PRESS_LONG pdMS_TO_TICKS(1500) //-------------------------------------------------------------------- static TaskHandle_t btn_task_handle = NULL; static void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t xPin, nrf_gpiote_polarity_t ePolarity) { uint32_t pins = nrf_gpio_pin_read(SHUT_DOWN_PIN); if (__get_IPSR() != 0) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xTaskNotifyFromISR(btn_task_handle, pins, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } else { xTaskNotify(btn_task_handle, xPin, eSetValueWithOverwrite); } } static bool wait_pressed(TickType_t xTimeout) { uint32_t pins; do { if (!xTaskNotifyWait(0, 0, &pins, xTimeout)) { return false; } do { } while (xTaskNotifyWait(0, 0, &pins, TIME_DEBOUNCE)); } while (pins); return true; } static bool wait_released(TickType_t xTimeout) { uint32_t pins; do { if (!xTaskNotifyWait(0, 0, &pins, xTimeout)) { return false; } do { } while (xTaskNotifyWait(0, 0, &pins, TIME_DEBOUNCE)); } while (!pins); return true; } //-------------------------------------------------------------------- typedef enum { BTN_EVENT_SHORTx1, BTN_EVENT_SHORTx2, BTN_EVENT_SHORTx3, BTN_EVENT_LONG, } BtnEvent_t; static BtnEvent_t btn_event(void) { while (1) { // drop previous/undefined clicks while (wait_pressed(TIME_CLICK_INTERVAL)) { wait_released(portMAX_DELAY); } // wait for clicks wait_pressed(portMAX_DELAY); if (!wait_released(TIME_PRESS_LONG)) { return BTN_EVENT_LONG; } for (BtnEvent_t e = BTN_EVENT_SHORTx1; e < BTN_EVENT_LONG; e++) { if (!wait_pressed(TIME_CLICK_INTERVAL)) { return e; } if (!wait_released(TIME_PRESS_LONG)) { break; } } } } static void btn_event_shortx1_cb(void) { NRF_LOG_INFO("BTN_EVENT_SHORTx1"); const struct led_color color[6] = { LED_RED, LED_ORANGE, LED_YELLOW, LED_GREEN, LED_BLUE, LED_PURPLE }; static int idx = 0; led_set(color[idx++ % COUNTOF(color)]); } static void btn_event_shortx2_cb(void) { NRF_LOG_INFO("BTN_EVENT_SHORTx2"); for (int i = 0; i < 2; i++) { led_set(LED_OFF); vTaskDelay(pdMS_TO_TICKS(250)); led_set(LED_BLUE); vTaskDelay(pdMS_TO_TICKS(250)); } led_set(LED_IDEL_DISCONNECT); } static void btn_event_shortx3_cb(void) { NRF_LOG_INFO("BTN_EVENT_SHORTx3"); for (int i = 0; i < 2; i++) { led_set(LED_OFF); vTaskDelay(pdMS_TO_TICKS(250)); led_set(LED_CYAN); vTaskDelay(pdMS_TO_TICKS(250)); led_set(LED_IDEL_DISCONNECT); } led_set(LED_IDEL_DISCONNECT); } static void btn_event_long(void) { NRF_LOG_INFO("BTN_EVENT_LONG"); led_set(LED_ORANGE); if (!wait_released(TIME_PRESS_LONG)) { led_set(LED_OFF); elite_board_power_off(); } led_set(LED_IDEL_DISCONNECT); } static void btn_task(void *pvArg) { for (;;) { switch (btn_event()) { case BTN_EVENT_SHORTx1: btn_event_shortx1_cb(); break; case BTN_EVENT_SHORTx2: btn_event_shortx2_cb(); break; case BTN_EVENT_SHORTx3: btn_event_shortx3_cb(); break; case BTN_EVENT_LONG: btn_event_long(); break; } } } void btn_init(void) { nrfx_gpiote_in_config_t config = { .hi_accuracy = 1, .is_watcher = 0, .pull = NRF_GPIO_PIN_NOPULL, .sense = NRF_GPIOTE_POLARITY_TOGGLE, .skip_gpio_setup = 0 }; nrfx_gpiote_init(); nrfx_gpiote_in_init(SHUT_DOWN_PIN, &config, nrfx_gpiote_evt_handler); nrfx_gpiote_in_event_enable(SHUT_DOWN_PIN, true); xTaskCreate(btn_task, "btn", 256, NULL, 3, &btn_task_handle); } #endif // !SHUT_DOWN_PIN