/**
 ******************************************************************************
 * @file    loop_uart_proto.h
 * @author  wangfq
 * @version V1.0
 * @date    2026-07-02
 * @brief   DLD960Loop 串口通信协议 (7F) — CH32V208 ↔ DLD960Loop MCU
 *
 *  帧格式: 7F | Addr | LEN | CMD | Data... | XOR | SUM
 *  UART:  USART2, 115200bps, PA2(Tx)/PA3(Rx)
 *
 *  该协议是通信MCU(CH32V208)与地感MCU(DLD960Loop/AT32F421)之间的接口。
 *  网络接口(TCP JSON/5960)通过本模块向地感MCU下发命令并获取数据。
 ******************************************************************************
 */
#ifndef __LOOP_UART_PROTO_H__
#define __LOOP_UART_PROTO_H__

#include <stdint.h>

/*===========================================================================
 * Protocol Constants
 *===========================================================================*/
#define LUP_MAGIC                   0x7F   // 配置/查询协议
#define LUP_MAGIC_OTA               0x9F   // OTA

#define LUP_ADDR_DEFAULT            0x00   // 默认地址

#define LUP_MAX_VALUE_LEN           64     // Value 字段最大长度
#define LUP_MAX_PKG_LEN             (1 + 3 + LUP_MAX_VALUE_LEN + 2)  // 70 bytes 最大帧

/*===========================================================================
 * Command Bytes (CMD)
 *===========================================================================*/
#define LUP_CMD_GET_VERSION         0x4A  // 获取设备版本号
#define LUP_CMD_RESET               0x6D  // 设备复位(无回复)
#define LUP_CMD_FACTORY_INIT        0x92  // 出厂初始化
#define LUP_CMD_SENSITIVITY         0x8A  // 读写线圈灵敏度列表
#define LUP_CMD_SET_PARAM           0x63  // 设置多路参数
#define LUP_CMD_GET_PARAM           0x64  // 读取多路参数
#define LUP_CMD_SENSOR_REPORT       0xC0  // 设备主动上报传感信息

/*===========================================================================
 * Sensor Types (0xC0 SensType)
 *===========================================================================*/
#define LUP_SENS_TYPE_MULTI_COIL    0x0C  // 多路线圈传感信息(四路)

/*===========================================================================
 * R/W byte for sensitivity (0x8A)
 *===========================================================================*/
#define LUP_SENS_RW_READ            0x00
#define LUP_SENS_RW_WRITE           0x01

/*===========================================================================
 * 线圈数
 *===========================================================================*/
#define LUP_COIL_COUNT              4

/*===========================================================================
 * Data Structures
 *===========================================================================*/

/* 线圈配置 (0x63 Set / 0x64 Get 中使用) */
typedef struct {
    uint8_t  sensitivity;       // 低4位灵敏度(0~9), 高4位频率等级[4]=高频,[5]=低频
    uint8_t  loop_delay;        // 延时时间 0~200, 0.1s/级
    uint8_t  output_mode;       // 低3位: 0=存在,1=进入脉冲,2=离开脉冲,3=方向
                                // 高5位: SafeMode 分钟数(0=关闭)
    uint8_t  exist_mode;        // 低4位: 0=永久, 非0=有限分钟
    uint8_t  direction_mode;    // 低3位: 0=触发, 1~6=方向模式
                                // 高4位: Function_Mode
} LUP_CoilParam;

/* 多路参数设置 (0x63) */
typedef struct {
    uint8_t      auto_mode;     // 0=不启用自动调频, 默认0
    uint8_t      amount;        // 线圈数量
    LUP_CoilParam params[LUP_COIL_COUNT];
} LUP_ParamSet;

/* 多路参数读取返回 (0x64 Response) */
typedef struct {
    uint8_t      auto_mode;
    uint8_t      amount;
    LUP_CoilParam params[LUP_COIL_COUNT];
    uint32_t     freq[LUP_COIL_COUNT][3];  // [ch][0]=freq1, [1]=freq2, [2]=freq3
} LUP_ParamGet;

/* 单路线圈传感数据单元 (0xC0/0x0C 中的每一路线圈) */
typedef struct {
    uint8_t  freq_level   : 2;  // 00=高频33nF, 01=中高43nF, 10=中低66nF, 11=低频76nF
    uint8_t  direction    : 1;  // 0=触发, 1=方向判别
    uint8_t  freq_type    : 1;  // 0=初始频率, 1=实时频率
    uint8_t  sensitivity  : 4;  // 灵敏度等级
    // 线圈评估条件
    uint8_t  condition    : 4;  // 环境状态评估值(0=正常, 值越大干扰越大)
    uint8_t  loop_state   : 1;  // 0=正常, 1=断开
    uint8_t  car_state    : 1;  // 0=无车, 1=有车
    uint8_t  misc_type    : 2;  // 0=时间量, 1=断开次数, 2=车流量
    uint32_t freq;              // 频率 (3 bytes, little-endian)
    uint16_t variation;         // 变化量 (2 bytes, little-endian)
    union {
        uint32_t passtime_ms5;  // 通过时间/车间距, 5ms单位 (misc_type=0)
        uint32_t cut_amount;    // 线圈断开次数 (misc_type=1)
        uint32_t flow_amount;   // 车流量数 (misc_type=2)
    } misc;
} LUP_CoilSensor;

/* 主动上报传感信息 (0xC0/0x0C) */
typedef struct {
    uint8_t        sens_type;       // 0x0C
    uint8_t        sub_amount;      // 分包数量(高4位), 0=无分包
    uint8_t        sub_sequence;    // 当前分包序号(低4位), 1-based
    uint8_t        coil_count;      // 线圈数 (解析出的)
    LUP_CoilSensor coils[LUP_COIL_COUNT];
} LUP_SensorReport;

/* 灵敏度读写 (0x8A) */
typedef struct {
    uint8_t  rw;                   // 0=Read, 1=Write
    uint8_t  amount;               // 灵敏度值数量
    uint16_t sens_in[LUP_COIL_COUNT];   // 触发灵敏度
    uint16_t sens_out[LUP_COIL_COUNT];  // 释放灵敏度
} LUP_Sensitivity;

/* 版本信息 (0x4A Response) */
typedef struct {
    uint8_t status;        // Status byte
    uint8_t hard_main;
    uint8_t hard_sub;
    uint8_t hard_ssub;
    uint8_t soft_main;
    uint8_t soft_sub;
    uint8_t soft_ssub;
    char    version_str[32];  // 格式化字符串
} LUP_VersionInfo;

/* 命令状态机 */
typedef enum {
    LUP_STATE_IDLE = 0,          // 空闲
    LUP_STATE_WAIT_RESPONSE,     // 等待响应
    LUP_STATE_RESPONSE_READY,    // 响应已就绪
    LUP_STATE_TIMEOUT            // 超时
} LUP_CmdState;

/* 挂起的命令跟踪 */
typedef struct {
    uint8_t      pending_cmd;    // 当前等待响应的命令字节
    uint32_t     send_tick;      // 发送时刻 (ms)
    uint32_t     timeout_ms;     // 超时时间
    LUP_CmdState state;
    // 响应数据缓冲区
    uint8_t  resp_buf[LUP_MAX_PKG_LEN];
    uint16_t resp_len;
} LUP_CmdTracker;

/*===========================================================================
 * Global State
 *===========================================================================*/
extern LUP_CmdTracker g_lup_cmd;

/*===========================================================================
 * Public API
 *===========================================================================*/

/* --- Checksum --- */
uint8_t lup_calc_xor(const uint8_t *data, uint16_t len);
uint8_t lup_calc_sum(const uint8_t *data, uint16_t len);
int     lup_verify_checksum(const uint8_t *pkg, uint16_t len);
void    lup_append_checksum(uint8_t *pkg);

/* --- Packet Builders (returns total packet length) --- */
uint16_t lup_build_get_version(uint8_t *buf);
uint16_t lup_build_reset(uint8_t *buf);
uint16_t lup_build_factory_init(uint8_t *buf);
uint16_t lup_build_sensitivity_read(uint8_t *buf);
uint16_t lup_build_sensitivity_write(uint8_t *buf, const LUP_Sensitivity *sens);
uint16_t lup_build_set_param(uint8_t *buf, const LUP_ParamSet *ps);
uint16_t lup_build_get_param(uint8_t *buf);

/* --- Packet Parsers (returns 0=success, <0=error) --- */
int lup_parse_version(const uint8_t *pkg, uint16_t len, LUP_VersionInfo *info);
int lup_parse_factory_init_resp(const uint8_t *pkg, uint16_t len, uint8_t *success);
int lup_parse_sensitivity_resp(const uint8_t *pkg, uint16_t len, LUP_Sensitivity *sens);
int lup_parse_param_get(const uint8_t *pkg, uint16_t len, LUP_ParamGet *pg);
int lup_parse_sensor_report(const uint8_t *pkg, uint16_t len, LUP_SensorReport *report);
int lup_parse_set_param_resp(const uint8_t *pkg, uint16_t len, uint8_t *success);

/* --- Command State Machine --- */
void lup_cmd_begin(uint8_t cmd, uint32_t timeout_ms);
void lup_cmd_done(void);
int  lup_cmd_check_timeout(void);
void lup_cmd_on_response(const uint8_t *pkg, uint16_t len);

/* --- High-level Commands (send + wait handled by state machine) --- */
void lup_send_get_version(void);
void lup_send_reset(void);
void lup_send_factory_init(void);
void lup_send_sensitivity_read(void);
void lup_send_set_param(const LUP_ParamSet *ps);
void lup_send_get_param(void);

/* --- Mid-packet ACK for 0xC0 multi-packet --- */
uint16_t lup_build_sensor_ack(uint8_t *buf, uint8_t sens_type,
                               uint8_t seq, uint8_t sub_amount);

/* --- UART Frame Parser (called from USART2 ISR context) --- */
typedef enum {
    LUP_FRAME_STATE_IDLE = 0,     // 等待 0x7F
    LUP_FRAME_STATE_HEADER,       // 接收 Header (Addr, LEN, CMD)
    LUP_FRAME_STATE_VALUE,        // 接收 Value
    LUP_FRAME_STATE_CHECK,        // 接收 Checksum
    LUP_FRAME_STATE_COMPLETE      // 帧完成
} LUP_FrameState;

typedef struct {
    LUP_FrameState state;
    uint8_t  buf[LUP_MAX_PKG_LEN];
    uint16_t idx;           // 当前写入位置
    uint16_t value_len;     // 期望的 Value 长度 (从 LEN 字段解析)
    uint16_t value_idx;     // 当前已接收的 Value 字节数
} LUP_FrameParser;

extern LUP_FrameParser g_lup_parser;

/* 喂一个字节给帧解析器，返回 1 表示帧接收完成 */
int lup_feed_byte(uint8_t byte);

/* 取完整帧的指针和数据长度 */
const uint8_t *lup_frame_data(void);
uint16_t       lup_frame_len(void);

/* 重置帧解析器 */
void lup_frame_reset(void);

/* --- Process a complete frame (call from main loop context) --- */
void lup_process_frame(const uint8_t *pkg, uint16_t len);

/* --- Sensor report callback (called when valid 0xC0 frame received) --- */
typedef void (*lup_sensor_cb_t)(const uint8_t *pkg, uint16_t len);
void lup_set_sensor_callback(lup_sensor_cb_t cb);

#endif /* __LOOP_UART_PROTO_H__ */
