/**
 * @file pwm_capture.c
 * @brief PWM 输入捕获实现（GPIO 外部中断 + 软件计时）
 *
 * 方案说明：
 *   每路 PWM 输入使用 GPIO 外部中断（双边沿触发），
 *   在上升沿记录起始时间，在下降沿计算高电平宽度，
 *   在第二个上升沿计算周期，求占空比后映射到 [0, 255]。
 *
 * 时间戳来源：
 *   SysTick 以 1MHz（1us 精度）运行，用全局计数器 g_us_tick 提供时间戳。
 *   若 SysTick 已被 HAL 占用，可改用 LPTIM 或其他基本定时器。
 */

#include "pwm_capture.h"
#include "hc32f003_config.h"

/* =========================================================
 * 全局捕获值
 * ========================================================= */
uint8_t g_cap_w = 0;
uint8_t g_cap_c = 0;
uint8_t g_cap_r = 0;
uint8_t g_cap_g = 0;
uint8_t g_cap_b = 0;

/* =========================================================
 * 内部状态：每路捕获通道
 * ========================================================= */
typedef struct {
    volatile uint32_t rise_ts;      /* 上升沿时间戳（us） */
    volatile uint32_t fall_ts;      /* 下降沿时间戳（us） */
    volatile uint32_t period_us;    /* 周期（us） */
    volatile uint32_t high_us;      /* 高电平时间（us） */
    volatile uint8_t  valid;        /* 数据有效标志 */
    volatile uint8_t  last_level;   /* 上一次边沿状态 */
} CaptureChannel_t;

#define CAP_CH_COUNT 5
static CaptureChannel_t s_cap[CAP_CH_COUNT]; /* 0=W, 1=C, 2=R, 3=G, 4=B */

/* =========================================================
 * 全局微秒计数器（由 SysTick ISR 累加）
 * ========================================================= */
volatile uint32_t g_us_tick = 0;

/* =========================================================
 * PwmCapture_Init：初始化捕获模块
 * ========================================================= */
void PwmCapture_Init(void)
{
    /*
     * DDL 调用说明：
     *
     * 1. 配置 SysTick 为 1us 节拍：
     *    SysTick_Config(SystemCoreClock / 1000000)
     *    — SystemCoreClock = 24000000（24MHz RC）
     *    — 每 24 个 CPU 周期触发一次 SysTick，即 1us
     *
     * 2. 配置 5 路 GPIO 为输入：
     *    stc_gpio_cfg_t gpio_cfg;
     *    gpio_cfg.enDir       = GpioDirIn;
     *    gpio_cfg.enDrv       = GpioDrvL;
     *    gpio_cfg.enPu        = GpioPuEnable;   // 内部上拉
     *    gpio_cfg.enPd        = GpioPdDisable;
     *    Gpio_Init(GpioPort0, GpioPin1, &gpio_cfg);  // P01 IN_W
     *    Gpio_Init(GpioPort0, GpioPin2, &gpio_cfg);  // P02 IN_C
     *    Gpio_Init(GpioPort0, GpioPin3, &gpio_cfg);  // P03 IN_R
     *    Gpio_Init(GpioPort1, GpioPin4, &gpio_cfg);  // P14 IN_G
     *    Gpio_Init(GpioPort1, GpioPin5, &gpio_cfg);  // P15 IN_B
     *
     * 3. 配置外部中断（双边沿触发）：
     *    stc_exti_cfg_t exti_cfg;
     *    exti_cfg.enSrc   = ExtiSrcGpio;
     *    exti_cfg.enLevel = ExtiLevelBoth;     // 双边沿
     *    exti_cfg.enFlt   = ExtiFilterEnable;  // 数字滤波（去抖）
     *    Exti_Init(ExtiLine0, &exti_cfg);      // P01 → 外部中断 Line0
     *    ... （5 路分别配置）
     *
     * 4. 使能 NVIC：
     *    NVIC_SetPriority(EXTI0_1_IRQn, 0)
     *    NVIC_EnableIRQ(EXTI0_1_IRQn)
     *    ... （根据 HC32F003 中断向量表配置）
     */

    /* 清零捕获状态 */
    for (int i = 0; i < CAP_CH_COUNT; i++) {
        s_cap[i].rise_ts   = 0;
        s_cap[i].fall_ts   = 0;
        s_cap[i].period_us = 0;
        s_cap[i].high_us   = 0;
        s_cap[i].valid     = 0;
        s_cap[i].last_level = 0;
    }

    /* 用户在此处插入 DDL 初始化代码 */
    (void)0;
}

/* =========================================================
 * PwmCapture_EdgeIsr：边沿中断处理（在 GPIO EXTI ISR 中调用）
 * ========================================================= */
void PwmCapture_EdgeIsr(uint8_t ch, uint8_t level, uint32_t timestamp_us)
{
    if (ch >= CAP_CH_COUNT) return;

    CaptureChannel_t *p = &s_cap[ch];

    if (level == 1) {
        /* 上升沿：计算周期（与上一个上升沿的时间差） */
        if (p->last_level == 0 && p->rise_ts != 0) {
            p->period_us = timestamp_us - p->rise_ts;
        }
        p->rise_ts    = timestamp_us;
        p->last_level = 1;
    } else {
        /* 下降沿：计算高电平时间 */
        if (p->last_level == 1) {
            p->high_us    = timestamp_us - p->rise_ts;
            p->last_level = 0;
            /* 高电平时间有效后，置 valid */
            if (p->period_us > 0) {
                p->valid = 1;
            }
        }
    }
}

/* =========================================================
 * PwmCapture_Update：主循环调用，将捕获时间转换为 0-255 占空比
 * ========================================================= */
void PwmCapture_Update(void)
{
    /* 占空比 = high_us / period_us，映射到 [0, 255] */
    uint8_t *results[CAP_CH_COUNT] = {
        &g_cap_w, &g_cap_c, &g_cap_r, &g_cap_g, &g_cap_b
    };

    for (int i = 0; i < CAP_CH_COUNT; i++) {
        CaptureChannel_t *p = &s_cap[i];

        if (!p->valid || p->period_us == 0) {
            /*
             * 无有效信号：
             * - 若引脚常低（无 PWM）→ 视为占空比 0
             * - 此处保持上次值，避免瞬时抖动
             */
            continue;
        }

        /* 防止高电平时间超过周期（硬件抖动保护） */
        uint32_t high = p->high_us;
        if (high > p->period_us) high = p->period_us;

        /*
         * duty_255 = round(high_us / period_us * 255)
         * 定点：duty_255 = (high_us * 255 + period_us/2) / period_us
         */
        uint32_t duty = (high * 255 + p->period_us / 2) / p->period_us;
        *results[i] = (uint8_t)CLAMP((int32_t)duty, 0, 255);

        /* 清除 valid 标志，等待下一个完整周期更新 */
        p->valid = 0;
    }
}

/* =========================================================
 * SysTick_Handler：微秒计数器累加（在 startup.s 中声明的弱函数覆盖处）
 * 注：若已有 SysTick_Handler，请将 g_us_tick++ 插入其中
 * ========================================================= */
void SysTick_Handler(void)
{
    g_us_tick++;

    /*
     * 说明：SysTick 配置为每 1us 触发一次（见 PwmCapture_Init）
     * g_us_tick 溢出约 4294 秒（uint32_t 上限），PWM 计算用差值，溢出安全
     */
}
