250 lines
11 KiB
C
250 lines
11 KiB
C
/* ================================================================
|
||
* jb_product.c — 用户层实现(请填补空白处)
|
||
* 设备: 侠客猫激光 | 生成时间: 2026-07-31 17:08:51
|
||
*
|
||
* ══ 开发流程 ══
|
||
* 1. 实现硬件抽象: jbGetTimerCount(定时器由 SOC SDK 提供)
|
||
* 发送由 SOC SDK 的 ble_send_data 承担,协议层已直接调用,无需 uartWrite
|
||
* 2. userInit() 设置 DP 默认值与外设初始化
|
||
* 3. userHandle() 用户数据采集
|
||
* 4. jbEventProcess() 处理 APP 下发的控制命令
|
||
* 5. 主动上报 / OTA 的网关应答在收到 REPORTCMD_V2 后调用 jbReportAckCheck 清除等待
|
||
* 6. main.c / 调用方需周期性调用 jbReportAckCheck(cmd, cnt, int0)
|
||
* ================================================================
|
||
*/
|
||
|
||
#include "jb_product.h"
|
||
|
||
/* ════════════════════════════════════════════════════════════════
|
||
* 全局变量
|
||
* ════════════════════════════════════════════════════════════════ */
|
||
|
||
jb_data_point_t gDevData;
|
||
static volatile uint32_t timerMs;
|
||
|
||
/* ════════════════════════════════════════════════════════════════
|
||
* userInit — DP 默认值
|
||
* ════════════════════════════════════════════════════════════════ */
|
||
void userInit(void)
|
||
{
|
||
memset(&gDevData, 0, sizeof(jb_data_point_t));
|
||
|
||
gDevData.power = 0; /* DP0 开关 0=关 1=开 */
|
||
gDevData.play_mode = 0; /* PLAY_MODE_0 (关) */
|
||
gDevData.hand_mode = 0; /* HAND_MODE_0 (关) */
|
||
gDevData.alm_low_battery = 0; /* DP3 低电量报警 0=关 1=开 */
|
||
gDevData.beep_trig = 0; /* DP4 声音开关 0=关 1=开 */
|
||
gDevData.battery = 0; /* DP5 电量上报 */
|
||
gDevData.shake_wake = 0; /* DP6 震动触发开机 0=关 1=开 */
|
||
memset(gDevData.no_disturb_enable, 0, 13); /* DP7 勿扰模式开关 */
|
||
gDevData.reserva_dp1 = 0; /* DP8 预留DP1 */
|
||
gDevData.reserva_dp2 = 0; /* DP9 预留DP2 */
|
||
gDevData.reserva_dp3 = 0; /* DP10 预留DP3 */
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════════════════
|
||
* userHandle — 用户数据采集
|
||
* 协议层自动检测变化并上报(注意:此处是上报,不是下发控制)
|
||
* ════════════════════════════════════════════════════════════════ */
|
||
void userHandle(void)
|
||
{
|
||
/* ── 可上报 DP (RO / RW): 用户数据采集 ── */
|
||
// gDevData.power = read_sensor(); /* DP0 开关 */
|
||
// gDevData.play_mode = read_sensor(); /* DP1 自动模式 */
|
||
// gDevData.alm_low_battery = read_sensor(); /* DP3 低电量报警 */
|
||
// gDevData.beep_trig = read_sensor(); /* DP4 声音开关 */
|
||
// gDevData.battery = read_sensor(); /* DP5 电量上报 */
|
||
// gDevData.shake_wake = read_sensor(); /* DP6 震动触发开机 */
|
||
// memcpy(gDevData.no_disturb_enable, sensor_read(), 13); /* DP7 勿扰模式开关 */
|
||
// gDevData.reserva_dp1 = read_sensor(); /* DP8 预留DP1 */
|
||
// gDevData.reserva_dp2 = read_sensor(); /* DP9 预留DP2 */
|
||
// gDevData.reserva_dp3 = read_sensor(); /* DP10 预留DP3 */
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════════════════
|
||
* jbEventProcess — 0x03 APP 控制事件处理(下行 / DP 赋值方向)
|
||
*
|
||
* 协议层自动解包 0x03 帧后调用本函数。
|
||
* info->dp_ids[] = 被控制的 DP ID 列表
|
||
* ctrl 已填入下发的值;复制到 gDevData 并执行动作
|
||
* ════════════════════════════════════════════════════════════════ */
|
||
int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
||
{
|
||
if (!info || !ctrl)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
for (uint8_t i = 0; i < info->count; i++)
|
||
{
|
||
switch (info->dp_ids[i])
|
||
{
|
||
|
||
/* ── DP0 开关 (bool) ── */
|
||
case DP_ID_POWER:
|
||
if (ctrl->power)
|
||
{
|
||
gDevData.power = 1;
|
||
// TODO: 开 — 执行动作
|
||
}
|
||
else
|
||
{
|
||
gDevData.power = 0;
|
||
// TODO: 关 — 执行动作
|
||
}
|
||
break;
|
||
|
||
/* ── DP1 自动模式 (enum) ── */
|
||
case DP_ID_PLAY_MODE:
|
||
gDevData.play_mode = ctrl->play_mode;
|
||
switch (ctrl->play_mode)
|
||
{
|
||
case PLAY_MODE_0: /* 关 */
|
||
// TODO: 处理 关
|
||
break;
|
||
case PLAY_MODE_1: /* mode1 */
|
||
// TODO: 处理 mode1
|
||
break;
|
||
case PLAY_MODE_2: /* mode2 */
|
||
// TODO: 处理 mode2
|
||
break;
|
||
case PLAY_MODE_3: /* mode3 */
|
||
// TODO: 处理 mode3
|
||
break;
|
||
case PLAY_MODE_4: /* mode4 */
|
||
// TODO: 处理 mode4
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
break;
|
||
|
||
/* ── DP2 手动模式 (enum) ── */
|
||
case DP_ID_HAND_MODE:
|
||
gDevData.hand_mode = ctrl->hand_mode;
|
||
switch (ctrl->hand_mode)
|
||
{
|
||
case HAND_MODE_0: /* 关 */
|
||
// TODO: 处理 关
|
||
break;
|
||
case HAND_MODE_1: /* 顺时针 */
|
||
// TODO: 处理 顺时针
|
||
break;
|
||
case HAND_MODE_2: /* 逆时针 */
|
||
// TODO: 处理 逆时针
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
break;
|
||
|
||
/* ── DP4 声音开关 (bool) ── */
|
||
case DP_ID_BEEP_TRIG:
|
||
if (ctrl->beep_trig)
|
||
{
|
||
gDevData.beep_trig = 1;
|
||
// TODO: 开 — 执行动作
|
||
}
|
||
else
|
||
{
|
||
gDevData.beep_trig = 0;
|
||
// TODO: 关 — 执行动作
|
||
}
|
||
break;
|
||
|
||
/* ── DP6 震动触发开机 (bool) ── */
|
||
case DP_ID_SHAKE_WAKE:
|
||
if (ctrl->shake_wake)
|
||
{
|
||
gDevData.shake_wake = 1;
|
||
// TODO: 开 — 执行动作
|
||
}
|
||
else
|
||
{
|
||
gDevData.shake_wake = 0;
|
||
// TODO: 关 — 执行动作
|
||
}
|
||
break;
|
||
|
||
/* ── DP7 勿扰模式开关 (raw) ── */
|
||
case DP_ID_NO_DISTURB_ENABLE:
|
||
memcpy(gDevData.no_disturb_enable, ctrl->no_disturb_enable, 13);
|
||
// TODO: 根据 gDevData.no_disturb_enable 执行动作 (长度 13 字节)
|
||
break;
|
||
|
||
/* ── DP8 预留DP1 (uint32) ── */
|
||
case DP_ID_RESERVA_DP1:
|
||
gDevData.reserva_dp1 = ctrl->reserva_dp1;
|
||
// TODO: 根据 ctrl->reserva_dp1 执行动作
|
||
break;
|
||
|
||
/* ── DP9 预留DP2 (uint32) ── */
|
||
case DP_ID_RESERVA_DP2:
|
||
gDevData.reserva_dp2 = ctrl->reserva_dp2;
|
||
// TODO: 根据 ctrl->reserva_dp2 执行动作
|
||
break;
|
||
|
||
/* ── DP10 预留DP3 (uint32) ── */
|
||
case DP_ID_RESERVA_DP3:
|
||
gDevData.reserva_dp3 = ctrl->reserva_dp3;
|
||
// TODO: 根据 ctrl->reserva_dp3 执行动作
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 0x30 OTA 升级请求 */
|
||
void jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32)
|
||
{
|
||
(void)fwVersion; (void)fwLength; (void)fwCrc32;
|
||
// TODO: 检查 Flash 空间与版本,决定是否接收升级
|
||
// 允许: 直接返回(协议层默认应答 JB_OK + MaxDataLen=128)
|
||
// 拒绝: 在 jbHandleOtaNotify 中改为 jbSendFrame(CMD_OTA_NOTIFY_ACK, sn, 错误码, 3)
|
||
}
|
||
|
||
/* 0x32 OTA 数据(含分片序号)*/
|
||
void jbOnOtaData(const uint8_t *data, uint16_t len,
|
||
uint16_t shardIdx, uint16_t totalShards)
|
||
{
|
||
(void)data; (void)len; (void)shardIdx; (void)totalShards;
|
||
// TODO: 写入 Flash,累计 CRC32
|
||
// 全部数据接收完成后调用 jbSendOtaResult(JB_OK, mcuVersion)
|
||
}
|
||
|
||
/* 0x36 / 0x38 停止 OTA */
|
||
void jbOnOtaStop(void)
|
||
{
|
||
// TODO: 终止 OTA,释放资源
|
||
}
|
||
|
||
/* 任意 MCU→BLE 请求的 ACK 回调(cmd 标识是哪条请求的应答,result 为结果码)
|
||
- SOC 仅保留 OTA 主动请求应答: OTA完成 0x35 / 停止 0x39
|
||
- 可在本回调中设置"XX 完成/失败"标志,供主循环判断"确认成功才继续" */
|
||
void jbOnAck(uint8_t cmd, uint8_t result)
|
||
{
|
||
(void)cmd; (void)result;
|
||
// TODO: switch(cmd){ case CMD_OTA_COMPLETE_ACK: gOtaDone = (result==JB_OK); break; case CMD_OTA_STOP_MCU_ACK: ... }
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════════════════
|
||
* 硬件抽象(按实际平台实现)
|
||
* ════════════════════════════════════════════════════════════════ */
|
||
|
||
/* ── 定时器 ── */
|
||
void jbTimerIrq(void)
|
||
{
|
||
timerMs++;
|
||
} /* 在 1ms 中断中调用本函数 */
|
||
|
||
uint32_t jbGetTimerCount(void)
|
||
{
|
||
return timerMs;
|
||
}
|
||
|
||
/* SOC: 发送由 SOC SDK 的 ble_send_data 承担,无需 uartInit / uartWrite;
|
||
* 定时器由 SOC SDK 提供,仅保留 jbTimerIrq / jbGetTimerCount 接入即可。 */
|