/*
 * @Author: mypx
 * @Description: ADS8866采集-3线模式(TIM3中断驱动)
 */
#include "bsp_collect.h"
#include "bsp_misc.h"
#include "et_log.h"
#include "main.h"
#include "spi.h"
#include "tim.h"
#include <rtthread.h>
#include <stdlib.h>

static uint16_t         *g_buffer       = NULL;
static uint16_t          g_buf_size     = 0;
static uint16_t          g_target_count = 0; // 目标采集数
static volatile uint16_t g_count        = 0; // 已采集数
static dma_full_cb_t     g_complete_cb  = NULL;

// 3线模式: DIN保持高, CONVST控制转换+片选
#define ADS8866_DIN_HIGH() GPIOB->BSRR = (1u << 15)
#define PB15_AS_GPIO()     GPIOB->CRH = (GPIOB->CRH & ~(0xFu << 28)) | (0x3u << 28)

// 延时n个时钟周期（每个周期≈13.89ns）
static inline void ns_delay(uint32_t cycles)
{
    // 关闭编译器优化，确保NOP不被删除
    __asm volatile("1: SUBS %0, %0, #1\n" // 计数器减1
                   "   BNE 1b"            // 若未到0则循环
                   : "=r"(cycles)         // 输出操作数
                   : "0"(cycles)          // 输入操作数
    );
}

void delay_100ns(void)
{
    ns_delay(7);
}

// 单次读取(在中断里调用,要快速)
static inline uint16_t ads8866_read_once(void)
{
    uint16_t rx = 0;
    // ADS8866转换时间约3µs, 等待转换完成
    // 72MHz系统时钟, 1个NOP约14ns, 300个NOP约4.2µs
    for (volatile int i = 0; i < 6; i++)
        delay_100ns();

    // CONVST回到高电平, 数据就绪, 直接SPI读取
    HAL_SPI_Receive(&ADS8866_SPI, (uint8_t *)&rx, 1, 10);
    return rx;
}

int bsp_light_data_sampling_init(uint16_t *adc_buf, uint16_t length, dma_full_cb_t cb)
{
    g_buffer       = adc_buf;
    g_buf_size     = length;
    g_complete_cb  = cb;
    g_count        = 0;
    g_target_count = 0;

    // 初始化TIM3(产生CONVST), SPI2(读取数据)
    MX_TIM3_Init();
    MX_SPI2_Init();
    __HAL_SPI_ENABLE(&ADS8866_SPI);

    // PB15(DIN)配置为GPIO并保持高电平
    PB15_AS_GPIO();
    ADS8866_DIN_HIGH();

    ET_INFO("bsp_collect: init done, buf_size=%u", length);
    return 0;
}

// // Shell命令: 启动采集指定数量
// int cstart(int argc, char **argv)
// {
//     if (argc < 2)
//     {
//         rt_kprintf("Usage: cstart <count>\r\n");
//         return -1;
//     }

//     int count = atoi(argv[1]);
//     if (count <= 0 || count > g_buf_size)
//     {
//         rt_kprintf("cstart: invalid count (1~%u)\r\n", g_buf_size);
//         return -2;
//     }

//     if (!g_buffer)
//     {
//         rt_kprintf("cstart: buffer not init\r\n");
//         return -3;
//     }

//     // 设置目标数量并启动
//     g_count        = 0;
//     g_target_count = count;
//     bsp_system_led_on();

//     rt_kprintf("cstart: collecting %d samples...\r\n", count);

//     // 启动TIM3 PWM + 中断
//     HAL_TIM_PWM_Start(&COLLECT_TIM, TIM_CHANNEL_3);
//     HAL_TIM_Base_Start_IT(&COLLECT_TIM);

//     rt_kprintf("cstart: started (non-blocking)\r\n");
//     return 0;
// }

// int cprint(int argc, char **argv)
// {
//     uint16_t n = 32;
//     if (argc >= 2)
//         n = (uint16_t)atoi(argv[1]);
//     if (!g_buffer || g_count == 0)
//     {
//         rt_kprintf("cprint: no data\r\n");
//         return -1;
//     }
//     if (n > g_count)
//         n = g_count;
//     uint16_t minv = 0xFFFF, maxv = 0;
//     uint32_t sum = 0;
//     for (uint16_t i = 0; i < g_count; i++)
//     {
//         uint16_t v = g_buffer[i];
//         if (v < minv)
//             minv = v;
//         if (v > maxv)
//             maxv = v;
//         sum += v;
//     }
//     rt_kprintf("cprint: N=%u min=%u max=%u avg=%lu\r\n", g_count, minv, maxv, sum / g_count);
//     rt_kprintf("first %u (dec / hex):\r\n", n);
//     for (uint16_t i = 0; i < n; i++)
//     {
//         if (i % 8 == 0)
//             rt_kprintf("\r\n[%04u] ", i);
//         rt_kprintf("%5u/0x%04X ", g_buffer[i], g_buffer[i]);
//     }
//     rt_kprintf("\r\n");
//     return 0;
// }

// MSH_CMD_EXPORT_ALIAS(cstart, cstart, collect N samples)
// MSH_CMD_EXPORT_ALIAS(cprint, cprint, print data)

// 启动采集: 设置目标数量, 启动TIM3+中断
int bsp_light_data_sampling_start(void)
{
    if (!g_buffer || g_buf_size == 0)
    {
        ET_ERR("bsp_collect: buffer not initialized");
        return -1;
    }

    g_count        = 0;
    g_target_count = g_buf_size; // 采集满缓冲区
    bsp_system_led_on();

    // 启动TIM3 PWM(产生CONVST) + Update中断
    HAL_TIM_PWM_Start(&COLLECT_TIM, TIM_CHANNEL_3);
    HAL_TIM_Base_Start_IT(&COLLECT_TIM);

    //ET_INFO("bsp_collect: start, target=%u", g_target_count);
    return 0;
}

// 停止采集
int bsp_light_data_sampling_stop(void)
{
    HAL_TIM_Base_Stop_IT(&COLLECT_TIM);
    HAL_TIM_PWM_Stop(&COLLECT_TIM, TIM_CHANNEL_3);
    bsp_system_led_off();

    //ET_INFO("bsp_collect: stopped, collected=%u/%u", g_count, g_target_count);
    return 0;
}

uint16_t light_raw_map_u16(uint16_t val)
{
    /* Avoid integer truncation: do multiply before divide using 32-bit intermediate.
     * Map 0..65535 -> 0..4095. Use rounding by adding half-divisor. */
    uint32_t tmp = (uint32_t)val * 4095u;
    return (uint16_t)(tmp / 65535u + 0.5f);
}

float light_raw_map_f32(uint16_t val)
{
    return (float)(val / 65535.0f * 4095.0f);
}

// TIM3中断回调: 每次CONVST触发后采集一个点
void sampling_tim_elapsed_callback(void)
{
    // 未启动或已完成
    if (g_target_count == 0 || g_count >= g_target_count)
        return;

    // 读取一个点
    if (g_buffer && g_count < g_buf_size)
    {
        /* drive LED pin high at the start of ISR and low at the end
     * so each interrupt produces one pulse. This makes the pulse
     * frequency equal to the timer update frequency (no 2x toggle
     * ambiguity). */
        bsp_system_led_on();
        g_buffer[g_count] = light_raw_map_u16(ads8866_read_once());
        g_count++;
        bsp_system_led_off();

        // 达到目标数量, 停止并回调
        if (g_count >= g_target_count)
        {
            HAL_TIM_Base_Stop_IT(&COLLECT_TIM);
            HAL_TIM_PWM_Stop(&COLLECT_TIM, TIM_CHANNEL_3);
            bsp_system_led_off();

            //ET_INFO("bsp_collect: complete, N=%u", g_count);

            // 调用完成回调
            if (g_complete_cb)
                g_complete_cb();

            g_target_count = 0; // 标记完成
        }
    }
}
