/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : bsp_key.c * @brief : Board support package key driver implementation ****************************************************************************** */ /* USER CODE END Header */ #include "bsp_key.h" #include "bsp_config.h" #include "hal_gpio.h" #include "bsp_board.h" #include "bsp_board_manager.h" #include "hal_delay.h" /** * @brief Key debounce configuration */ #define KEY_DEBOUNCE_COUNT 5 /* Debounce count (each update is ~10ms, so 50ms debounce) */ #define KEY_LONG_PRESS_TIME 1000 /* Long press time in ms */ #define KEY_REPEAT_INTERVAL 200 /* Repeat interval in ms */ #define KEY_SHORT_PRESS_TIME 200 /* Short press time in ms */ #define KEY_UPDATE_INTERVAL 10 /* Update interval in ms */ /** * @brief Key configuration structure */ typedef struct { hal_gpio_port_t port; hal_gpio_pin_t pin; uint8_t active_high; } bsp_key_config_t; /** * @brief Key state structure for debouncing and event detection */ typedef struct { /* Debounce state */ bsp_key_state_t current_state; /* Current debounced state */ bsp_key_state_t previous_state; /* Previous debounced state */ uint8_t debounce_counter; /* Debounce counter */ /* Event flags */ uint8_t press_event; /* Press event flag */ uint8_t release_event; /* Release event flag */ uint8_t long_press_event; /* Long press event flag */ uint8_t repeat_event; /* Repeat event flag */ uint8_t short_press_event; /* Short press event flag */ /* Timing variables */ uint32_t press_start_time; /* Press start time in ms */ uint32_t last_repeat_time; /* Last repeat event time in ms */ uint32_t current_time; /* Current time in ms */ /* Configuration */ uint16_t long_press_time; /* Long press time in ms */ uint16_t repeat_interval; /* Repeat interval in ms */ uint16_t short_press_time; /* Short press time in ms */ /* Key configuration */ const bsp_button_config_t* button_config; } bsp_key_internal_state_t; /** * @brief Key state table for debouncing and event detection */ static bsp_key_internal_state_t key_state_table[BSP_KEY_ID_MAX] = {0}; /** * @brief Get current board button configuration */ static const bsp_button_config_t* bsp_key_get_button_config(bsp_key_id_t key_id) { const bsp_board_config_t* board_config = bsp_board_get_config(); if (board_config && key_id < board_config->buttons.count) { return &board_config->buttons.buttons[key_id]; } return NULL; } /** * @brief Read raw key state (without debounce) * @param key_id: Key ID * @retval Raw key state */ static bsp_key_state_t bsp_key_read_raw(bsp_key_id_t key_id) { bsp_key_state_t state; const bsp_button_config_t* button_config = bsp_key_get_button_config(key_id); if (button_config) { hal_gpio_pin_state_t gpio_state; /* Read GPIO pin state */ gpio_state = hal_gpio_read_pin(button_config->port, button_config->pin); /* Convert to key state based on active level */ if (button_config->active_high) { state = (gpio_state == HAL_GPIO_PIN_SET) ? BSP_KEY_STATE_PRESSED : BSP_KEY_STATE_RELEASED; } else { state = (gpio_state == HAL_GPIO_PIN_RESET) ? BSP_KEY_STATE_PRESSED : BSP_KEY_STATE_RELEASED; } } else { state = BSP_KEY_STATE_RELEASED; } return state; } /** * @brief Get current system time in milliseconds * @retval Current time in ms */ static uint32_t bsp_key_get_time_ms(void) { /* Use HAL tick function */ return hal_get_tick(); } /** * @brief Initialize all keys */ void bsp_key_init(void) { uint8_t i; /* Get current board configuration */ const bsp_board_config_t* board_config = bsp_board_get_config(); /* Initialize key state table */ for (i = 0; i < BSP_KEY_ID_MAX; i++) { /* Get button configuration for this key */ const bsp_button_config_t* button_config = bsp_key_get_button_config((bsp_key_id_t)i); /* Initialize with current state */ key_state_table[i].current_state = bsp_key_read_raw((bsp_key_id_t)i); key_state_table[i].previous_state = key_state_table[i].current_state; key_state_table[i].debounce_counter = 0; /* Clear event flags */ key_state_table[i].press_event = 0; key_state_table[i].release_event = 0; key_state_table[i].long_press_event = 0; key_state_table[i].repeat_event = 0; key_state_table[i].short_press_event = 0; /* Initialize timing variables */ key_state_table[i].press_start_time = 0; key_state_table[i].last_repeat_time = 0; key_state_table[i].current_time = 0; /* Set default configuration */ key_state_table[i].long_press_time = KEY_LONG_PRESS_TIME; key_state_table[i].repeat_interval = KEY_REPEAT_INTERVAL; key_state_table[i].short_press_time = KEY_SHORT_PRESS_TIME; /* Store button configuration */ key_state_table[i].button_config = button_config; } /* Call board-specific button initialization if available */ if (board_config && board_config->button_init) { board_config->button_init(&board_config->buttons); } } /** * @brief Update key state (call this function periodically, e.g. every 10ms) */ void bsp_key_update(void) { uint8_t i; uint32_t current_time = bsp_key_get_time_ms(); for (i = 0; i < BSP_KEY_ID_MAX; i++) { /* Skip if button configuration is not available */ if (!key_state_table[i].button_config) { continue; } bsp_key_state_t raw_state = bsp_key_read_raw((bsp_key_id_t)i); bsp_key_internal_state_t* key_state = &key_state_table[i]; /* Update current time */ key_state->current_time = current_time; /* Debounce logic - optimized version */ if (raw_state != key_state->current_state) { /* State is changing, increment counter */ if (++key_state->debounce_counter >= KEY_DEBOUNCE_COUNT) { /* Debounce count reached, update state */ key_state->previous_state = key_state->current_state; key_state->current_state = raw_state; key_state->debounce_counter = 0; if (raw_state == BSP_KEY_STATE_PRESSED) { /* Key pressed event */ key_state->press_event = 1; key_state->release_event = 0; key_state->short_press_event = 0; /* Reset timing variables */ key_state->press_start_time = current_time; key_state->last_repeat_time = current_time; key_state->long_press_event = 0; key_state->repeat_event = 0; } else { /* Key released event */ key_state->release_event = 1; key_state->press_event = 0; /* Check for short press event */ uint32_t press_duration = current_time - key_state->press_start_time; if (press_duration < key_state->long_press_time) { key_state->short_press_event = 1; } /* Reset long press and repeat flags */ key_state->long_press_event = 0; key_state->repeat_event = 0; } } } else { /* State is stable, reset counter */ key_state->debounce_counter = 0; /* Handle timing-based events if key is pressed */ if (raw_state == BSP_KEY_STATE_PRESSED) { uint32_t press_duration = current_time - key_state->press_start_time; /* Check for long press event - only set once */ if (press_duration >= key_state->long_press_time && !key_state->long_press_event) { key_state->long_press_event = 1; } /* Check for repeat event - only after long press */ if (key_state->long_press_event && (current_time - key_state->last_repeat_time >= key_state->repeat_interval)) { key_state->repeat_event = 1; key_state->last_repeat_time = current_time; } } } } } /** * @brief Read debounced key state * @param key_id: Key ID * @retval Key state */ bsp_key_state_t bsp_key_read(bsp_key_id_t key_id) { if (key_id < BSP_KEY_ID_MAX) { return key_state_table[key_id].current_state; } return BSP_KEY_STATE_RELEASED; } /** * @brief Check if key is pressed * @param key_id: Key ID * @retval 1 if pressed, 0 otherwise */ uint8_t bsp_key_is_pressed(bsp_key_id_t key_id) { return (bsp_key_read(key_id) == BSP_KEY_STATE_PRESSED) ? 1 : 0; } /** * @brief Check if key is released * @param key_id: Key ID * @retval 1 if released, 0 otherwise */ uint8_t bsp_key_is_released(bsp_key_id_t key_id) { return (bsp_key_read(key_id) == BSP_KEY_STATE_RELEASED) ? 1 : 0; } /** * @brief Check for key press event (edge detection) * @param key_id: Key ID * @retval 1 if key was pressed, 0 otherwise */ uint8_t bsp_key_get_press_event(bsp_key_id_t key_id) { uint8_t event = 0; if (key_id < BSP_KEY_ID_MAX) { event = key_state_table[key_id].press_event; key_state_table[key_id].press_event = 0; /* Clear event flag */ } return event; } /** * @brief Check for key release event (edge detection) * @param key_id: Key ID * @retval 1 if key was released, 0 otherwise */ uint8_t bsp_key_get_release_event(bsp_key_id_t key_id) { uint8_t event = 0; if (key_id < BSP_KEY_ID_MAX) { event = key_state_table[key_id].release_event; key_state_table[key_id].release_event = 0; /* Clear event flag */ } return event; } /** * @brief Check for key long pressed event * @param key_id: Key ID * @retval 1 if key was long pressed, 0 otherwise */ uint8_t bsp_key_get_long_press_event(bsp_key_id_t key_id) { uint8_t event = 0; if (key_id < BSP_KEY_ID_MAX) { event = key_state_table[key_id].long_press_event; /* Long press event is only reported once */ } return event; } /** * @brief Check for key repeat event * @param key_id: Key ID * @retval 1 if key repeat event occurred, 0 otherwise */ uint8_t bsp_key_get_repeat_event(bsp_key_id_t key_id) { uint8_t event = 0; if (key_id < BSP_KEY_ID_MAX) { event = key_state_table[key_id].repeat_event; key_state_table[key_id].repeat_event = 0; /* Clear event flag */ } return event; } /** * @brief Check for key short pressed event * @param key_id: Key ID * @retval 1 if key was short pressed, 0 otherwise */ uint8_t bsp_key_get_short_press_event(bsp_key_id_t key_id) { uint8_t event = 0; if (key_id < BSP_KEY_ID_MAX) { event = key_state_table[key_id].short_press_event; key_state_table[key_id].short_press_event = 0; /* Clear event flag */ } return event; }