/**
 ******************************************************************************
 * @文件     key.c
 * @作者     阜阳师范大学物电学院
 * @版本     V0.1
 * @日期     2026-01-15
 * @简介     按键驱动 - 基于 MultiButton 的高可移植性实现
 * @说明     
 *           
 ****
 */
 
#include "key.h"
#include "160160D.h"

// 按键配置结构体
typedef struct {
    uint16_t pin;                           // GPIO引脚
    GPIO_TypeDef* port;                     // GPIO端口
    KEY_TYPE key_type;                        // 按键ID
} KeyConfig_t;

/*
*******************详细引脚映射*****************************
| 按键名称 | 端口 | 引脚 | 位定义 | 功能说明 |
|---------|------|------|--------|----------|
| KEY_ENTER | GPIOB | PB15 | KEY_ENTER_BIT | 确认键 |
| KEY_UP | GPIOD | PD11 | KEY_UP_BIT | 上键 |
| KEY_DOWN | GPIOD | PD10 | KET_DOWN_BIT | 下键 |
| KEY_LEFT | GPIOD | PD13 | KET_LEFT_BIT | 左键 |
| KEY_RIGHT | GPIOD | PD8 | KET_RIGHT_BIT | 右键 |
| KEY_ESC | GPIOD | PD12 | KET_ESC_BIT | 取消键 |
| KEY_ADD | GPIOD | PD14 | KET_ADD_BIT | 加键 |
| KEY_DEC | GPIOD | PD9 | KET_DEC_BIT | 减键 |
| KEY_RESET | GPIOD | PD15 | KET_RESET_BIT | 复位键 |
***************************************************************
*/
// 按键配置表
static const KeyConfig_t key_configs[] = {
    {GPIO_PIN_12, GPIOD, KEY_ENTER},       
    {GPIO_PIN_11, GPIOD, KEY_UP},
    {GPIO_PIN_10, GPIOD, KEY_DOWN},
    {GPIO_PIN_13, GPIOD, KEY_LEFT},
    {GPIO_PIN_8,  GPIOD, KEY_RIGHT},
    {GPIO_PIN_15, GPIOB, KEY_ESC},
    {GPIO_PIN_3,  GPIOB, KEY_ADD},
    {GPIO_PIN_15, GPIOD, KEY_RESET},
};
#define KEY_COUNT         (sizeof(key_configs) / sizeof(key_configs[0]))

// 按键句柄数组
static Button btn_handles[KEY_COUNT];
// 业务逻辑回调函数指针（由main.c注册）
static KeyCallback key_callback = NULL;


/**
 * @brief 读取按键GPIO电平
 * @param button_id 按键ID
 * @retval 0:按下, 1:释放
 */
static uint8_t button_read_level(uint8_t button_id)
{
    uint8_t pin_bit = HAL_GPIO_ReadPin(key_configs[button_id].port, key_configs[button_id].pin);
    return pin_bit;
}

/**
 * @brief 统一的按键回调函数（内部使用，调用业务逻辑回调）
* @param btn 按键句柄指针 
 */
static void button_callback(Button* btn)
{
    if (btn != NULL && key_callback != NULL)
    {
        // 通过button_id获取对应的按键类型
        uint8_t button_id = btn->button_id;
        if (button_id < KEY_COUNT)
        {
            // 调用业务逻辑层注册的回调函数
            key_callback(key_configs[button_id].key_type);
        }
    }
}
/**
 * @brief 注册按键回调函数（供业务逻辑层调用）
 * @param callback 回调函数指针
 */
void Key_RegisterCallback(KeyCallback callback)
{
    key_callback = callback;
}
/**
 * @brief  使能GPIO时钟
 * @param  port: GPIO端口
 * @retval 无
 * @note   使用switch-case结构，代码更简洁清晰，支持所有GPIO端口（A-G）
 */
static void KEY_GPIO_ClockEnable(GPIO_TypeDef *port)
{
    switch ((uint32_t)port) {
        case (uint32_t)GPIOA: __HAL_RCC_GPIOA_CLK_ENABLE(); break;
        case (uint32_t)GPIOB: __HAL_RCC_GPIOB_CLK_ENABLE(); break;
        case (uint32_t)GPIOC: __HAL_RCC_GPIOC_CLK_ENABLE(); break;
        case (uint32_t)GPIOD: __HAL_RCC_GPIOD_CLK_ENABLE(); break;
        case (uint32_t)GPIOE: __HAL_RCC_GPIOE_CLK_ENABLE(); break;
        case (uint32_t)GPIOF: __HAL_RCC_GPIOF_CLK_ENABLE(); break;
        case (uint32_t)GPIOG: __HAL_RCC_GPIOG_CLK_ENABLE(); break;
        default: break;
    }
}
/**************************************************************************************
* FunctionName   : Key_Init()
* Description    : 按键硬件初始化（使用MultiButton库）
* EntryParameter : none
* ReturnValue    : none 
**************************************************************************************/
void Key_Init(void)
{
    /*由于使用了 PB3 才需要特殊加的*/
    __HAL_RCC_AFIO_CLK_ENABLE();      // AFIO时钟（修改AFIO寄存器前必须）
    
    /* 禁用JTAG，保留SWD（PA13、PA14仍可用于调试）*/
    /* 这会释放 PA15、PB3、PB4 作为普通GPIO */
    __HAL_AFIO_REMAP_SWJ_NOJTAG();    
    
    
    GPIO_InitTypeDef gpio_init_struct = {0};
    // 批量初始化GPIO
    for (uint8_t button_id = 0; button_id < KEY_COUNT; button_id++)
    {
        /* 使能对应GPIO时钟 */
        KEY_GPIO_ClockEnable(key_configs[button_id].port);
        
        // 配置并初始化引脚
        gpio_init_struct.Pin = key_configs[button_id].pin;
        gpio_init_struct.Mode = GPIO_MODE_INPUT;  
        gpio_init_struct.Pull = GPIO_NOPULL;          
        gpio_init_struct.Speed = GPIO_SPEED_HIGH;
        HAL_GPIO_Init(key_configs[button_id].port, &gpio_init_struct);
        
        button_init(&btn_handles[button_id], button_read_level, 0, button_id);
        button_attach(&btn_handles[button_id], BTN_SINGLE_CLICK, button_callback);
        button_start(&btn_handles[button_id]);
    }
}

