feat(Puya-PY32F040): add OTA dual-project codegen template

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-18 18:56:19 +08:00
co-authored by Cursor
commit 62eb0199ed
498 changed files with 329164 additions and 0 deletions
+362
View File
@@ -0,0 +1,362 @@
/* ================================================================
* 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();
}