feat: 完成弹力魔盒初版固件
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/* ================================================================
|
||||
* jb_product.c — 用户层实现(请填补空白处)
|
||||
* 设备: 门夹弹力绳 | 生成时间: 2026-08-21 18:01:47
|
||||
* 设备: 猫猫捕猎罩 | 生成时间: 2026-08-18 16:24:47
|
||||
*
|
||||
* ══ 开发流程 ══
|
||||
* 1. 实现硬件抽象: jbGetTimerCount(定时器由 SOC SDK 提供)
|
||||
@@ -13,6 +13,8 @@
|
||||
*/
|
||||
|
||||
#include "jb_product.h"
|
||||
#include "app_function.h"
|
||||
#include "usr_rtc.h"
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 全局变量
|
||||
@@ -21,6 +23,79 @@
|
||||
jb_data_point_t gDevData;
|
||||
static volatile uint32_t timerMs;
|
||||
|
||||
#define JB_DND_LEN 13
|
||||
#define JB_DND_ENABLE_OFFSET 0
|
||||
#define JB_DND_WEEK_OFFSET 2
|
||||
#define JB_DND_START_HOUR_OFFSET 9
|
||||
#define JB_DND_START_MIN_OFFSET 10
|
||||
#define JB_DND_END_HOUR_OFFSET 11
|
||||
#define JB_DND_END_MIN_OFFSET 12
|
||||
static uint8_t jbLastNoDisturbActive;
|
||||
|
||||
/* Return weekday with Monday=0, matching DP7 bytes 2..8. */
|
||||
static uint8_t jbWeekdayMonday0(const struct sys_time *time)
|
||||
{
|
||||
static const uint8_t monthOffset[12] = {
|
||||
0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4
|
||||
};
|
||||
uint16_t year = time->year;
|
||||
uint8_t sunday0;
|
||||
|
||||
if (time->month < 3) {
|
||||
year--;
|
||||
}
|
||||
sunday0 = (uint8_t)((year + year / 4U - year / 100U + year / 400U +
|
||||
monthOffset[time->month - 1U] + time->day) % 7U);
|
||||
return (uint8_t)((sunday0 + 6U) % 7U);
|
||||
}
|
||||
|
||||
static void jbNoDisturbNormalize(uint8_t *cfg)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
cfg[JB_DND_ENABLE_OFFSET] = !!cfg[JB_DND_ENABLE_OFFSET];
|
||||
for (i = 0; i < 7; i++) {
|
||||
cfg[JB_DND_WEEK_OFFSET + i] = !!cfg[JB_DND_WEEK_OFFSET + i];
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t jbNoDisturbScheduleValid(const uint8_t *cfg)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
if (cfg[JB_DND_START_HOUR_OFFSET] >= 24 ||
|
||||
cfg[JB_DND_END_HOUR_OFFSET] >= 24 ||
|
||||
cfg[JB_DND_START_MIN_OFFSET] >= 60 ||
|
||||
cfg[JB_DND_END_MIN_OFFSET] >= 60) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (cfg[JB_DND_WEEK_OFFSET + i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t jbNoDisturbActive(void)
|
||||
{
|
||||
/* Match the verified product behavior: DP7 byte 0 is the global
|
||||
* no-disturb switch. Schedule bytes are retained and reported, but do
|
||||
* not gate the local vibration wake path. */
|
||||
return !!gDevData.no_disturb_enable[JB_DND_ENABLE_OFFSET];
|
||||
}
|
||||
|
||||
static void jbNoDisturbUpdate(void)
|
||||
{
|
||||
uint8_t active = jbNoDisturbActive();
|
||||
|
||||
if (active == jbLastNoDisturbActive) {
|
||||
return;
|
||||
}
|
||||
jbLastNoDisturbActive = active;
|
||||
app_function_set_no_disturb(active);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* userInit — DP 默认值
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
@@ -30,16 +105,16 @@ void userInit(void)
|
||||
|
||||
gDevData.power = 0; /* DP0 开关 0=关 1=开 */
|
||||
gDevData.play_mode = 0; /* PLAY_MODE_0 (停止复位) */
|
||||
memset(gDevData.hand_mode, 0, 2); /* DP2 手动模式 */
|
||||
gDevData.calibration = 0; /* DP3 绳索校准 0=关 1=开 */
|
||||
gDevData.numberturns = 0; /* DP4 绳索圈数 */
|
||||
gDevData.alm_low_battery = 0; /* DP5 低电量报警 0=关 1=开 */
|
||||
gDevData.battery = 0; /* DP6 电量上报 */
|
||||
gDevData.charge = 1; /* CHARGE_1 (充电中) */
|
||||
memset(gDevData.no_disturb_enable, 0, 13); /* DP8 勿扰模式开关 */
|
||||
gDevData.reserva_dp1 = 0; /* DP9 预留DP1 */
|
||||
gDevData.reserva_dp2 = 0; /* DP10 预留DP2 */
|
||||
gDevData.reserva_dp3 = 0; /* DP11 预留DP3 */
|
||||
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.charge = 0; /* CHARGE_0 (不支持充电) */
|
||||
gDevData.reserva_dp3 = 0; /* DP10 预留DP3 */
|
||||
jbLastNoDisturbActive = 0xff;
|
||||
jbNoDisturbUpdate();
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
@@ -48,16 +123,18 @@ void userInit(void)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
void userHandle(void)
|
||||
{
|
||||
jbNoDisturbUpdate();
|
||||
|
||||
/* ── 可上报 DP (RO / RW): 用户数据采集 ── */
|
||||
// gDevData.power = read_sensor(); /* DP0 开关 */
|
||||
// gDevData.play_mode = read_sensor(); /* DP1 自动模式 */
|
||||
// gDevData.alm_low_battery = read_sensor(); /* DP5 低电量报警 */
|
||||
// gDevData.battery = read_sensor(); /* DP6 电量上报 */
|
||||
// gDevData.charge = read_sensor(); /* DP7 充电状态 */
|
||||
// memcpy(gDevData.no_disturb_enable, sensor_read(), 13); /* DP8 勿扰模式开关 */
|
||||
// gDevData.reserva_dp1 = read_sensor(); /* DP9 预留DP1 */
|
||||
// gDevData.reserva_dp2 = read_sensor(); /* DP10 预留DP2 */
|
||||
// gDevData.reserva_dp3 = read_sensor(); /* DP11 预留DP3 */
|
||||
// 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.charge = read_sensor(); /* DP8 充电状态 */
|
||||
// gDevData.reserva_dp3 = read_sensor(); /* DP10 预留DP3 */
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
@@ -69,6 +146,8 @@ void userHandle(void)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
||||
{
|
||||
int8_t result = JB_OK;
|
||||
|
||||
if (!info || !ctrl)
|
||||
{
|
||||
return -1;
|
||||
@@ -81,98 +160,47 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
||||
|
||||
/* ── DP0 开关 (bool) ── */
|
||||
case DP_ID_POWER:
|
||||
if (ctrl->power)
|
||||
{
|
||||
gDevData.power = 1;
|
||||
// TODO: 开 — 执行动作
|
||||
}
|
||||
else
|
||||
{
|
||||
gDevData.power = 0;
|
||||
// TODO: 关 — 执行动作
|
||||
}
|
||||
app_function_dp_power_write(ctrl->power);
|
||||
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: /* 弹力伪装 */
|
||||
// TODO: 处理 弹力伪装
|
||||
break;
|
||||
case PLAY_MODE_2: /* 飞鸟俯冲 */
|
||||
// TODO: 处理 飞鸟俯冲
|
||||
break;
|
||||
case PLAY_MODE_3: /* 云阶小陀螺 */
|
||||
// TODO: 处理 云阶小陀螺
|
||||
break;
|
||||
case PLAY_MODE_4: /* 起伏攻防战 */
|
||||
// TODO: 处理 起伏攻防战
|
||||
break;
|
||||
case PLAY_MODE_5: /* 微风拂动 */
|
||||
// TODO: 处理 微风拂动
|
||||
break;
|
||||
case PLAY_MODE_6: /* 闪电快闪 */
|
||||
// TODO: 处理 闪电快闪
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
app_function_dp_play_write(ctrl->play_mode);
|
||||
break;
|
||||
|
||||
/* ── DP2 手动模式 (raw) ── */
|
||||
/* ── DP2 手动模式 (enum) ── */
|
||||
case DP_ID_HAND_MODE:
|
||||
memcpy(gDevData.hand_mode, ctrl->hand_mode, 2);
|
||||
/* 薄适配:通知业务层;03=停,00=空闲 */
|
||||
{
|
||||
extern void usr_dp_hand_write(uint8_t cmd);
|
||||
usr_dp_hand_write(ctrl->hand_mode[0]);
|
||||
}
|
||||
app_function_dp_hand_write(ctrl->hand_mode);
|
||||
break;
|
||||
|
||||
/* ── DP3 绳索校准 (bool) ── */
|
||||
case DP_ID_CALIBRATION:
|
||||
if (ctrl->calibration)
|
||||
/* ── DP4 声音开关 (bool) ── */
|
||||
case DP_ID_BEEP_TRIG:
|
||||
if (ctrl->beep_trig)
|
||||
{
|
||||
gDevData.calibration = 1;
|
||||
gDevData.beep_trig = 1;
|
||||
// TODO: 开 — 执行动作
|
||||
}
|
||||
else
|
||||
{
|
||||
gDevData.calibration = 0;
|
||||
gDevData.beep_trig = 0;
|
||||
// TODO: 关 — 执行动作
|
||||
}
|
||||
break;
|
||||
|
||||
/* ── DP4 绳索圈数 (uint8) ── */
|
||||
case DP_ID_NUMBERTURNS:
|
||||
gDevData.numberturns = ctrl->numberturns;
|
||||
// TODO: 根据 ctrl->numberturns 执行动作
|
||||
/* ── DP6 震动触发开机 (bool) ── */
|
||||
case DP_ID_SHAKE_WAKE:
|
||||
app_function_set_shake_wake(ctrl->shake_wake);
|
||||
break;
|
||||
|
||||
/* ── DP8 勿扰模式开关 (raw) ── */
|
||||
/* ── DP7 勿扰模式开关 (raw) ── */
|
||||
case DP_ID_NO_DISTURB_ENABLE:
|
||||
memcpy(gDevData.no_disturb_enable, ctrl->no_disturb_enable, 13);
|
||||
// TODO: 根据 gDevData.no_disturb_enable 执行动作 (长度 13 字节)
|
||||
memcpy(gDevData.no_disturb_enable, ctrl->no_disturb_enable,
|
||||
JB_DND_LEN);
|
||||
jbNoDisturbNormalize(gDevData.no_disturb_enable);
|
||||
jbNoDisturbUpdate();
|
||||
break;
|
||||
|
||||
/* ── DP9 预留DP1 (uint32) ── */
|
||||
case DP_ID_RESERVA_DP1:
|
||||
gDevData.reserva_dp1 = ctrl->reserva_dp1;
|
||||
// TODO: 根据 ctrl->reserva_dp1 执行动作
|
||||
break;
|
||||
|
||||
/* ── DP10 预留DP2 (uint32) ── */
|
||||
case DP_ID_RESERVA_DP2:
|
||||
gDevData.reserva_dp2 = ctrl->reserva_dp2;
|
||||
// TODO: 根据 ctrl->reserva_dp2 执行动作
|
||||
break;
|
||||
|
||||
/* ── DP11 预留DP3 (uint32) ── */
|
||||
/* ── DP10 预留DP3 (uint32) ── */
|
||||
case DP_ID_RESERVA_DP3:
|
||||
gDevData.reserva_dp3 = ctrl->reserva_dp3;
|
||||
// TODO: 根据 ctrl->reserva_dp3 执行动作
|
||||
@@ -182,21 +210,16 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 0x30 OTA 升级请求
|
||||
* 返回 0=接受升级(协议层应答 JB_OK + MaxDataLen)
|
||||
* 非 0=拒绝,返回值即错误码(JB_OTA_*)
|
||||
*
|
||||
* ⚠ SOC 侧 OTA 尚未实现:当前仅应答,不执行任何升级动作。 */
|
||||
int8_t jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32)
|
||||
/* 0x30 OTA 升级请求 */
|
||||
void jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32)
|
||||
{
|
||||
(void)fwVersion; (void)fwLength; (void)fwCrc32;
|
||||
// TODO: 检查 Flash 空间与版本,决定是否接收升级
|
||||
// 允许: 返回 JB_OK(协议层应答 JB_OK + MaxDataLen)
|
||||
// 拒绝: 返回对应 JB_OTA_* 错误码(如 JB_OTA_VER_LOW / JB_OTA_SPACE_ERR)
|
||||
return JB_OK;
|
||||
// 允许: 直接返回(协议层默认应答 JB_OK + MaxDataLen=128)
|
||||
// 拒绝: 在 jbHandleOtaNotify 中改为 jbSendFrame(CMD_OTA_NOTIFY_ACK, sn, 错误码, 3)
|
||||
}
|
||||
|
||||
/* 0x32 OTA 数据(含分片序号)*/
|
||||
@@ -219,8 +242,7 @@ void jbOnOtaStop(void)
|
||||
- 可在本回调中设置"XX 完成/失败"标志,供主循环判断"确认成功才继续" */
|
||||
void jbOnAck(uint8_t cmd, uint8_t result)
|
||||
{
|
||||
(void)cmd;
|
||||
(void)result;
|
||||
(void)cmd; (void)result;
|
||||
// TODO: switch(cmd){ case CMD_OTA_COMPLETE_ACK: gOtaDone = (result==JB_OK); break; case CMD_OTA_STOP_MCU_ACK: ... }
|
||||
}
|
||||
|
||||
@@ -232,7 +254,7 @@ void jbOnAck(uint8_t cmd, uint8_t result)
|
||||
void jbTimerIrq(void)
|
||||
{
|
||||
timerMs++;
|
||||
} /* 在 1ms 中断中调用本函数 */
|
||||
} /* 在 1ms 中断中调用本函数 */
|
||||
|
||||
uint32_t jbGetTimerCount(void)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* ================================================================
|
||||
* jb_product.h — 用户层头文件(自动生成)
|
||||
* 设备: 门夹弹力绳 | 生成时间: 2026-08-21 18:01:47
|
||||
* 设备: 猫猫捕猎罩 | 生成时间: 2026-08-18 16:24:47
|
||||
*
|
||||
* 声明用户需实现的函数。数据结构定义见 jb_protocol.h
|
||||
* ================================================================
|
||||
@@ -43,7 +43,7 @@ void jbTimerIrq(void); /* Call from 1ms timer ISR */
|
||||
|
||||
/* =========== 协议回调(声明见 jb_protocol.h)================== */
|
||||
/* int8_t jbEventProcess(...); // 0x03 控制事件 */
|
||||
/* int8_t jbOnOtaNotify(...); // 0x30 OTA 请求 */
|
||||
/* void jbOnOtaNotify(...); // 0x30 OTA 请求 */
|
||||
/* void jbOnOtaData(...); // 0x32 OTA 数据 */
|
||||
/* void jbOnOtaStop(); // 0x36/0x38 停止 OTA */
|
||||
/* void jbOnAck(...); // 任意请求 ACK(结果) */
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
/* ================================================================
|
||||
* jb_protocol.c — 见宝 IOT 协议实现(自动生成)
|
||||
* 设备: 门夹弹力绳 | 生成时间: 2026-08-21 18:01:47
|
||||
* 设备: 猫猫捕猎罩 | 生成时间: 2026-08-18 16:24:47
|
||||
* ================================================================
|
||||
*/
|
||||
|
||||
#include "jb_protocol.h"
|
||||
#include "jb_common.h"
|
||||
#include "jb_product.h"
|
||||
#include "jb_ringbuffer.h"
|
||||
#include "stdio.h"
|
||||
#include "jb_common.h"
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 全局实例
|
||||
@@ -168,46 +167,44 @@ static uint16_t jbPackDps(const jb_data_point_t *dp,
|
||||
bitmap[DP_ID_PLAY_MODE / 8] |= (1 << (DP_ID_PLAY_MODE % 8));
|
||||
out[valIdx++] = (uint8_t)dp->play_mode;
|
||||
}
|
||||
/* DP5 低电量报警 (bool, 1B, RO) */
|
||||
/* DP3 低电量报警 (bool, 1B, RO) */
|
||||
if (mask[DP_ID_ALM_LOW_BATTERY / 8] & (1 << (DP_ID_ALM_LOW_BATTERY % 8)))
|
||||
{
|
||||
bitmap[DP_ID_ALM_LOW_BATTERY / 8] |= (1 << (DP_ID_ALM_LOW_BATTERY % 8));
|
||||
out[valIdx++] = dp->alm_low_battery ? 1 : 0;
|
||||
}
|
||||
/* DP6 电量上报 (uint8, 1B, RO) */
|
||||
/* DP4 声音开关 (bool, 1B, RW) */
|
||||
if (mask[DP_ID_BEEP_TRIG / 8] & (1 << (DP_ID_BEEP_TRIG % 8)))
|
||||
{
|
||||
bitmap[DP_ID_BEEP_TRIG / 8] |= (1 << (DP_ID_BEEP_TRIG % 8));
|
||||
out[valIdx++] = dp->beep_trig ? 1 : 0;
|
||||
}
|
||||
/* DP5 电量上报 (uint8, 1B, RO) */
|
||||
if (mask[DP_ID_BATTERY / 8] & (1 << (DP_ID_BATTERY % 8)))
|
||||
{
|
||||
bitmap[DP_ID_BATTERY / 8] |= (1 << (DP_ID_BATTERY % 8));
|
||||
out[valIdx++] = (uint8_t)dp->battery;
|
||||
}
|
||||
/* DP7 充电状态 (enum, 1B, RO) */
|
||||
if (mask[DP_ID_CHARGE / 8] & (1 << (DP_ID_CHARGE % 8)))
|
||||
/* DP6 震动触发开机 (bool, 1B, RW) */
|
||||
if (mask[DP_ID_SHAKE_WAKE / 8] & (1 << (DP_ID_SHAKE_WAKE % 8)))
|
||||
{
|
||||
bitmap[DP_ID_CHARGE / 8] |= (1 << (DP_ID_CHARGE % 8));
|
||||
out[valIdx++] = (uint8_t)dp->charge;
|
||||
bitmap[DP_ID_SHAKE_WAKE / 8] |= (1 << (DP_ID_SHAKE_WAKE % 8));
|
||||
out[valIdx++] = dp->shake_wake ? 1 : 0;
|
||||
}
|
||||
/* DP8 勿扰模式开关 (raw, 13B, RW) */
|
||||
/* DP7 勿扰模式开关 (raw, 13B, RW) */
|
||||
if (mask[DP_ID_NO_DISTURB_ENABLE / 8] & (1 << (DP_ID_NO_DISTURB_ENABLE % 8)))
|
||||
{
|
||||
bitmap[DP_ID_NO_DISTURB_ENABLE / 8] |= (1 << (DP_ID_NO_DISTURB_ENABLE % 8));
|
||||
memcpy(&out[valIdx], dp->no_disturb_enable, 13);
|
||||
valIdx += 13;
|
||||
}
|
||||
/* DP9 预留DP1 (uint32, 4B, RW) */
|
||||
if (mask[DP_ID_RESERVA_DP1 / 8] & (1 << (DP_ID_RESERVA_DP1 % 8)))
|
||||
/* DP8 充电状态 (enum, 1B, RO) */
|
||||
if (mask[DP_ID_CHARGE / 8] & (1 << (DP_ID_CHARGE % 8)))
|
||||
{
|
||||
bitmap[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8));
|
||||
jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp1);
|
||||
valIdx += 4;
|
||||
bitmap[DP_ID_CHARGE / 8] |= (1 << (DP_ID_CHARGE % 8));
|
||||
out[valIdx++] = (uint8_t)dp->charge;
|
||||
}
|
||||
/* DP10 预留DP2 (uint32, 4B, RW) */
|
||||
if (mask[DP_ID_RESERVA_DP2 / 8] & (1 << (DP_ID_RESERVA_DP2 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_RESERVA_DP2 / 8] |= (1 << (DP_ID_RESERVA_DP2 % 8));
|
||||
jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp2);
|
||||
valIdx += 4;
|
||||
}
|
||||
/* DP11 预留DP3 (uint32, 4B, RW) */
|
||||
/* DP10 预留DP3 (uint32, 4B, RW) */
|
||||
if (mask[DP_ID_RESERVA_DP3 / 8] & (1 << (DP_ID_RESERVA_DP3 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_RESERVA_DP3 / 8] |= (1 << (DP_ID_RESERVA_DP3 % 8));
|
||||
@@ -256,44 +253,43 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_PLAY_MODE;
|
||||
}
|
||||
}
|
||||
/* DP2 手动模式 (raw, 2B, WO) */
|
||||
/* DP2 手动模式 (enum, 1B, WO) */
|
||||
if (bitmap[DP_ID_HAND_MODE / 8] & (1 << (DP_ID_HAND_MODE % 8)))
|
||||
{
|
||||
if (valIdx + 2 <= valLen)
|
||||
if (valIdx < valLen)
|
||||
{
|
||||
memcpy(dp->hand_mode, &values[valIdx], 2);
|
||||
valIdx += 2;
|
||||
dp->hand_mode = values[valIdx++];
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_HAND_MODE;
|
||||
}
|
||||
}
|
||||
/* DP3 绳索校准 (bool, 1B, WO) */
|
||||
if (bitmap[DP_ID_CALIBRATION / 8] & (1 << (DP_ID_CALIBRATION % 8)))
|
||||
/* DP4 声音开关 (bool, 1B, RW) */
|
||||
if (bitmap[DP_ID_BEEP_TRIG / 8] & (1 << (DP_ID_BEEP_TRIG % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
{
|
||||
dp->calibration = (values[valIdx++] != 0);
|
||||
dp->beep_trig = (values[valIdx++] != 0);
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_CALIBRATION;
|
||||
info->dp_ids[info->count++] = DP_ID_BEEP_TRIG;
|
||||
}
|
||||
}
|
||||
/* DP4 绳索圈数 (uint8, 1B, WO) */
|
||||
if (bitmap[DP_ID_NUMBERTURNS / 8] & (1 << (DP_ID_NUMBERTURNS % 8)))
|
||||
/* DP6 震动触发开机 (bool, 1B, RW) */
|
||||
if (bitmap[DP_ID_SHAKE_WAKE / 8] & (1 << (DP_ID_SHAKE_WAKE % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
{
|
||||
dp->numberturns = values[valIdx++];
|
||||
dp->shake_wake = (values[valIdx++] != 0);
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_NUMBERTURNS;
|
||||
info->dp_ids[info->count++] = DP_ID_SHAKE_WAKE;
|
||||
}
|
||||
}
|
||||
/* DP8 勿扰模式开关 (raw, 13B, RW) */
|
||||
/* DP7 勿扰模式开关 (raw, 13B, RW) */
|
||||
if (bitmap[DP_ID_NO_DISTURB_ENABLE / 8] & (1 << (DP_ID_NO_DISTURB_ENABLE % 8)))
|
||||
{
|
||||
if (valIdx + 13 <= valLen)
|
||||
@@ -306,33 +302,7 @@ static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
info->dp_ids[info->count++] = DP_ID_NO_DISTURB_ENABLE;
|
||||
}
|
||||
}
|
||||
/* DP9 预留DP1 (uint32, 4B, RW) */
|
||||
if (bitmap[DP_ID_RESERVA_DP1 / 8] & (1 << (DP_ID_RESERVA_DP1 % 8)))
|
||||
{
|
||||
if (valIdx + 4 <= valLen)
|
||||
{
|
||||
dp->reserva_dp1 = (uint32_t)jbReadU32BE(&values[valIdx]);
|
||||
valIdx += 4;
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_RESERVA_DP1;
|
||||
}
|
||||
}
|
||||
/* DP10 预留DP2 (uint32, 4B, RW) */
|
||||
if (bitmap[DP_ID_RESERVA_DP2 / 8] & (1 << (DP_ID_RESERVA_DP2 % 8)))
|
||||
{
|
||||
if (valIdx + 4 <= valLen)
|
||||
{
|
||||
dp->reserva_dp2 = (uint32_t)jbReadU32BE(&values[valIdx]);
|
||||
valIdx += 4;
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_RESERVA_DP2;
|
||||
}
|
||||
}
|
||||
/* DP11 预留DP3 (uint32, 4B, RW) */
|
||||
/* DP10 预留DP3 (uint32, 4B, RW) */
|
||||
if (bitmap[DP_ID_RESERVA_DP3 / 8] & (1 << (DP_ID_RESERVA_DP3 % 8)))
|
||||
{
|
||||
if (valIdx + 4 <= valLen)
|
||||
@@ -370,43 +340,43 @@ static uint8_t jbBuildDiffMask(const jb_data_point_t *last,
|
||||
mask[DP_ID_PLAY_MODE / 8] |= (1 << (DP_ID_PLAY_MODE % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP5 低电量报警 */
|
||||
/* DP3 低电量报警 */
|
||||
if (last->alm_low_battery != cur->alm_low_battery)
|
||||
{
|
||||
mask[DP_ID_ALM_LOW_BATTERY / 8] |= (1 << (DP_ID_ALM_LOW_BATTERY % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP6 电量上报 */
|
||||
/* DP4 声音开关 */
|
||||
if (last->beep_trig != cur->beep_trig)
|
||||
{
|
||||
mask[DP_ID_BEEP_TRIG / 8] |= (1 << (DP_ID_BEEP_TRIG % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP5 电量上报 */
|
||||
if (last->battery != cur->battery)
|
||||
{
|
||||
mask[DP_ID_BATTERY / 8] |= (1 << (DP_ID_BATTERY % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP7 充电状态 */
|
||||
if (last->charge != cur->charge)
|
||||
/* DP6 震动触发开机 */
|
||||
if (last->shake_wake != cur->shake_wake)
|
||||
{
|
||||
mask[DP_ID_CHARGE / 8] |= (1 << (DP_ID_CHARGE % 8));
|
||||
mask[DP_ID_SHAKE_WAKE / 8] |= (1 << (DP_ID_SHAKE_WAKE % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP8 勿扰模式开关 */
|
||||
/* DP7 勿扰模式开关 */
|
||||
if (memcmp(last->no_disturb_enable, cur->no_disturb_enable, 13))
|
||||
{
|
||||
mask[DP_ID_NO_DISTURB_ENABLE / 8] |= (1 << (DP_ID_NO_DISTURB_ENABLE % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP9 预留DP1 */
|
||||
if (last->reserva_dp1 != cur->reserva_dp1)
|
||||
/* DP8 充电状态 */
|
||||
if (last->charge != cur->charge)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8));
|
||||
mask[DP_ID_CHARGE / 8] |= (1 << (DP_ID_CHARGE % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP10 预留DP2 */
|
||||
if (last->reserva_dp2 != cur->reserva_dp2)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP2 / 8] |= (1 << (DP_ID_RESERVA_DP2 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP11 预留DP3 */
|
||||
/* DP10 预留DP3 */
|
||||
if (last->reserva_dp3 != cur->reserva_dp3)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP3 / 8] |= (1 << (DP_ID_RESERVA_DP3 % 8));
|
||||
@@ -419,11 +389,9 @@ static uint8_t jbBuildDiffMask(const jb_data_point_t *last,
|
||||
/* 置全量掩码(所有可上报 DP)*/
|
||||
static void jbSetFullMask(uint8_t *mask)
|
||||
{
|
||||
memset(mask, 0xFF, DP_BITMAP_SIZE);
|
||||
if (DP_COUNT % 8)
|
||||
{
|
||||
mask[DP_BITMAP_SIZE - 1] &= (1 << (DP_COUNT % 8)) - 1;
|
||||
}
|
||||
/* DP IDs are sparse; list only the fields that can be reported/read. */
|
||||
mask[0] = 0xFB; /* 0, 1, 3, 4, 5, 6, 7 */
|
||||
mask[1] = 0x05; /* 8, 10 */
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
@@ -582,14 +550,25 @@ static void jbHandleControl(uint8_t *frame, uint16_t len)
|
||||
uint8_t *values = &frame[6 + DP_BITMAP_SIZE];
|
||||
uint16_t valLen = len - 7 - DP_BITMAP_SIZE;
|
||||
|
||||
/* Only writable fields are legal in a control frame. */
|
||||
if ((bitmap[0] & (uint8_t)~0xD7U) ||
|
||||
(bitmap[1] & (uint8_t)~0x04U))
|
||||
{
|
||||
jbSendAck(CMD_CONTROL_ACK, sn, JB_NOT_SUPPORT);
|
||||
return;
|
||||
}
|
||||
|
||||
jb_event_info_t info;
|
||||
jb_data_point_t ctrlData;
|
||||
memset(&ctrlData, 0, sizeof(ctrlData));
|
||||
jbUnpackDps(bitmap, values, valLen, &ctrlData, &info);
|
||||
|
||||
/* 分发给用户层;用户在回调中更新 gDevData */
|
||||
jbEventProcess(&info, &ctrlData);
|
||||
jbSendAck(CMD_CONTROL_ACK, sn, JB_OK);
|
||||
/* 分发给用户层;用户在回调中更新 gDevData。 */
|
||||
{
|
||||
int8_t result = jbEventProcess(&info, &ctrlData);
|
||||
jbSendAck(CMD_CONTROL_ACK, sn,
|
||||
(result < 0) ? JB_PARAM_ERR : (uint8_t)result);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 0x05 APP 读取请求 ── */
|
||||
@@ -632,10 +611,12 @@ static void jbHandleOtaNotify(uint8_t *frame, uint16_t len)
|
||||
uint32_t fwLength = jbReadU32BE(&frame[9]);
|
||||
uint32_t fwCrc32 = jbReadU32BE(&frame[13]);
|
||||
|
||||
/* 应答: 结果码 + 最大单包长度(2B)(协议原格式,3 字节) */
|
||||
int8_t otaRet = jbOnOtaNotify(fwVersion, fwLength, fwCrc32);
|
||||
jbOnOtaNotify(fwVersion, fwLength, fwCrc32);
|
||||
|
||||
/* 默认应答: 结果码 + 最大单包长度(2B) */
|
||||
/* maxDataLen 由 MCU 自身能力决定,填入 0x31 应答,BLE 据此分片 */
|
||||
uint8_t ack[3];
|
||||
ack[0] = (otaRet == 0) ? JB_OK : (uint8_t)otaRet;
|
||||
ack[0] = JB_OK;
|
||||
ack[1] = (uint8_t)(JB_OTA_MAX_PAYLOAD >> 8);
|
||||
ack[2] = (uint8_t)(JB_OTA_MAX_PAYLOAD & 0xFF);
|
||||
jbSendFrame(CMD_OTA_NOTIFY_ACK, sn, ack, 3);
|
||||
@@ -649,9 +630,8 @@ static void jbHandleOtaData(uint8_t *frame, uint16_t len)
|
||||
uint16_t totalShards = jbReadU16BE(&frame[8]);
|
||||
const uint8_t *pData = &frame[10];
|
||||
uint16_t dataLen = (len > 11) ? (len - 11) : 0;
|
||||
/* 先发本包 0x33 应答,再调用户回调满足「先回复、再重启」 */
|
||||
jbSendAck(CMD_OTA_DATA_ACK, sn, JB_OK);
|
||||
jbOnOtaData(pData, dataLen, shardIdx, totalShards);
|
||||
jbSendAck(CMD_OTA_DATA_ACK, sn, JB_OK);
|
||||
}
|
||||
|
||||
/* ── 0x36 BLE 通知停止 OTA ── */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* ================================================================
|
||||
* jb_protocol.h — 见宝 IOT 协议层(自动生成)
|
||||
* 设备: 门夹弹力绳 | DP 数: 12 | Bitmap: 2B
|
||||
* 协议版本: V1.0 | 生成时间: 2026-08-21 18:01:47
|
||||
* 设备: 猫猫捕猎罩 | DP 数: 10 | Bitmap: 2B
|
||||
* 协议版本: V1.0 | 生成时间: 2026-08-18 16:24:47
|
||||
*
|
||||
* 帧格式: [55 AA] [LEN_H LEN_L] [CMD] [SN] [payload...] [CKSUM]
|
||||
* LEN = CMD(1) + SN(1) + payload + CKSUM(1) = payload + 3
|
||||
@@ -26,7 +26,7 @@
|
||||
#define MAX_PACKAGE_LEN 128
|
||||
#define JB_OTA_MAX_PAYLOAD 96 /* OTA 单包 Payload 上限(Byte); 须 <= MAX_PACKAGE_LEN - 11(0x32 帧开销) */
|
||||
|
||||
#define DP_COUNT 12
|
||||
#define DP_COUNT 10
|
||||
#define DP_BITMAP_SIZE 2
|
||||
|
||||
#define SEND_MAX_TIME 2500 /* ACK 重传超时(ms);BLE Indication往返常需数百ms~1s,过短会误重传导致双应答 */
|
||||
@@ -34,14 +34,13 @@
|
||||
#define REPORT_DEBOUNCE 2000 /* 变化上报防抖时间(ms) */
|
||||
#define REPORT_PERIOD 600000 /* 定时全量上报周期(ms) */
|
||||
|
||||
/* Device identity: 取自 Excel 设备信息表的 ProdtCode / productCode。
|
||||
/* Device identity: change these values for the target product.
|
||||
* JB_CATEGORY_CODE: 必须 4 字符 ASCII,供 BLE 广播 prodcode 使用
|
||||
* JB_PRODUCT_CODE : 必须 6 字符 ASCII,供 BLE 广播 pcode 使用
|
||||
* 模板未填时回退占位 XXXX / XXXXXX(仍需用户修改)。
|
||||
*/
|
||||
#define JB_PROTOCOL_VERSION 0x0100 /* V1.0 */
|
||||
#define JB_CATEGORY_CODE "CBC2"
|
||||
#define JB_PRODUCT_CODE "PICBC2"
|
||||
#define JB_CATEGORY_CODE "CBC4"
|
||||
#define JB_PRODUCT_CODE "PICBC4"
|
||||
#define JB_DEVICE_SN 0x00
|
||||
#define JB_DEVICE_CAPABILITY 0ULL
|
||||
|
||||
@@ -93,14 +92,14 @@ typedef enum
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* BLE 工作状态位 (0x14)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
#define WS_CONNECTING (1 << 0) /* 配网中 */
|
||||
#define WS_PAIRING (1 << 0) /* 配网中 */
|
||||
#define WS_CONFIGURED (1 << 1) /* 已配网 */
|
||||
#define WS_RECONNECTING (1 << 2) /* 断线重连中 */
|
||||
#define WS_CLOUD_CONNECTED (1 << 3) /* 已连接到云 */
|
||||
#define WS_APP_ONLINE (1 << 4) /* App 在线 */
|
||||
#define WS_APP_DIRECT (1 << 5) /* App 直连 */
|
||||
#define WS_APP_ONLINE (1 << 4) /* APP 在线 */
|
||||
#define WS_APP_DIRECT (1 << 5) /* APP 直连 */
|
||||
#define WS_OTA_UPGRADING (1 << 6) /* 模组 OTA 升级中 */
|
||||
#define WS_RESERVED (1 << 7) /* 保留 */
|
||||
#define WS_RESERVED (1 << 7) /* Reserved */
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 设备能力位图 (0x02 Capability Bitmap, 8B 大端)
|
||||
@@ -120,31 +119,27 @@ typedef enum
|
||||
{
|
||||
DP_ID_POWER = 0, /* 开关 (bool, RW) */
|
||||
DP_ID_PLAY_MODE = 1, /* 自动模式 (enum, RW) */
|
||||
DP_ID_HAND_MODE = 2, /* 手动模式 (raw, WO) */
|
||||
DP_ID_CALIBRATION = 3, /* 绳索校准 (bool, WO) */
|
||||
DP_ID_NUMBERTURNS = 4, /* 绳索圈数 (uint8, WO) */
|
||||
DP_ID_ALM_LOW_BATTERY = 5, /* 低电量报警 (bool, RO) */
|
||||
DP_ID_BATTERY = 6, /* 电量上报 (uint8, RO) */
|
||||
DP_ID_CHARGE = 7, /* 充电状态 (enum, RO) */
|
||||
DP_ID_NO_DISTURB_ENABLE = 8, /* 勿扰模式开关 (raw, RW) */
|
||||
DP_ID_RESERVA_DP1 = 9, /* 预留DP1 (uint32, RW) */
|
||||
DP_ID_RESERVA_DP2 = 10, /* 预留DP2 (uint32, RW) */
|
||||
DP_ID_RESERVA_DP3 = 11, /* 预留DP3 (uint32, RW) */
|
||||
DP_ID_HAND_MODE = 2, /* 手动模式 (enum, WO) */
|
||||
DP_ID_ALM_LOW_BATTERY = 3, /* 低电量报警 (bool, RO) */
|
||||
DP_ID_BEEP_TRIG = 4, /* 声音开关 (bool, RW) */
|
||||
DP_ID_BATTERY = 5, /* 电量上报 (uint8, RO) */
|
||||
DP_ID_SHAKE_WAKE = 6, /* 震动触发开机 (bool, RW) */
|
||||
DP_ID_NO_DISTURB_ENABLE = 7, /* 勿扰模式开关 (raw, RW) */
|
||||
DP_ID_CHARGE = 8, /* 充电状态 (enum, RO) */
|
||||
DP_ID_RESERVA_DP3 = 10, /* 预留DP3 (uint32, RW) */
|
||||
DP_ID_MAX
|
||||
} dp_id_t;
|
||||
|
||||
/* DP 数据长度(字节) */
|
||||
#define DP_LEN_POWER 1
|
||||
#define DP_LEN_PLAY_MODE 1
|
||||
#define DP_LEN_HAND_MODE 2
|
||||
#define DP_LEN_CALIBRATION 1
|
||||
#define DP_LEN_NUMBERTURNS 1
|
||||
#define DP_LEN_HAND_MODE 1
|
||||
#define DP_LEN_ALM_LOW_BATTERY 1
|
||||
#define DP_LEN_BEEP_TRIG 1
|
||||
#define DP_LEN_BATTERY 1
|
||||
#define DP_LEN_CHARGE 1
|
||||
#define DP_LEN_SHAKE_WAKE 1
|
||||
#define DP_LEN_NO_DISTURB_ENABLE 13
|
||||
#define DP_LEN_RESERVA_DP1 4
|
||||
#define DP_LEN_RESERVA_DP2 4
|
||||
#define DP_LEN_CHARGE 1
|
||||
#define DP_LEN_RESERVA_DP3 4
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
@@ -154,17 +149,25 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
PLAY_MODE_0 = 0, /* 停止复位 */
|
||||
PLAY_MODE_1 = 1, /* 弹力伪装 */
|
||||
PLAY_MODE_2 = 2, /* 飞鸟俯冲 */
|
||||
PLAY_MODE_3 = 3, /* 云阶小陀螺 */
|
||||
PLAY_MODE_4 = 4, /* 起伏攻防战 */
|
||||
PLAY_MODE_5 = 5, /* 微风拂动 */
|
||||
PLAY_MODE_6 = 6, /* 闪电快闪 */
|
||||
PLAY_MODE_1 = 1, /* 上部慢速往复 */
|
||||
PLAY_MODE_2 = 2, /* 上部快速往复 */
|
||||
PLAY_MODE_3 = 3, /* 上部间歇、下部均匀摇摆 */
|
||||
PLAY_MODE_4 = 4, /* 上部慢探、下部随机摇摆 */
|
||||
PLAY_MODE_5 = 5, /* 上下电机随机组合 */
|
||||
} PLAY_MODE_t;
|
||||
|
||||
/* 手动模式 */
|
||||
typedef enum
|
||||
{
|
||||
HAND_MODE_0 = 0, /* 停止 */
|
||||
HAND_MODE_1 = 1, /* 上部电机探出 */
|
||||
HAND_MODE_2 = 2, /* 下部电机探出 */
|
||||
} HAND_MODE_t;
|
||||
|
||||
/* 充电状态 */
|
||||
typedef enum
|
||||
{
|
||||
CHARGE_0 = 0, /* 不支持充电 */
|
||||
CHARGE_1 = 1, /* 充电中 */
|
||||
CHARGE_2 = 2, /* 未充电 */
|
||||
} CHARGE_t;
|
||||
@@ -178,16 +181,14 @@ typedef struct
|
||||
{
|
||||
uint8_t power; /* DP0 开关 */
|
||||
uint8_t play_mode; /* DP1 自动模式 */
|
||||
uint8_t hand_mode[2]; /* DP2 手动模式 */
|
||||
uint8_t calibration; /* DP3 绳索校准 */
|
||||
uint8_t numberturns; /* DP4 绳索圈数 */
|
||||
uint8_t alm_low_battery;/* DP5 低电量报警 */
|
||||
uint8_t battery; /* DP6 电量上报 */
|
||||
uint8_t charge; /* DP7 充电状态 */
|
||||
uint8_t no_disturb_enable[13];/* DP8 勿扰模式开关 */
|
||||
uint32_t reserva_dp1; /* DP9 预留DP1 */
|
||||
uint32_t reserva_dp2; /* DP10 预留DP2 */
|
||||
uint32_t reserva_dp3; /* DP11 预留DP3 */
|
||||
uint8_t hand_mode; /* DP2 手动模式 */
|
||||
uint8_t alm_low_battery;/* DP3 低电量报警 */
|
||||
uint8_t beep_trig; /* DP4 声音开关 */
|
||||
uint8_t battery; /* DP5 电量上报 */
|
||||
uint8_t shake_wake; /* DP6 震动触发开机 */
|
||||
uint8_t no_disturb_enable[13];/* DP7 勿扰模式开关 */
|
||||
uint8_t charge; /* DP8 充电状态 */
|
||||
uint32_t reserva_dp3; /* DP10 预留DP3 */
|
||||
} jb_data_point_t;
|
||||
|
||||
/* 控制事件信息 */
|
||||
@@ -260,7 +261,7 @@ extern void ble_send_data(uint8_t *data, uint16_t len);
|
||||
int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *data);
|
||||
|
||||
/* BLE → MCU 事件回调 */
|
||||
int8_t jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32); /* 0x30, 返回0=接受,非0=拒绝码 */
|
||||
void jbOnOtaNotify(uint32_t fwVersion, uint32_t fwLength, uint32_t fwCrc32); /* 0x30 */
|
||||
void jbOnOtaData(const uint8_t *data, uint16_t len,
|
||||
uint16_t shardIdx, uint16_t totalShards); /* 0x32 */
|
||||
void jbOnOtaStop(void); /* 0x36 / 0x38 停止 */
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/******************************************************************************
|
||||
* @file usr_jb_main.c
|
||||
* @brief CBC2 业务组合根:只做“先后调用谁、谁通知谁”,不含具体业务算法
|
||||
* @brief CBC1 猫猫捕猎罩业务组合根:只做调用编排,不含具体业务算法
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.27
|
||||
* @version V2.2.0
|
||||
* @version V2.3.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.24, cyWu, 收口未接线模块;DP2 仅第 1 字节点动 1s
|
||||
@@ -16,11 +16,13 @@
|
||||
* - V2.1.0, 2026.08.26, cyWu, 电机运转期间长期占用 1ms 硬件定时器中断,
|
||||
* 配网连接后与 BLE 协议栈抢时序触发看门狗复位;
|
||||
* 换向死区判定改用阈值检查而非精确计时,
|
||||
* 取消专门的 1ms 高频档,全系统统一 20ms 节拍,
|
||||
* 取消专门的 1ms 高频档,全系统统一 10ms 节拍,
|
||||
* 只保留"能不能休眠"这一个维度
|
||||
* - V2.2.0, 2026.08.27, cyWu, app_led_init() 提前到 app_boot_wait_key() 之前,
|
||||
* 开机 3s/5s/拒绝开机低电闪直接用灯效事件表,
|
||||
* 不用再各自摸裸 GPIO 手搓一份闪烁定时
|
||||
* - V2.3.0, 2026.08.31, cyWu, DP0=0 待机允许系统轻睡;震动检测并入现有
|
||||
* 10ms 业务节拍,避免重复定时器唤醒
|
||||
*
|
||||
* @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData。
|
||||
* usr_timer_loop 由 BLE 回调,勿再注册第二份。
|
||||
@@ -45,6 +47,7 @@
|
||||
#include "usr_le_product.h"
|
||||
#include "usr_le_api.h"
|
||||
#include "bsp_hw.h"
|
||||
#include "board_pin.h"
|
||||
#include "app_power.h"
|
||||
#include "app_pair.h"
|
||||
#include "app_boot.h"
|
||||
@@ -69,7 +72,7 @@ const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = {
|
||||
JB_PRODUCT_CODE[3], JB_PRODUCT_CODE[4], JB_PRODUCT_CODE[5]
|
||||
};
|
||||
|
||||
#define USR_TIMER_IDLE_MS 20 /**< 全局统一节拍:按键消抖、换向死区判定都按它对齐 */
|
||||
#define USR_TIMER_IDLE_MS BOARD_SHAKE_POLL_MS /**< 按键、换向和震动检测共用同一节拍 */
|
||||
|
||||
/**
|
||||
* @brief 业务节拍档位
|
||||
@@ -78,7 +81,7 @@ const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = {
|
||||
* 单独开过 1ms 硬件定时器中断,配网连接后跟 BLE 协议栈自己的收发/ACK
|
||||
* 处理抢时序,长时间叠加导致看门狗复位。
|
||||
* 换向死区的判定是"距上次换向是否已过 switch_ms"这种阈值检查,不是
|
||||
* 精确计时:用 20ms 节拍去查,查到时实际已经过了不少于 20ms,天然
|
||||
* 精确计时:用 10ms 节拍去查,查到时实际已经过了不少于 10ms,天然
|
||||
* 满足"至少 1ms"的死区要求,只会让保护更充分,不会失效。所以死区
|
||||
* 不需要专门的 1ms 精度,可以和其它业务共用同一个节拍。
|
||||
*/
|
||||
@@ -108,11 +111,20 @@ static void usr_on_power_evt(AppPowerEvt_t evt)
|
||||
{
|
||||
switch (evt) {
|
||||
case APP_POWER_EVT_USB_IN:
|
||||
app_function_stop_all();
|
||||
log_info("usb in, motor stop\n");
|
||||
if (!app_led_is_ota()) {
|
||||
app_pair_stop();
|
||||
usr_var.usr_goto_pair = 0;
|
||||
app_function_soft_off();
|
||||
log_info("usb in, charge standby\n");
|
||||
} else {
|
||||
app_function_stop_all();
|
||||
log_info("usb in, keep ota\n");
|
||||
}
|
||||
break;
|
||||
case APP_POWER_EVT_USB_OUT:
|
||||
app_function_soft_off();
|
||||
if (!app_led_is_ota()) {
|
||||
app_function_soft_off();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -161,6 +173,8 @@ static void usr_poweroff_finalize_hook(void)
|
||||
*/
|
||||
static UsrTickMode_t usr_timer_pick_mode(void)
|
||||
{
|
||||
/* DP0=0 仍保留低优先级业务节拍、BLE 和外部唤醒源,不需要禁止轻睡。
|
||||
* 定时器到期会正常唤醒 CPU,按键/震动/USB 检测功能不会因此停掉。 */
|
||||
if (bsp_key_is_pressed() || app_power_poweroff_pending()
|
||||
|| app_mode_get_active() || bsp_motor_is_busy()
|
||||
|| app_function_is_hand_busy()) {
|
||||
@@ -194,7 +208,7 @@ static void usr_timer_rearm(UsrTickMode_t mode)
|
||||
* 只有这一种,没有"任务线程 + 禁睡"的组合可选。
|
||||
* 代价是这里执行的每一行代码都会占用中断时间,跟 BLE 协议栈自己的
|
||||
* 收发中断抢时序;这次的看门狗复位就是因为这条路径长期以 1kHz
|
||||
* 触发。现在虽然降到了 20ms 一拍,但仍要守住底线:
|
||||
* 触发。现在虽然降到了 10ms 一拍,但仍要守住底线:
|
||||
* - 禁止阻塞等待(信号量/循环等 ACK 之类)
|
||||
* - 禁止耗时操作(flash 擦写、大块 memcpy、长循环)
|
||||
* 按键短按/长按走到的 usr_on_key_short/long、jbSendReqWithAck
|
||||
@@ -291,6 +305,7 @@ void usr_jb_init(void)
|
||||
user_key_init();
|
||||
user_key_lock_if_held();
|
||||
app_function_power_on_silent();
|
||||
usr_on_power_evt(app_power_tick_1ms(0));
|
||||
|
||||
usr_timer_rearm(USR_TICK_IDLE);
|
||||
log_info("timer idle %ums, sleep ok\n", (unsigned)USR_TIMER_IDLE_MS);
|
||||
|
||||
Reference in New Issue
Block a user