/******************************************************************************
 * @file        main.c
 * @brief       DTU 主程序 - 屏幕与按键控制
 * @details     本文件实现了 DTU 设备的主程序逻辑，包括：
 *              - 系统初始化（时钟、外设、看门狗等）
 *              - 按键事件处理与业务逻辑
 *              - RS485 Modbus 通信处理
 *              - 定时器中断服务（5ms 周期）
 *              - 系统运行指示灯控制
 *              - 看门狗喂狗与系统复位保护
 * @author      阜阳师范大学物电学院
 * @version     V0.1
 * @date        2026.1.19
 * @note        定时器周期：5ms
 *              系统复位时间：约 5000 秒（1000000 × 5ms）
 *              通信协议：Modbus RTU over RS485
 ******************************************************************************/

#include "main.h"

/* ============================================================================
 * 宏定义
 * ============================================================================ */
#define TIMER                               5        /**< 定时器周期（毫秒） */
#define LED_TOGGLE_TIME                     1000     /**< 系统运行指示灯闪烁周期（毫秒），即 LED 点亮持续时间 */

/* ============================================================================
 * 全局变量定义
 * ============================================================================ */
volatile static uint32_t sysRunTime = 0;            /**< 系统运行时间计数器（单位：5ms） */
volatile static uint8_t LED_ToggleFlag = 0;         /**< LED 闪烁定时标志位（1=需要翻转） */
static KEY_TYPE keyStatus = KEY_NONE;               /**< 按键状态指示（当前按键值） */
static uint8_t ConnectFlg = 0;                      /**< 连接标志：1=已连接，0=未连接 */
volatile static uint32_t KEY_RUN_Count = 0;         /**< 按键按下时 LCD 屏幕显示计时计数器（单位：5ms） */

/* ============================================================================
 * 内部函数实现
 * ============================================================================ */

/**
 * @brief  按键业务逻辑回调函数
 * @param  key_type 按键类型（KEY_TYPE 枚举值）
 * @note   当检测到按键事件时，由按键驱动层调用此函数
 *          处理流程：
 *          1. 打开背光（任意按键按下都打开背光）
 *          2. 显示按键按下指示（KeyRun_Disp）
 *          3. 重置按键显示计时器
 *          4. 更新按键状态（供主循环使用）
 * @retval 无
 */
static void Key_ProcessCallback(KEY_TYPE key_type)
{
    BackLight_ON();           /**< 任意按键按下，都打开背光 */
    
    KeyRun_Disp(1);           /**< 有按键按下，LCD 显示按键指示 */
    KEY_RUN_Count = 0;        /**< 重置按键显示计时器 */
    
    keyStatus = key_type;     /**< 更新按键状态，供主循环处理 */
}

/**
 * @brief  按键显示自动关闭处理
 * @note   在定时器中断中调用，用于自动关闭按键按下后的 LCD 显示指示
 *          处理逻辑：
 *          - KEY_RUN_Count 递增（每 5ms 一次）
 *          - 当计数达到 15（约 75ms）时，关闭按键显示
 *          - 计数限制在 15，防止溢出
 * @retval 无
 */
void KeyRun_Disp_Close(void)
{
    KEY_RUN_Count++;
    if (KEY_RUN_Count >= 15)
    {
        KEY_RUN_Count = 15;    /**< 限制最大计数，防止溢出 */
        KeyRun_Disp(0);        /**< 关闭按键显示指示 */
    }
}

/* ============================================================================
 * 主程序入口
 * ============================================================================ */

/**
 * @brief  主函数
 * @note   系统初始化流程：
 *          1. HAL 库初始化
 *          2. 系统时钟配置（72MHz）
 *          3. 延时函数初始化
 *          4. LED 初始化
 *          5. 按键驱动初始化
 *          6. 看门狗初始化
 *          7. RS485 通信初始化
 *          8. LCD 初始化
 *          9. Modbus 通信任务初始化
 *          10. 显示存储的 LOGO
 *          11. 定时器初始化（5ms 周期）
 *          12. 注册按键回调函数
 *          
 *          主循环处理：
 *          - 连接状态下的 LED 指示灯闪烁
 *          - RS485 Modbus 通信处理（包含按键上报）
 *          - 系统运行时间监控与自动复位保护
 *          
 *          定时器中断（5ms）处理：
 *          - 系统运行时间计数
 *          - LED 闪烁标志更新
 *          - 按键检测扫描
 *          - 看门狗喂狗
 *          - 背光关闭检测
 *          - Modbus 轮询计数
 *          - 按键显示自动关闭
 * @retval 无（永不返回）
 */
int main(void)
{
    /* ========== 系统初始化 ========== */
    HAL_Init();                              /**< 初始化 HAL 库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);     /**< 设置系统时钟，72MHz */
    delay_init(72);                          /**< 延时函数初始化（基于 72MHz 时钟） */
    
    /* ========== 外设初始化 ========== */
    LED_Init();                              /**< LED 灯初始化 */
    Key_Init();                              /**< 初始化按键驱动 */
    WDog_Init();                             /**< 看门狗初始化 */
    RS485_DMA_init();                        /**< RS485 初始化（DMA 方式） */
    LcdInit();                               /**< LCD 初始化 */
    
    /* ========== 通信与显示初始化 ========== */
    Process_Init();                          /**< Modbus 通信任务初始化 */
    NL_LOGO_Printf();                        /**< 显示存储的 LOGO（从 Flash 读取） */
    
    /* ========== 定时器与回调注册 ========== */
    gtim_timx_int_init(50-1, 7200-1);      /**< 定时器初始化：5ms 周期（50×0.1ms，7200 分频） */
    Key_RegisterCallback(Key_ProcessCallback); /**< 注册按键回调函数 */
    
    /* ========== 主循环 ========== */
    while (1)
    {
        /* LED 指示灯闪烁控制（仅在已连接状态下闪烁） */
        if (ConnectFlg == 1)
        {
            if (LED_ToggleFlag == 1)
            {
                LED_ToggleFlag = 0;          /**< 清除闪烁标志 */
                LED_Toggle(LED_RUN);         /**< 翻转运行指示灯 */
            }
        }
        
        /* RS485 Modbus 通信处理（包含按键上报） */
        ConnectFlg = RS485_Process(keyStatus, ConnectFlg);
        keyStatus = KEY_NONE;                /**< 清除按键状态（已处理） */
        
        /* 系统运行时间监控与自动复位保护 */
        if (sysRunTime > 1000000)            /**< 约 5000 秒（1000000 × 5ms） */
        {
            HAL_NVIC_SystemReset();          /**< 系统立即复位（防止长时间运行异常） */
            sysRunTime = 0;
        }
    }
}

/* ============================================================================
 * 中断服务函数
 * ============================================================================ */

/**
 * @brief  定时器中断服务函数（5ms 周期）
 * @note   在定时器溢出中断中执行以下任务：
 *          1. 系统运行时间计数（sysRunTime++）
 *          2. LED 闪烁标志更新（每 200 次中断，即 1 秒）
 *          3. 按键检测扫描（Button_Ticks）
 *          4. 看门狗喂狗（Clear_Watchdog）
 *          5. 背光关闭检测（BackLight_Close）
 *          6. Modbus 轮询计数（Process_Count）
 *          7. 按键显示自动关闭（KeyRun_Disp_Close）
 *          
 *          定时器配置：5ms 周期
 *          中断标志：TIM_FLAG_UPDATE（定时器溢出标志）
 * @retval 无
 */
void GTIM_TIMX_INT_IRQHandler(void)
{
    /* 判断定时器溢出中断标志位 */
    if (__HAL_TIM_GET_FLAG(&g_timx_handle, TIM_FLAG_UPDATE) != RESET)
    {
        sysRunTime++;                        /**< 系统运行时间计数递增 */
        
        /* LED 闪烁标志更新：每 200 次中断（1 秒）翻转一次 */
        if (sysRunTime % (LED_TOGGLE_TIME / 5) == 0)
        {
            LED_ToggleFlag = 1;              /**< 设置 LED 闪烁标志 */
        }
        
        Button_Ticks();                      /**< 按键检测扫描（MultiButton 库） */
        Clear_Watchdog();                    /**< 看门狗喂狗 */
        BackLight_Close();                   /**< 背光关闭检测 */
        Process_Count();                     /**< Modbus 通信轮询计数 */
        KeyRun_Disp_Close();                 /**< LCD 屏幕按键指示自动关闭处理 */
        
        __HAL_TIM_CLEAR_IT(&g_timx_handle, TIM_IT_UPDATE);  /**< 清除定时器溢出中断标志 */
    }
}
