/**
 ******************************************************************************
 * @file    loop_uart_proto.c
 * @author  wangfq
 * @version V1.0
 * @date    2026-07-02
 * @brief   DLD960Loop 串口通信协议实现
 *          - 校验计算 (XOR + SUM)
 *          - 命令组包 / 响应解析
 *          - 帧接收状态机 (替代 timeout heuristic)
 *          - 命令发送 + 超时跟踪
 ******************************************************************************
 */
#include "CONFIG.h"
#include "loop_uart_proto.h"
#include "cmcng.h"
#include <string.h>

/*===========================================================================
 * Global State
 *===========================================================================*/
LUP_CmdTracker g_lup_cmd = {0, 0, 0, LUP_STATE_IDLE, {0}, 0};

/* --- Frame Parser --- */
LUP_FrameParser g_lup_parser = {
    .state     = LUP_FRAME_STATE_IDLE,
    .idx       = 0,
    .value_len = 0,
    .value_idx = 0
};

/*===========================================================================
 * Checksum
 *===========================================================================*/

/*
 * XOR 校验: 从 Addr 字节开始，到命令数据的最后一个字节结束
 */
uint8_t lup_calc_xor(const uint8_t *data, uint16_t len)
{
    uint8_t x = 0;
    uint16_t i;
    for (i = 0; i < len; i++) {
        x ^= data[i];
    }
    return x;
}

/*
 * SUM 校验: 从 Addr 字节开始，到命令数据的最后一个字节结束
 */
uint8_t lup_calc_sum(const uint8_t *data, uint16_t len)
{
    uint8_t s = 0;
    uint16_t i;
    for (i = 0; i < len; i++) {
        s += data[i];
    }
    return s;
}

/*
 * 校验整包: pkg = [7F] [Addr] [LEN] [CMD] [Data...] [XOR] [SUM]
 * Checksum covers: Addr + LEN_field + Value (=CMD + Data) = 2 + LEN bytes
 *                starting at pkg[1]
 */
int lup_verify_checksum(const uint8_t *pkg, uint16_t len)
{
    if (len < 6) return -1;  // 最小: 7F + 3 header + 2 checksum = 6

    uint8_t pkg_len = pkg[2];  // LEN field
    uint16_t check_len = 2 + pkg_len;  // Addr(1)+LEN_field(1)+Value(LEN)

    if (len < check_len + 3) return -4;  // Not enough data: Magic(1) + covered + Check(2)

    uint8_t expect_xor = lup_calc_xor(pkg + 1, check_len);
    uint8_t expect_sum = lup_calc_sum(pkg + 1, check_len);

    uint8_t got_xor = pkg[1 + check_len];
    uint8_t got_sum = pkg[2 + check_len];

    if (expect_xor != got_xor) return -2;
    if (expect_sum != got_sum) return -3;
    return 0;
}

/*
 * 为已填充好 Data 的 buf 追加 checksum。
 * buf 格式: [7F] [Addr] [LEN] [CMD] [Data...]
 * Checksum 覆盖: Addr(1) + LEN(1) + Value(LEN) = 2 + LEN bytes
 * Output: [7F][Addr][LEN][CMD][Data...][XOR][SUM]
 */
void lup_append_checksum(uint8_t *pkg)
{
    // Frame: [Magic][Addr][LEN][Value(LEN bytes)][XOR][SUM]
    // Total = 1 + 1 + 1 + LEN + 2 = 5 + LEN
    //   (Addr + LEN_field are NOT inside Value; CMD is the 1st byte of Value)
    uint8_t  total_len = 5 + pkg[2];              // Magic(1)+Addr(1)+LEN(1)+Value(LEN)+Check(2)
    uint16_t check_len = 2 + pkg[2];              // Addr(1)+LEN_field(1)+Value(LEN)

    pkg[total_len - 2] = lup_calc_xor(pkg + 1, check_len);
    pkg[total_len - 1] = lup_calc_sum(pkg + 1, check_len);
}

/*===========================================================================
 * Packet Builders
 *===========================================================================*/

/*
 * 0x4A — 获取设备版本号
 *   Req: 7F 00 01 4A 4B 4B
 */
uint16_t lup_build_get_version(uint8_t *buf)
{
    buf[0] = LUP_MAGIC;           // 7F
    buf[1] = LUP_ADDR_DEFAULT;    // 0x00
    buf[2] = 0x01;                // LEN = 1 (CMD byte)
    buf[3] = LUP_CMD_GET_VERSION; // 0x4A
    lup_append_checksum(buf);
    return 6;  // Magic(1) + Header(3) + Check(2)
}

/*
 * 0x6D — 设备复位 (无回复)
 *   Req: 7F 00 01 6D 6C 6E
 */
uint16_t lup_build_reset(uint8_t *buf)
{
    buf[0] = LUP_MAGIC;
    buf[1] = LUP_ADDR_DEFAULT;
    buf[2] = 0x01;
    buf[3] = LUP_CMD_RESET;
    lup_append_checksum(buf);
    return 6;
}

/*
 * 0x92 — 出厂初始化
 *   Req: 7F 00 01 92 93 93
 */
uint16_t lup_build_factory_init(uint8_t *buf)
{
    buf[0] = LUP_MAGIC;
    buf[1] = LUP_ADDR_DEFAULT;
    buf[2] = 0x01;
    buf[3] = LUP_CMD_FACTORY_INIT;
    lup_append_checksum(buf);
    return 6;
}

/*
 * 0x8A — 读灵敏度列表
 *   Req: 7F 00 03 8A 00 00 xx xx
 *   LEN=3: CMD(1) + R/W(1) + Amount(1)
 */
uint16_t lup_build_sensitivity_read(uint8_t *buf)
{
    buf[0] = LUP_MAGIC;
    buf[1] = LUP_ADDR_DEFAULT;
    buf[2] = 0x03;                    // LEN = 3 (CMD + R/W + Amount)
    buf[3] = LUP_CMD_SENSITIVITY;     // 0x8A
    buf[4] = LUP_SENS_RW_READ;        // 0x00
    buf[5] = 0x00;                    // Amount (ignored for read)
    lup_append_checksum(buf);
    return 5 + buf[2];               // = 8
}

/*
 * 0x8A — 写灵敏度列表
 */
uint16_t lup_build_sensitivity_write(uint8_t *buf, const LUP_Sensitivity *sens)
{
    uint8_t i;
    uint16_t idx = 0;

    buf[idx++] = LUP_MAGIC;
    buf[idx++] = LUP_ADDR_DEFAULT;
    // LEN = CMD(1) + R/W(1) + Amount(1) + Amount*(SensIn(2)+SensOut(2))
    //     = 3 + sens->amount * 4
    uint8_t val_len = 3 + sens->amount * 4;
    buf[idx++] = val_len;
    buf[idx++] = LUP_CMD_SENSITIVITY;

    buf[idx++] = sens->rw;         // 0x01 (Write)
    buf[idx++] = sens->amount;

    for (i = 0; i < sens->amount; i++) {
        buf[idx++] = (uint8_t)(sens->sens_in[i] & 0xFF);
        buf[idx++] = (uint8_t)((sens->sens_in[i] >> 8) & 0xFF);
        buf[idx++] = (uint8_t)(sens->sens_out[i] & 0xFF);
        buf[idx++] = (uint8_t)((sens->sens_out[i] >> 8) & 0xFF);
    }
    lup_append_checksum(buf);
    return 5 + val_len;  // Magic(1)+Addr(1)+LEN(1)+Value(val_len)+Check(2)
}

/*
 * 0x63 — 设置多路参数
 *   Value: AutoMode(1) + Amount(1) + Amount * Param[5]
 *   LEN = CMD(1) + AutoMode(1) + Amount(1) + Amount*5 = 3 + 5*Amount
 */
uint16_t lup_build_set_param(uint8_t *buf, const LUP_ParamSet *ps)
{
    uint8_t i;
    uint16_t idx = 0;

    buf[idx++] = LUP_MAGIC;
    buf[idx++] = LUP_ADDR_DEFAULT;
    uint8_t val_len = 3 + 5 * ps->amount;   // CMD + AutoMode + Amount + Amount*Param
    buf[idx++] = val_len;
    buf[idx++] = LUP_CMD_SET_PARAM;

    buf[idx++] = ps->auto_mode;
    buf[idx++] = ps->amount;

    for (i = 0; i < ps->amount; i++) {
        buf[idx++] = ps->params[i].sensitivity;
        buf[idx++] = ps->params[i].loop_delay;
        buf[idx++] = ps->params[i].output_mode;
        buf[idx++] = ps->params[i].exist_mode;
        buf[idx++] = ps->params[i].direction_mode;
    }
    lup_append_checksum(buf);
    return 5 + val_len;  // Magic(1)+Addr(1)+LEN(1)+Value(val_len)+Check(2)
}

/*
 * 0x64 — 读取多路参数
 *   Req: 7F 00 01 64 ...
 */
uint16_t lup_build_get_param(uint8_t *buf)
{
    buf[0] = LUP_MAGIC;
    buf[1] = LUP_ADDR_DEFAULT;
    buf[2] = 0x01;              // LEN = 1
    buf[3] = LUP_CMD_GET_PARAM; // 0x64
    lup_append_checksum(buf);
    return 6;
}

/*
 * 0xC0 mid-packet ACK
 *   Req: 7F | 00 | 07 | C0 | SensType | Seq | SubAmount | XOR | SUM
 */
uint16_t lup_build_sensor_ack(uint8_t *buf, uint8_t sens_type,
                               uint8_t seq, uint8_t sub_amount)
{
    buf[0] = LUP_MAGIC;
    buf[1] = LUP_ADDR_DEFAULT;
    buf[2] = 0x07;               // LEN = 7 (CMD + SensType + Seq + SubAmount + 3 padding)
    buf[3] = LUP_CMD_SENSOR_REPORT;
    buf[4] = sens_type;
    buf[5] = seq;
    buf[6] = sub_amount;
    buf[7] = 0x00;               // padding
    buf[8] = 0x00;
    buf[9] = 0x00;
    lup_append_checksum(buf);
    return 5 + buf[2];           // = 12: Magic+Addr+LEN+Value(7)+Check(2)
}

/*===========================================================================
 * Packet Parsers
 *===========================================================================*/

/*
 * Parse 0x4A Response:
 *   Header: 00 08 4A (Addr, LEN=8, CMD)
 *   Value:  Status + Hard_Main + Hard_Sub + Hard_SSub + Soft_Main + Soft_Sub + Soft_SSub
 */
int lup_parse_version(const uint8_t *pkg, uint16_t len, LUP_VersionInfo *info)
{
    if (len < 10) return -1;       // 1+3+7+2 = 13 min

    // pkg layout: [7F][Addr=0][LEN=8][CMD=0x4A][Status...7bytes][XOR][SUM]
    if (pkg[0] != LUP_MAGIC || pkg[3] != LUP_CMD_GET_VERSION) return -2;
    if (pkg[2] < 7) return -3;    // LEN should be >= 7

    const uint8_t *val = pkg + 4;  // skip magic + header(3)
    info->status    = val[0];
    info->hard_main = val[1];
    info->hard_sub  = val[2];
    info->hard_ssub = val[3];
    info->soft_main = val[4];
    info->soft_sub  = val[5];
    info->soft_ssub = val[6];

    return 0;
}

/*
 * Parse 0x92 Response:
 *   Value: 00/01 (00=success)
 */
int lup_parse_factory_init_resp(const uint8_t *pkg, uint16_t len, uint8_t *success)
{
    if (len < 7) return -1;
    if (pkg[0] != LUP_MAGIC || pkg[3] != LUP_CMD_FACTORY_INIT) return -2;
    *success = (pkg[4] == 0x00) ? 1 : 0;
    return 0;
}

/*
 * Parse 0x8A Response:
 *   Value: Ret(1) + Amount(1) + Amount*(SensIn(2) + SensOut(2))
 *   Ret = 0x10 (Read return) | 0x11 (Write return)
 *
 *   eg: 7F 80 13 8A 10 04 A2 00 51 00 51 00 36 00 ...
 *       Ret=0x10=Read, Amount=4
 *       Lv0: SensIn=0x00A2, SensOut=0x0051
 */
int lup_parse_sensitivity_resp(const uint8_t *pkg, uint16_t len, LUP_Sensitivity *sens)
{
    uint8_t i;
    if (len < 8) return -1;   // min: 7F+Addr+LEN+CMD+Ret+Amount+XOR+SUM = 8
    if (pkg[0] != LUP_MAGIC || pkg[3] != LUP_CMD_SENSITIVITY) return -2;

    const uint8_t *val = pkg + 4;
    sens->rw     = val[0];          // 0x10 or 0x11
    sens->amount = val[1];

    if (sens->amount > LUP_COIL_COUNT) sens->amount = LUP_COIL_COUNT;

    for (i = 0; i < sens->amount; i++) {
        sens->sens_in[i]  = val[2 + i * 4] | ((uint16_t)val[3 + i * 4] << 8);
        sens->sens_out[i] = val[4 + i * 4] | ((uint16_t)val[5 + i * 4] << 8);
    }
    return 0;
}

/*
 * Parse 0x64 Response:
 *   Value: AutoMode(1) + Amount(1) + Amount * [Sensitivity, Loop_Delay, Output_Mode,
 *          Exist_Mode, Direction_Mode, freq1(2), freq2(2), freq3(2)]
 *   Each coil = 8 bytes
 */
int lup_parse_param_get(const uint8_t *pkg, uint16_t len, LUP_ParamGet *pg)
{
    uint8_t i;
    if (len < 6) return -1;
    if (pkg[0] != LUP_MAGIC || pkg[3] != LUP_CMD_GET_PARAM) return -2;

    const uint8_t *val = pkg + 4;
    pg->auto_mode = val[0];
    pg->amount    = val[1];

    if (pg->amount > LUP_COIL_COUNT) pg->amount = LUP_COIL_COUNT;

    for (i = 0; i < pg->amount; i++) {
        const uint8_t *c = val + 2 + i * 8;
        pg->params[i].sensitivity    = c[0];
        pg->params[i].loop_delay     = c[1];
        pg->params[i].output_mode    = c[2];
        pg->params[i].exist_mode     = c[3];
        pg->params[i].direction_mode = c[4];
        pg->freq[i][0] = c[5] | ((uint32_t)c[6] << 8);
        pg->freq[i][1] = c[7] | ((uint32_t)c[8] << 8);
        pg->freq[i][2] = c[9] | ((uint32_t)c[10] << 8);
    }

    return 0;
}

/*
 * Parse 0x63 Response (Set Param):
 *   Value: Status(1 byte, 0x00=success)
 */
int lup_parse_set_param_resp(const uint8_t *pkg, uint16_t len, uint8_t *success)
{
    if (len < 7) return -1;
    if (pkg[0] != LUP_MAGIC || pkg[3] != LUP_CMD_SET_PARAM) return -2;
    *success = (pkg[4] == 0x00) ? 1 : 0;
    return 0;
}

/*
 * Parse 0xC0/0x0C — 多路线圈传感信息
 *
 * 每路线圈数据单元 = 11 bytes:
 *   [0] 配置1:  freq_level(2) | Direction(1) | freq_type(1) | sens(4)
 *   [1] 评估条件: condition(4) | loop_state(1) | car_state(1) | misc_type(2)
 *   [2-4] 频率 (3 bytes, LE)
 *   [5-6] 变化量 (2 bytes, LE)
 *   [7-10] 杂项 (4 bytes)
 */
int lup_parse_sensor_report(const uint8_t *pkg, uint16_t len, LUP_SensorReport *report)
{
    uint8_t i;
    if (len < 9) return -1;  // 7F + 3 header + 2 sensType/SubPkgFlag + 2 checksum min
    if (pkg[0] != LUP_MAGIC || pkg[3] != LUP_CMD_SENSOR_REPORT) return -2;

    uint8_t sens_type = pkg[4];
    if (sens_type != LUP_SENS_TYPE_MULTI_COIL) return -3;

    uint8_t sub_pkg = pkg[5];
    report->sens_type    = sens_type;
    report->sub_amount    = (sub_pkg >> 4) & 0x0F;
    report->sub_sequence  = sub_pkg & 0x0F;

    // 计算线圈数: Value = sensType(1) + SubPkgFlag(1) + coil_count * 11
    uint16_t val_len = pkg[2];  // LEN field
    uint16_t data_offset = 6;   // 跳过 7F + Addr + LEN + CMD + SensType + SubPkgFlag
    uint16_t data_len = val_len - 2;  // 减去 SensType + SubPkgFlag

    uint8_t coil_count = data_len / 11;
    if (coil_count > LUP_COIL_COUNT) coil_count = LUP_COIL_COUNT;
    report->coil_count = coil_count;

    for (i = 0; i < coil_count; i++) {
        const uint8_t *c = pkg + data_offset + i * 11;

        LUP_CoilSensor *cs = &report->coils[i];
        cs->freq_level  = (c[0] >> 6) & 0x03;
        cs->direction   = (c[0] >> 5) & 0x01;
        cs->freq_type   = (c[0] >> 4) & 0x01;
        cs->sensitivity = c[0] & 0x0F;

        cs->condition   = (c[1] >> 4) & 0x0F;
        cs->loop_state  = (c[1] >> 3) & 0x01;
        cs->car_state   = (c[1] >> 2) & 0x01;
        cs->misc_type   = c[1] & 0x03;

        cs->freq       = c[2] | ((uint32_t)c[3] << 8) | ((uint32_t)c[4] << 16);
        cs->variation  = c[5] | ((uint16_t)c[6] << 8);
        cs->misc.passtime_ms5 = c[7] | ((uint32_t)c[8] << 8)
                                | ((uint32_t)c[9] << 16) | ((uint32_t)c[10] << 24);
    }

    return 0;
}

/*===========================================================================
 * Command State Machine
 *===========================================================================*/

void lup_cmd_begin(uint8_t cmd, uint32_t timeout_ms)
{
    g_lup_cmd.pending_cmd = cmd;
    g_lup_cmd.send_tick   = mstick();
    g_lup_cmd.timeout_ms  = timeout_ms;
    g_lup_cmd.state       = LUP_STATE_WAIT_RESPONSE;
    g_lup_cmd.resp_len    = 0;
    memset(g_lup_cmd.resp_buf, 0, sizeof(g_lup_cmd.resp_buf));
}

void lup_cmd_done(void)
{
    g_lup_cmd.pending_cmd = 0;
    g_lup_cmd.state       = LUP_STATE_IDLE;
    g_lup_cmd.resp_len    = 0;
}

int lup_cmd_check_timeout(void)
{
    if (g_lup_cmd.state != LUP_STATE_WAIT_RESPONSE) return 0;
    if (mstick() - g_lup_cmd.send_tick > g_lup_cmd.timeout_ms) {
        g_lup_cmd.state = LUP_STATE_TIMEOUT;
        PRINT("LUP: cmd 0x%02X timeout\n", g_lup_cmd.pending_cmd);
        return 1;
    }
    return 0;
}

/*
 * 收到响应时调用 — 如果当前有挂起命令且 CMD 匹配，则保存响应
 */
void lup_cmd_on_response(const uint8_t *pkg, uint16_t len)
{
    if (g_lup_cmd.state != LUP_STATE_WAIT_RESPONSE) return;
    if (len < 4) return;

    uint8_t resp_cmd = pkg[3];
    if (resp_cmd == g_lup_cmd.pending_cmd) {
        // 保存响应数据
        uint16_t copy_len = (len < sizeof(g_lup_cmd.resp_buf)) ? len : sizeof(g_lup_cmd.resp_buf);
        memcpy(g_lup_cmd.resp_buf, pkg, copy_len);
        g_lup_cmd.resp_len = copy_len;
        g_lup_cmd.state = LUP_STATE_RESPONSE_READY;
    }
}

/*===========================================================================
 * High-level Send Commands
 *===========================================================================*/

static void lup_debug_tx(const uint8_t *buf, uint16_t len)
{
    uint8_t i;
    PRINT("LUP Tx:");
    for (i = 0; i < len; i++) {
        PRINT(" %02X", buf[i]);
    }
    PRINT("\n");
}

void lup_send_get_version(void)
{
    uint8_t buf[LUP_MAX_PKG_LEN];
    uint16_t len = lup_build_get_version(buf);
    lup_debug_tx(buf, len);
    UART2_SendString(buf, len);
    lup_cmd_begin(LUP_CMD_GET_VERSION, 200);
}

void lup_send_reset(void)
{
    uint8_t buf[LUP_MAX_PKG_LEN];
    uint16_t len = lup_build_reset(buf);
    lup_debug_tx(buf, len);
    UART2_SendString(buf, len);
    // No response expected
}

void lup_send_factory_init(void)
{
    uint8_t buf[LUP_MAX_PKG_LEN];
    uint16_t len = lup_build_factory_init(buf);
    lup_debug_tx(buf, len);
    UART2_SendString(buf, len);
    lup_cmd_begin(LUP_CMD_FACTORY_INIT, 500);
}

void lup_send_sensitivity_read(void)
{
    uint8_t buf[LUP_MAX_PKG_LEN];
    uint16_t len = lup_build_sensitivity_read(buf);
    lup_debug_tx(buf, len);
    UART2_SendString(buf, len);
    lup_cmd_begin(LUP_CMD_SENSITIVITY, 200);
}

void lup_send_set_param(const LUP_ParamSet *ps)
{
    uint8_t buf[LUP_MAX_PKG_LEN];
    uint16_t len = lup_build_set_param(buf, ps);
    lup_debug_tx(buf, len);
    UART2_SendString(buf, len);
    lup_cmd_begin(LUP_CMD_SET_PARAM, 500);
}

void lup_send_get_param(void)
{
    uint8_t buf[LUP_MAX_PKG_LEN];
    uint16_t len = lup_build_get_param(buf);
    lup_debug_tx(buf, len);
    UART2_SendString(buf, len);
    lup_cmd_begin(LUP_CMD_GET_PARAM, 500);
}

/*===========================================================================
 * Frame Parser (called per-byte from USART2 ISR / timer context)
 *
 * 帧格式: [7F] [Addr] [LEN] [CMD] [Value: LEN bytes] [XOR] [SUM]
 * LEN = Value 字段的长度，包括 CMD byte
 * 所以: Value data bytes = LEN - 1 (减掉 CMD)
 *
 * 状态机:
 *   IDLE     → 找 0x7F → HEADER
 *   HEADER   → 收完 3 bytes Header → VALUE (若 LEN>1)
 *   VALUE    → 收完 data_bytes → CHECK
 *   CHECK    → 收完 2 bytes → COMPLETE
 *===========================================================================*/

void lup_frame_reset(void)
{
    g_lup_parser.state     = LUP_FRAME_STATE_IDLE;
    g_lup_parser.idx       = 0;
    g_lup_parser.value_len = 0;
    g_lup_parser.value_idx = 0;
    memset(g_lup_parser.buf, 0, sizeof(g_lup_parser.buf));
}

const uint8_t *lup_frame_data(void)
{
    return g_lup_parser.buf;
}

uint16_t lup_frame_len(void)
{
    return g_lup_parser.idx;
}

/*
 * 喂一个字节。返回 1 = 帧接收完成（在 buf 中）
 */
int lup_feed_byte(uint8_t byte)
{
    LUP_FrameParser *p = &g_lup_parser;

    switch (p->state) {
    case LUP_FRAME_STATE_IDLE:
        if (byte == LUP_MAGIC) {
            p->buf[0] = byte;
            p->idx = 1;
            p->state = LUP_FRAME_STATE_HEADER;
        }
        break;

    case LUP_FRAME_STATE_HEADER:
        p->buf[p->idx++] = byte;
        if (p->idx == 4) {
            // Header 收完: [7F][Addr][LEN][CMD]
            // Value data bytes = LEN - 1 (CMD byte 已计入 LEN)
            uint8_t  len_field = p->buf[2];
            uint16_t data_bytes;  // Value 中除 CMD 之外的 data 字节数
            if (len_field < 1) {
                data_bytes = 0;
            } else {
                data_bytes = len_field - 1;
            }

            if (data_bytes > LUP_MAX_VALUE_LEN) {
                // 非法长度，丢弃
                lup_frame_reset();
                break;
            }

            if (data_bytes > 0) {
                p->value_len  = data_bytes;
                p->value_idx  = 0;
                p->state      = LUP_FRAME_STATE_VALUE;
            } else {
                // 无 Data，直接等 Checksum
                p->value_len  = 0;
                p->value_idx  = 0;
                p->state      = LUP_FRAME_STATE_CHECK;
            }
        }
        break;

    case LUP_FRAME_STATE_VALUE:
        p->buf[p->idx++] = byte;
        p->value_idx++;
        if (p->value_idx >= p->value_len) {
            p->state = LUP_FRAME_STATE_CHECK;
        }
        break;

    case LUP_FRAME_STATE_CHECK:
        p->buf[p->idx++] = byte;
        if (p->idx >= p->value_len + 1 + 3 + 2) {  // Magic(1) + Header(3) + Value data + Check(2)
            p->state = LUP_FRAME_STATE_COMPLETE;
            return 1;
        }
        break;

    case LUP_FRAME_STATE_COMPLETE:
        // 不应该到达这里，调用方应在 COMPLETE 后 reset
        lup_frame_reset();
        break;
    }

    return 0;
}

/*===========================================================================
 * Sensor Report Callback
 *===========================================================================*/
static lup_sensor_cb_t g_lup_sensor_cb = NULL;

void lup_set_sensor_callback(lup_sensor_cb_t cb)
{
    g_lup_sensor_cb = cb;
    PRINT("LUP: sensor callback %s\n", cb ? "registered" : "cleared");
}

/*
 * 收到完整帧后的处理：
 *  1. 校验 checksum
 *  2. 如果是主动上报 (0xC0) → 调用回调（网络推送等）
 *  3. 如果是命令响应 → 匹配挂起命令
 */
void lup_process_frame(const uint8_t *pkg, uint16_t len)
{
    int csr;
    uint8_t i;

    if (len < 6) return;

    // Debug: print raw
    PRINT("LUP Rx:");
    for (i = 0; i < len; i++) {
        PRINT(" %02X", pkg[i]);
    }
    PRINT("\n");

    // --- Checksum ---
    csr = lup_verify_checksum(pkg, len);
    if (csr != 0) {
        PRINT("LUP: checksum fail (%d)\n", csr);
        return;
    }

    // --- Dispatch by CMD ---
    uint8_t cmd = pkg[3];

    // Active reports (0xC0) → trigger callback for network/upstream forwarding
    if (cmd == LUP_CMD_SENSOR_REPORT) {
        if (g_lup_sensor_cb) {
            g_lup_sensor_cb(pkg, len);
        } else {
            PRINT("LUP: 0xC0 received but no callback registered!\n");
        }
        return;
    }

    // Try matching with pending command
    lup_cmd_on_response(pkg, len);
}
