Files
stm32f407ve_black/BSP/Src/bsp_key.c
2026-01-23 14:35:51 +08:00

352 lines
11 KiB
C

/* 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->init_funcs.button_init) {
board_config->init_funcs.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;
}