Files
mcu-codegen-template/App/Protocol/jb_product.c
T

363 lines
13 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.
/* ================================================================
* jb_product.c — 用户层实现(请填补空白处)
* 设备: 侠客猫激光 | 生成时间: 2026-07-28 15:42:40
*
* ══ 开发流程 ══
* 1. 实现硬件抽象: uartInit / timerInit / uartWrite / jbGetTimerCount
* 2. userInit() 设置 DP 默认值与外设初始化
* 3. userHandle() 用户数据采集
* 4. jbEventProcess() 处理 APP 下发的控制命令
* 5. main.c 模板:
*
* int main(void)
* {
* uartInit();
* timerInit();
* jbInit();
* userInit();
* while (1)
* {
* userHandle();
* jbProtocolHandle(&gDevData);
* }
* }
* ================================================================
*/
#include "jb_product.h"
#include "jb_port.h"
#include "main.h"
#include "ota_ab.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;
}
/* ════════════════════════════════════════════════════════════════
* BLE → MCU 回调(按需实现)
* ════════════════════════════════════════════════════════════════ */
/* 0x14 工作状态同步(含 RSSI*/
void jbOnWorkState(uint8_t state, int8_t rssi)
{
(void)state;
(void)rssi;
// Bit0=已配网 Bit1=外网 Bit2=App在线 Bit3=BLE连接 Bit4=OTA Bit5=配对
// TODO: 按状态位更新状态指示;rssi: >=-60 优秀, -61~-70 良好, -71~-80 一般, -81~-90 较差, <-90 极差
}
/* 0x1A BLE 通知 MCU 重启 */
void jbOnBleRestartRequest(void)
{
ota_abort();
mcuRestart();
}
/* 0x30 OTA 升级请求
* 返回 0=接受升级(协议层应答 JB_OK + MaxDataLen
* 非 0=拒绝,返回值即错误码(JB_OTA_*) */
int8_t jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32)
{
/* 版本校验:拒绝「版本一致」与「降级」,只允许升级到更高版本。 */
const uint32_t curVer = ((uint32_t)JB_MCU_SW_VERSION_MAJOR << 16) |
((uint32_t)JB_MCU_SW_VERSION_MINOR << 8) |
(uint32_t)JB_MCU_SW_VERSION_PATCH;
appPrintf(LOG_NOTIC, "OTA notify: ver=%06X cur=%06X len=%lu crc=%08X\r\n",
(unsigned int)fwVersion, (unsigned int)curVer,
(unsigned long)fwLength, (unsigned int)fwCrc32);
if (fwVersion == curVer)
{
appPrintf(LOG_NOTIC, "OTA reject: same version, no need to upgrade\r\n");
return JB_OTA_NO_NEED; /* 0x20 版本一致,无需升级 */
}
if (fwVersion < curVer)
{
appPrintf(LOG_NOTIC, "OTA reject: version lower than current\r\n");
return JB_OTA_VER_LOW; /* 0x21 版本低于当前,拒绝降级 */
}
if ((fwLength == 0) || (fwLength > OTA_SLOT_MAX_SIZE))
{
appPrintf(LOG_ERROR, "OTA reject: length %lu out of range\r\n", (unsigned long)fwLength);
return JB_OTA_SPACE_ERR;
}
if (ota_start(fwLength, fwCrc32) != 0)
{
return JB_OTA_STATE_ERR;
}
return JB_OK;
}
/* 0x32 OTA 数据(含分片序号)*/
void jbOnOtaData(const uint8_t *data, uint16_t len, uint16_t shardIdx, uint16_t totalShards)
{
if (ota_receive_chunk(data, len) != 0)
{
appPrintf(LOG_ERROR, "OTA chunk write fail (shard %u/%u)\r\n", shardIdx, totalShards);
return;
}
/* 以 0x30 的 fwLength 收满为准,不依赖分片序号 0/1 基 */
if (ota_is_download_complete())
{
appPrintf(LOG_NOTIC, "OTA download complete (shard %u/%u), verify...\r\n",
shardIdx, totalShards);
if (ota_finish() == 0)
{
appPrintf(LOG_NOTIC, "OTA verify OK, rebooting...\r\n");
HAL_Delay(100);
mcuRestart();
}
else
{
uint8_t ver[3] = {
JB_MCU_SW_VERSION_MAJOR,
JB_MCU_SW_VERSION_MINOR,
JB_MCU_SW_VERSION_PATCH};
appPrintf(LOG_ERROR, "OTA verify FAILED\r\n");
(void)jbSendOtaResult(JB_OTA_FILE_ERR, ver);
}
}
}
/* 0x36 / 0x38 停止 OTA */
void jbOnOtaStop(void)
{
ota_abort();
}
/* 0x1D 时间同步应答 */
void jbOnTimeSync(uint32_t timestamp)
{
/* Unix 时间戳(秒);后续可在此写入 MCU RTC */
appPrintf(LOG_NOTIC, "RTC time sync: timestamp=%lu\r\n",
(unsigned long)timestamp);
}
/* 任意 MCU→BLE 请求的 ACK 回调(cmd 标识是哪条请求的应答,result 为结果码)
- 如配对 0x11 / 产测 0x21 / 拍照 0x23 / 录像 0x25 / 音频 0x27 / OTA完成 0x35 / 停止 0x39
- 可在本回调中设置"XX 完成/失败"标志,供主循环判断"确认成功才继续" */
void jbOnAck(uint8_t cmd, uint8_t result)
{
(void)cmd;
(void)result;
// TODO: switch(cmd){ case CMD_PAIRING_ACK: gPairingDone = (result==JB_OK); break; ... }
}
/* ════════════════════════════════════════════════════════════════
* 硬件抽象(按实际平台实现)
* ════════════════════════════════════════════════════════════════ */
/* ── 定时器 ── */
void jbTimerIrq(void)
{
timerMs++;
} /* 在 1ms 中断中调用本函数 */
uint32_t jbGetTimerCount(void)
{
return timerMs;
}
void timerInit(void)
{
timerMs = 0;
jb_port_timer_init();
}
/* ── UART ── */
void uartInit(void)
{
jb_port_uart_init();
}
int32_t uartWrite(uint8_t *buf, uint32_t len)
{
return jb_port_uart_write(buf, len);
}
/* ── 系统 ── */
void mcuRestart(void)
{
NVIC_SystemReset();
}