/*
 * 模块名称：TPAFE5160 16�?通道同步采样ADC驱动
 * 模块功能：提�?TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接�? * 适用平台：STM32F407ZGT6，并�?6位数据总线�?GPIOG[15:0]
 * 作者：王建�? * 创建日期�?026-07-17
 * 修改记录�? *     2026-07-17  王建�? 创建初始版本，参�?AD7606 并行驱动�?TPAFE5160 手册
 *     2026-07-17  王建�? 增加 EXTI 中断读取模式
 */

/* 头文件包含区 */
#include "tpafe5160.h"
#include "main.h"

/*
 * 调试输出配置
 */
#define DBG_TAG "[ADC]"
#include "dbg_log.h"

/* ======================== 私有宏定�?======================== */

/*
 * 并行读取时序延时 (168MHz 主频�? NOP �?5.95ns)
 *
 * TPAFE5160 并行时序要求 (VDRIVE > 2.7V)�? *   t10 (RD 低脉�?   �?22ns
 *   t11 (RD 高脉�?   �?10ns
 *   t14 (数据访问时间) �?21ns (�?RD 下降沿算�?
 *   t15 (数据保持时间) �?6ns  (�?RD 下降沿算�?
 *
 * GPIO 写操作本身约 1 �?AHB 周期 (~6ns)�? * 加上端口延迟 (~12-18ns)，实�?RD 引脚翻转滞后�?18-24ns�? * 因此 NOP 延时只需覆盖数据建立时间即可�? */
#define TPAFE5160_NOP_5()      __NOP(); __NOP(); __NOP(); __NOP(); __NOP()

/* RD 低脉宽延时：GPIO�?~6ns) + 5NOP(~30ns) > 22ns */
#define TPAFE5160_RD_LOW_DLY() do { TPAFE5160_RD_LOW();  TPAFE5160_NOP_5(); } while (0)

/* RD 高脉宽延时：GPIO�?~6ns) + 3NOP(~18ns) > 10ns */
#define TPAFE5160_RD_HIGH_DLY() do { TPAFE5160_RD_HIGH(); __NOP(); __NOP(); __NOP(); } while (0)

/* CONVST 脉冲延时：上升沿前需保证低电平，5NOP 覆盖 t5 �?20ns */
#define TPAFE5160_CONVST_PULSE() do { \
    TPAFE5160_CONVST_LOW(); \
    TPAFE5160_NOP_5(); \
    TPAFE5160_CONVST_HIGH(); \
    TPAFE5160_NOP_5(); \
} while (0)

/* ======================== 私有函数声明 ======================== */

static void tpafe5160_read_channels(uint8_t count, int16_t *buf);

/* ======================== 公共函数定义 ======================== */

/*
 * 函数功能：初始化 TPAFE5160（设置过采样、等待就绪）
 * 入口参数：无
 * 返回值：0 - 成功�?2 - BUSY 超时
 * 限定条件：CubeMX 已完�?GPIO 初始�? * 函数说明�?. 设置过采样为无过采样 (000)
 *           2. 确保 RD 为高、CONVST 为低
 *           3. 等待 BUSY 释放（转换空闲）
 */
int tpafe5160_init(void) {
    /* 设置默认过采样：无过采样 (OS[2:0] = 000) */
    tpafe5160_set_os(TPAFE5160_OS_NONE);

    /* 确保控制引脚处于空闲状�?*/
    TPAFE5160_RD_HIGH();
    TPAFE5160_CONVST_LOW();

    /* 等待 BUSY 释放，确保上电后无残留转�?*/
    int ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
    if (ret != TPAFE5160_OK) {
        DBG_ERROR("Init wait BUSY timeout");
    } else {
        DBG_INFO("Init OK");
    }
    return ret;
}

/*
 * 函数功能：设置过采样�? * 入口参数：os - 过采样率枚举�? tpafe5160_os_t
 * 返回值：�? * 限定条件：GPIO 已初始化
 * 函数说明：通过 OS[2:0] 引脚设置过采样率，在下一�?BUSY 下降沿锁存生�? */
void tpafe5160_set_os(tpafe5160_os_t os) {
    TPAFE5160_OS0(os & 0x01);       /* OS0 = bit0 */
    TPAFE5160_OS1((os >> 1) & 0x01); /* OS1 = bit1 */
    TPAFE5160_OS2((os >> 2) & 0x01); /* OS2 = bit2 */
}

/*
 * 函数功能：启动一次转换（CONVST 上升沿触发）
 * 入口参数：无
 * 返回值：�? * 限定条件：GPIO 已初始化
 * 函数说明：产�?CONVST 脉冲上升沿，启动全部8通道同步采样与转�? */
void tpafe5160_start_conv(void) {
    TPAFE5160_CONVST_PULSE();
}

/*

 * 函数功能：等待转换完�? * 入口参数：timeout_ms - 超时时间  uint32_t  > 0
 * 返回值：0 - 转换完成�?2 - 超时
 * 限定条件：已调用 tpafe5160_start_conv()
 * 函数说明：轮�?BUSY 引脚等待下降�? */
int tpafe5160_wait_busy(uint32_t timeout_ms) {
    uint32_t tick_start = HAL_GetTick();

    /* 等待 BUSY 释放（低电平表示空闲�?*/
    while (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) {
        if ((HAL_GetTick() - tick_start) >= timeout_ms) {
            return TPAFE5160_BUSY_TIMEOUT;
        }
    }

    return TPAFE5160_OK;
}

/*
 * 函数功能：查询当前是否正在转�? * 入口参数：无
 * 返回值：1 - 正在转换�? - 空闲
 * 限定条件：GPIO 已初始化
 * 函数说明：读�?BUSY 引脚电平
 */
uint8_t tpafe5160_is_busy(void) {
    return (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) ? 1 : 0;
}

/*
 * 函数功能：读取全�?通道转换结果
 * 入口参数：buf - 8个int16_t的输出缓冲区  int16_t*  不为 NULL
 * 返回值：0 - 成功�?2 - BUSY 超时
 * 限定条件：GPIO 已初始化
 * 函数说明�?. 启动转换并等�?BUSY 释放
 *           2. 连续8次拉低RD读取各通道数据
 *           3. 通过 FRSTDATA 验证第一通道
 */
int tpafe5160_read_all(int16_t *buf) {
    int ret = 0;

    /* 启动转换 */
    tpafe5160_start_conv();

    /* 等待转换完成 */
    ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
    if (ret != TPAFE5160_OK) {
        DBG_ERROR("read_all BUSY timeout");
        return ret;
    }

    /* 连续读取8个通道 */
    tpafe5160_read_channels(TPAFE5160_CH_NUM, buf);

    return TPAFE5160_OK;
}

/*
 * 函数功能：读取指定通道的转换结�? * 入口参数：channel - 通道�? uint8_t  0 - 7
 *           value   - 输出指针 int16_t*  不为 NULL
 * 返回值：0 - 成功�?1 - 通道号无效，-2 - BUSY 超时
 * 限定条件：GPIO 已初始化
 * 函数说明：启动转换并等待完成后，连续读取至指定通道
 */
int tpafe5160_read_channel(uint8_t channel, int16_t *value) {
    int ret = 0;
    int16_t buf[TPAFE5160_CH_NUM] = {0};

    if (channel >= TPAFE5160_CH_NUM || value == NULL) {
        return TPAFE5160_ERROR;
    }

    ret = tpafe5160_read_all(buf);
    if (ret != TPAFE5160_OK) {
        return ret;
    }

    *value = buf[channel];
    return TPAFE5160_OK;
}

/*
 * 函数功能：原始ADC值转电压�? * 入口参数：raw - ADC原始�? int16_t  有符号补�? * 返回值：电压�? float  单位 V
 * 限定条件：无
 * 函数说明：�?V量程�?LSB = 10V / 65536 �?152.59μV
 *           ±10V量程�?LSB = 20V / 65536 �?305.18μV
 *           硬件 RANGE 引脚�?GND，默�?±5V 量程
 */
float tpafe5160_to_voltage(int16_t raw) {
    /* RANGE �?GND �?±5V 量程，满量程 10V */
    return (float)raw * (10.0f / 65536.0f);
}

/*
 * 函数功能：直接读取并行数据总线（不启动转换�? * 入口参数：无
 * 返回值：16位原始数�? uint16_t
 * 限定条件：RD 为低�?CS �?RD 已拉�? * 函数说明：读�?GPIOG->IDR �?6位，对应 DB[15:0]
 */
uint16_t tpafe5160_read_bus(void) {
    return TPAFE5160_READ_BUS();
}

/* ======================== 私有函数定义 ======================== */

/*
 * 函数功能：通过 RD 脉冲连续读取多个通道数据
 * 入口参数：count - 要读取的通道�? uint8_t  1 - 8
 *           buf   - 输出缓冲�?      int16_t* 不为 NULL
 * 返回值：�? * 限定条件：转换已完成（BUSY 为低），RD 初始为高
 * 函数说明：每�?RD 下降沿输出一个通道数据，按通道1~8顺序输出
 *           DB[15:0] 直接�?GPIOG[15:0]，通过 IDR 寄存器一次读�? *
 * 时序关键�?(VDRIVE > 2.7V, 168MHz 主频)�? *   GPIO 写操�?~6ns + 端口延迟 ~18ns �?RD 引脚实际翻转�?24ns �? *   t14 数据建立 �?21ns �?数据�?RD 下降沿后 21ns 内有�? *   5 �?NOP (~30ns) 覆盖建立时间
 */
static void tpafe5160_read_channels(uint8_t count, int16_t *buf) {
    uint8_t i;

    for (i = 0; i < count; i++) {
        /* RD 下降沿：ADC 输出当前通道数据�?DB[15:0] */
        TPAFE5160_RD_LOW_DLY();

        /* 读取16位并行数�?*/
        buf[i] = (int16_t)TPAFE5160_READ_BUS();

        /* RD 上升沿：准备下一通道 */
        TPAFE5160_RD_HIGH_DLY();
    }
}

/* ======================== 中断模式实现 ======================== */

/* 双缓冲区：ISR �?s_buf_b，主循环�?s_buf_a */
static int16_t s_buf_a[TPAFE5160_CH_NUM];
static int16_t s_buf_b[TPAFE5160_CH_NUM];
static volatile uint8_t s_ready = 0;
static volatile uint8_t s_buf_sel = 0;   /* 0 = �?B / �?A, 1 = �?A / �?B */

/*
 * 函数功能：使�?BUSY EXTI 中断（运行时重使能用�? * 入口参数：无
 * 返回值：�? * 限定条件：CubeMX 已完�?GPIO �?NVIC 配置
 * 函数说明：正常启动流程无需调用，仅�?irq_disable() 后需要重新使能时使用
 */
void tpafe5160_irq_enable(void) {
    HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}

/*
 * 函数功能：关�?BUSY EXTI 中断
 * 入口参数：无
 * 返回值：�? * 限定条件：已调用 tpafe5160_irq_enable()
 * 函数说明：仅禁用 NVIC 中断，GPIO 配置保持 CubeMX 设定
 */
void tpafe5160_irq_disable(void) {
    HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
}

/*
 * 函数功能：启动转换（中断模式�? * 入口参数：无
 * 返回值：�? * 限定条件：已调用 tpafe5160_irq_enable()
 * 函数说明：产�?CONVST 脉冲，转换完成后�?EXTI 中断自动读取 8 通道数据
 */
void tpafe5160_start_conv_irq(void) {
    s_ready = 0;
    TPAFE5160_CONVST_PULSE();
}

/*
 * 函数功能：检查是否有新的转换数据
 * 入口参数：无
 * 返回值：1 - 数据就绪�? - 无新数据
 * 限定条件：中断模式已启用
 * 函数说明：在 EXTI 回调中置位，主循环读取后需调用 tpafe5160_clear_ready() 清除
 */
uint8_t tpafe5160_data_ready(void) {
    return s_ready;
}

/*
 * 函数功能：清除数据就绪标�? * 入口参数：无
 * 返回值：�? * 限定条件：中断模式已启用
 * 函数说明：主循环处理完数据后调用
 */
void tpafe5160_clear_ready(void) {
    s_ready = 0;
}

/*
 * 函数功能：获取数据缓冲区指针
 * 入口参数：无
 * 返回值：int16_t[8] 数据缓冲区的 const 指针
 * 限定条件：tpafe5160_data_ready() 返回 1 时调�? * 函数说明：双缓冲切换，ISR 写另一个缓冲区，主循环安全读取当前缓冲�? */
const int16_t* tpafe5160_get_buf(void) {
    return (s_buf_sel == 0) ? s_buf_a : s_buf_b;
}

/*
 * 函数功能：BUSY 下降�?EXTI 处理（由 HAL_GPIO_EXTI_Callback 调用�? * 入口参数：GPIO_Pin - 触发中断的引脚号
 * 返回值：�? * 限定条件：BUSY EXTI 已使�? * 函数说明：转换完成后自动读取 8 通道数据到缓冲区，耗时�?0.5µs (168MHz)
 */
void tpafe5160_exti_handler(uint16_t GPIO_Pin) {
    if (GPIO_Pin != TP_BUSY_Pin) {
        return;
    }

    /* 双缓冲切换：ISR 写与主循环读不同的缓冲区 */
    int16_t *p_wr = (s_buf_sel == 0) ? s_buf_b : s_buf_a;

    /* 连续读取8个通道，约 0.5µs @ 168MHz */
    uint8_t i;
    for (i = 0; i < TPAFE5160_CH_NUM; i++) {
        TPAFE5160_RD_LOW_DLY();
        p_wr[i] = (int16_t)TPAFE5160_READ_BUS();
        TPAFE5160_RD_HIGH_DLY();
    }

    /* 切换缓冲区并标记就绪 */
    s_buf_sel ^= 1;
    s_ready = 1;
}
