Files
vd_960/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/loop_uart_proto.c
wangfq c4a2b50ca5 fix: tcp_json_srv_init 加一次性守卫 + callback NULL 诊断
问题: NET_SSC_ENABLE 时 g_net_state.flag 保持 1, net_srv_init 反复调用
      tcp_json_srv_init 第二次因 socket 已存在失败 → 过早 return
      → lup_set_sensor_callback 未执行 → 0xC0 回调永远 NULL

修复:
- tcp_json_srv_init: 加 static _init_done 守卫,防止重复执行
- lup_set_sensor_callback: 打印注册/清除日志
- lup_process_frame: 回调为 NULL 时打印诊断信息
2026-07-02 14:29:23 +08:00

710 lines
21 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
******************************************************************************
* @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);
}