1、将固件改造为 BLE 串口模组:新增 usr_mcu_bridge,移除旧 jb_proto
2、通过 UART 55AA 对接外部 MCU,完成身份/透传/配对/心跳;桥接忙时注册 LP target 拦住休眠,空闲可进 SLEEP,兼顾串口可靠与低功耗。
This commit is contained in:
@@ -174,8 +174,7 @@
|
||||
<Add directory="apps/usr_le_code" />
|
||||
<Add directory="apps/usr_le_code/thirdpart/mjson" />
|
||||
<Add directory="apps/usr_le_code/thirdpart" />
|
||||
<Add directory="apps/usr_jb_proto/Protocol" />
|
||||
<Add directory="apps/usr_jb_proto/Utils" />
|
||||
<Add directory="apps/usr_mcu_bridge" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-flto" />
|
||||
@@ -758,25 +757,23 @@
|
||||
<Unit filename="apps/earphone/version.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="apps/usr_jb_proto/Protocol/jb_product.c">
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_bridge.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="apps/usr_jb_proto/Protocol/jb_product.h" />
|
||||
<Unit filename="apps/usr_jb_proto/Protocol/jb_protocol.c">
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_bridge.h" />
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_cmd.h" />
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_frame.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="apps/usr_jb_proto/Protocol/jb_protocol.h" />
|
||||
<Unit filename="apps/usr_jb_proto/Utils/jb_common.c">
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_frame.h" />
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_uart.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="apps/usr_jb_proto/Utils/jb_common.h" />
|
||||
<Unit filename="apps/usr_jb_proto/Utils/jb_ringbuffer.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="apps/usr_jb_proto/Utils/jb_ringbuffer.h" />
|
||||
<Unit filename="apps/usr_jb_proto/usr_jb_main.c">
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_uart.h" />
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_util.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="apps/usr_mcu_bridge/mcu_util.h" />
|
||||
<Unit filename="apps/usr_le_code/ble_proto.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
|
||||
@@ -248,8 +248,7 @@ INCLUDES := \
|
||||
-Iapps/usr_le_code \
|
||||
-Iapps/usr_le_code/thirdpart \
|
||||
-Iapps/usr_le_code/thirdpart/mjson \
|
||||
-Iapps/usr_jb_proto/Protocol \
|
||||
-Iapps/usr_jb_proto/Utils \
|
||||
-Iapps/usr_mcu_bridge \
|
||||
-I$(SYS_INC_DIR) \
|
||||
|
||||
|
||||
@@ -614,11 +613,10 @@ c_SRC_FILES := \
|
||||
cpu/br28/tws_audio.c \
|
||||
cpu/br28/uart_dev.c \
|
||||
cpu/br28/umidigi_chargestore.c \
|
||||
apps/usr_jb_proto/Protocol/jb_product.c \
|
||||
apps/usr_jb_proto/Protocol/jb_protocol.c \
|
||||
apps/usr_jb_proto/Utils/jb_common.c \
|
||||
apps/usr_jb_proto/Utils/jb_ringbuffer.c \
|
||||
apps/usr_jb_proto/usr_jb_main.c \
|
||||
apps/usr_mcu_bridge/mcu_bridge.c \
|
||||
apps/usr_mcu_bridge/mcu_frame.c \
|
||||
apps/usr_mcu_bridge/mcu_uart.c \
|
||||
apps/usr_mcu_bridge/mcu_util.c \
|
||||
apps/usr_le_code/ble_proto.c \
|
||||
apps/usr_le_code/bleproto.c \
|
||||
apps/usr_le_code/bleproto_packer.c \
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "bt_profile_cfg.h"
|
||||
#include "dev_manager/dev_manager.h"
|
||||
#include "update_loader_download.h"
|
||||
#include "mcu_bridge.h"
|
||||
|
||||
#ifndef CONFIG_MEDIA_NEW_ENABLE
|
||||
#ifndef CONFIG_MEDIA_DEVELOP_ENABLE
|
||||
@@ -254,7 +255,6 @@ const struct rtc_dev_platform_data rtc_init_data=
|
||||
};
|
||||
#endif // 0
|
||||
extern void bt_osc_offset_ext_updata(s32 offset);
|
||||
extern void usr_jb_init();
|
||||
void app_main()
|
||||
{
|
||||
int update = 0;
|
||||
@@ -292,7 +292,7 @@ void app_main()
|
||||
}
|
||||
|
||||
app_var_init();
|
||||
usr_jb_init();
|
||||
mcu_bridge_init();
|
||||
|
||||
#if TCFG_MC_BIAS_AUTO_ADJUST
|
||||
mc_trim_init(update);
|
||||
@@ -325,13 +325,11 @@ void app_main()
|
||||
}
|
||||
|
||||
/*
|
||||
* 上电强制进入配对模式:
|
||||
* 1) usr_goto_pair=1:后续 usr_ble_adv_init() 走绑定广播(encode4bind),不走重连广播
|
||||
* 2) usr_clear_pair_info_noreset():清 VM 中三元组,保证 paired_flag=0
|
||||
* 注意:须在 BLE 协议栈调用 usr_ble_adv_init() 之前设置;此处不清复位,避免上电死循环复位
|
||||
* BLE+MCU:上电不强制配网。
|
||||
* - 未配网:等 MCU 0x10 后再绑定广播
|
||||
* - 已配网:身份就绪后由 usr_ble_adv_init() 发回连广播
|
||||
*/
|
||||
usr_var.usr_goto_pair = 1;
|
||||
usr_clear_pair_info_noreset();
|
||||
usr_var.usr_goto_pair = 0;
|
||||
|
||||
ui_manage_init();
|
||||
ui_update_status(STATUS_POWERON);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
//*********************************************************************************//
|
||||
#define TCFG_UART0_ENABLE ENABLE_THIS_MOUDLE //串口打印模块使能
|
||||
#define TCFG_UART0_RX_PORT NO_CONFIG_PORT //串口接收脚配置(用于打印可以选择NO_CONFIG_PORT)
|
||||
#define TCFG_UART0_TX_PORT IO_PORTC_05 //串口发送脚配置
|
||||
#define TCFG_UART0_TX_PORT IO_PORTC_08 //串口发送脚配置
|
||||
#define TCFG_UART0_BAUDRATE 1000000 //串口波特率配置
|
||||
|
||||
//*********************************************************************************//
|
||||
@@ -733,6 +733,7 @@ DAC硬件上的连接方式,可选的配置:
|
||||
//*********************************************************************************//
|
||||
#define TCFG_LOWPOWER_POWER_SEL PWR_LDO15//PWR_LDO15 //电源模式设置,可选DCDC和LDO
|
||||
#define TCFG_LOWPOWER_BTOSC_DISABLE 0 //低功耗模式下BTOSC是否保持
|
||||
/* MCU 串口方案:配合 mcu_bridge LP target,忙时保持唤醒、空闲可进低功耗 */
|
||||
#define TCFG_LOWPOWER_LOWPOWER_SEL SLEEP_EN//DEEP_SLEEP_EN//SLEEP_EN//DEEP_SLEEP_EN //低功耗使能,蓝牙&&系统空闲可进入低功耗
|
||||
#define TCFG_LOWPOWER_VDDIOM_LEVEL VDDIOM_VOL_28V //vddiom等级
|
||||
#define TCFG_LOWPOWER_OSC_TYPE OSC_TYPE_LRC //低功耗晶振类型,btosc/lrc
|
||||
|
||||
@@ -6,9 +6,21 @@ typedef struct _USR_VAR {
|
||||
u8 usr_plan_cnt ;
|
||||
u8 usr_intterupt_reinit_falg ;
|
||||
u8 usr_goto_updata ;
|
||||
/**
|
||||
* 是否处于“主动配网”流程(RAM 运行态,掉电丢失)
|
||||
* 0:正常态。未配网则不广播;已配网则发回连广播
|
||||
* 1:MCU 下发 0x10 / 调用 usr_goto_pair_mode() 后置位,强制发绑定广播
|
||||
* 配网成功(AUTHSETUP 写对)或配网超时后应清 0
|
||||
*/
|
||||
u8 usr_goto_pair ;
|
||||
u8 usr_can_pair ;
|
||||
u8 usr_ota_succ_flag ;
|
||||
/**
|
||||
* 广播数据是否需要刷新到协议栈(一次性触发位)
|
||||
* 1:usr_ble_adv_updata() 会把 muti_adv_data 写入栈并 enable 广播,然后清 0
|
||||
* 0:本周期不更新广播数据
|
||||
* 注意:置 1 不等于“一直在广播”,只是请求“应用一次新的广播包”
|
||||
*/
|
||||
u8 usr_adv_flag ;
|
||||
u8 usr_low_power_flag ;
|
||||
u8 usr_allow_to_sleep_cnt;
|
||||
|
||||
@@ -97,7 +97,7 @@ const char log_tag_const_e_APP_POWER AT(.LOG_TAG_CONST) = TRUE;
|
||||
|
||||
const char log_tag_const_v_APP AT(.LOG_TAG_CONST) = FALSE;
|
||||
const char log_tag_const_i_APP AT(.LOG_TAG_CONST) = TRUE;
|
||||
const char log_tag_const_d_APP AT(.LOG_TAG_CONST) = FALSE;
|
||||
const char log_tag_const_d_APP AT(.LOG_TAG_CONST) = TRUE; /* MCU_BR 等 APP 标签的 log_debug 开关 */
|
||||
const char log_tag_const_w_APP AT(.LOG_TAG_CONST) = TRUE;
|
||||
const char log_tag_const_e_APP AT(.LOG_TAG_CONST) = TRUE;
|
||||
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
/* ================================================================
|
||||
* 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 接入即可。 */
|
||||
@@ -1,55 +0,0 @@
|
||||
/* ================================================================
|
||||
* jb_product.h — 用户层头文件(自动生成)
|
||||
* 设备: 侠客猫激光 | 生成时间: 2026-07-31 17:08:51
|
||||
*
|
||||
* 声明用户需实现的函数。数据结构定义见 jb_protocol.h
|
||||
* ================================================================
|
||||
*/
|
||||
|
||||
#ifndef _JB_PRODUCT_H
|
||||
#define _JB_PRODUCT_H
|
||||
|
||||
#include "jb_protocol.h"
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 硬件配置(SOC SDK 已提供定时器,无需 UART 波特率配置)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
#define TIMER_PERIOD_MS 1
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 版本管理
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
/* MCU software version: Vmajor.minor.patch */
|
||||
#define JB_MCU_SW_VERSION_MAJOR 1
|
||||
#define JB_MCU_SW_VERSION_MINOR 0
|
||||
#define JB_MCU_SW_VERSION_PATCH 0
|
||||
|
||||
/* MCU hardware version: Vmajor.minor.patch */
|
||||
#define JB_MCU_HW_VERSION_MAJOR 1
|
||||
#define JB_MCU_HW_VERSION_MINOR 0
|
||||
#define JB_MCU_HW_VERSION_PATCH 0
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 用户 API
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* 全局设备数据 — 协议层直接读写该变量 */
|
||||
extern jb_data_point_t gDevData;
|
||||
|
||||
/* ==================== 用户必须实现 ============================== */
|
||||
void userInit(void); /* DP 默认值与外设初始化 */
|
||||
void userHandle(void); /* 用户数据采集 */
|
||||
void jbTimerIrq(void); /* Call from 1ms timer ISR */
|
||||
|
||||
/* =========== 协议回调(声明见 jb_protocol.h)================== */
|
||||
/* int8_t jbEventProcess(...); // 0x03 控制事件 */
|
||||
/* void jbOnOtaNotify(...); // 0x30 OTA 请求 */
|
||||
/* void jbOnOtaData(...); // 0x32 OTA 数据 */
|
||||
/* void jbOnOtaStop(); // 0x36/0x38 停止 OTA */
|
||||
/* void jbOnAck(...); // 任意请求 ACK(结果) */
|
||||
|
||||
/* ============= 主动请求(声明见 jb_protocol.h)================ */
|
||||
/* int32_t jbNotifyOtaStop(); // 0x38 通知 BLE 停止 OTA */
|
||||
/* int32_t jbSendOtaResult(...); // 0x34 OTA 结果 */
|
||||
|
||||
#endif /* _JB_PRODUCT_H */
|
||||
@@ -1,749 +0,0 @@
|
||||
/* ================================================================
|
||||
* jb_protocol.c — 见宝 IOT 协议实现(自动生成)
|
||||
* 设备: 侠客猫激光 | 生成时间: 2026-07-31 17:08:51
|
||||
* ================================================================
|
||||
*/
|
||||
|
||||
#include "jb_protocol.h"
|
||||
#include "jb_product.h"
|
||||
#include "jb_ringbuffer.h"
|
||||
#include "jb_common.h"
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 全局实例
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
jb_protocol_t jbProtocol;
|
||||
static jb_ringbuffer_t rb; /* UART 接收缓冲区 */
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbInit — 协议层初始化
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
void jbInit(void)
|
||||
{
|
||||
memset(&jbProtocol, 0, sizeof(jb_protocol_t));
|
||||
jbRbInit(&rb);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbPutData — UART 中断将数据压入环形缓冲区
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
int32_t jbPutData(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (!buf)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
jbRbPush(&rb, buf[i]);
|
||||
}
|
||||
return (int32_t)len;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbSendFrame — 组装协议帧并经 ble_send_data 发送(SOC 无串口)
|
||||
* 返回帧总长度,< 0 表示出错
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static int32_t jbSendFrame(uint8_t cmd, uint8_t sn,
|
||||
const uint8_t *payload, uint16_t pLen)
|
||||
{
|
||||
uint8_t buf[MAX_PACKAGE_LEN];
|
||||
uint16_t lenField = pLen + 3; /* CMD + SN + payload + CKSUM */
|
||||
uint16_t total = lenField + 4;
|
||||
|
||||
if (total > MAX_PACKAGE_LEN)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 55 AA | LEN_H LEN_L | CMD | SN | payload | CKSUM */
|
||||
buf[0] = PKT_HEAD_0;
|
||||
buf[1] = PKT_HEAD_1;
|
||||
jbWriteU16BE(&buf[2], lenField);
|
||||
buf[4] = cmd;
|
||||
buf[5] = sn;
|
||||
if (payload && pLen > 0)
|
||||
{
|
||||
memcpy(&buf[6], payload, pLen);
|
||||
}
|
||||
buf[total - 1] = jbChecksum(buf, total);
|
||||
|
||||
ble_send_data(buf, total);
|
||||
return (int32_t)total;
|
||||
}
|
||||
|
||||
/* 发送单字节结果应答 */
|
||||
static void jbSendAck(uint8_t cmd, uint8_t sn, uint8_t result)
|
||||
{
|
||||
jbSendFrame(cmd, sn, &result, 1);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbGetOnePacket — 从环形缓冲区提取完整帧
|
||||
* 返回: 0 = 成功, 1 = 需要更多数据, -2 = 校验和错误
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static int8_t jbGetOnePacket(uint8_t *out, uint16_t *outLen)
|
||||
{
|
||||
static uint8_t state = 0;
|
||||
static uint16_t expect = 0;
|
||||
static uint16_t idx = 0;
|
||||
static uint8_t prev = 0;
|
||||
|
||||
while (jbRbAvailable(&rb))
|
||||
{
|
||||
uint8_t b = jbRbPop(&rb);
|
||||
|
||||
if (state == 0)
|
||||
{
|
||||
/* 搜索同步头 55 AA */
|
||||
if (prev == PKT_HEAD_0 && b == PKT_HEAD_1)
|
||||
{
|
||||
out[0] = PKT_HEAD_0;
|
||||
out[1] = PKT_HEAD_1;
|
||||
idx = 2;
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
else if (state == 1)
|
||||
{
|
||||
/* 接收 LEN(2B) + CMD + SN */
|
||||
out[idx++] = b;
|
||||
if (idx == 6)
|
||||
{
|
||||
expect = 4 + jbReadU16BE(&out[2]);
|
||||
if (expect > MAX_PACKAGE_LEN || expect < 7)
|
||||
{
|
||||
state = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 接收剩余数据 */
|
||||
out[idx++] = b;
|
||||
if (idx >= expect)
|
||||
{
|
||||
state = 0;
|
||||
if (out[expect - 1] == jbChecksum(out, expect))
|
||||
{
|
||||
*outLen = expect;
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
prev = b;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbPackDps — dataPoint → outBuf[bitmap | values]
|
||||
* mask 指定要打包的 DP(bit 序号 = DP ID)
|
||||
* 返回 outBuf 总字节数(bitmap + values)
|
||||
* 仅打包 RO / RW 方向的 DP
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static uint16_t jbPackDps(const jb_data_point_t *dp,
|
||||
const uint8_t *mask, uint8_t *outBuf)
|
||||
{
|
||||
uint8_t *bitmap = outBuf;
|
||||
uint8_t *out = outBuf + DP_BITMAP_SIZE;
|
||||
uint16_t valIdx = 0;
|
||||
memset(bitmap, 0, DP_BITMAP_SIZE);
|
||||
|
||||
/* DP0 开关 (bool, 1B, RW) */
|
||||
if (mask[DP_ID_POWER / 8] & (1 << (DP_ID_POWER % 8)))
|
||||
{
|
||||
bitmap[DP_ID_POWER / 8] |= (1 << (DP_ID_POWER % 8));
|
||||
out[valIdx++] = dp->power ? 1 : 0;
|
||||
}
|
||||
/* DP1 自动模式 (enum, 1B, RW) */
|
||||
if (mask[DP_ID_PLAY_MODE / 8] & (1 << (DP_ID_PLAY_MODE % 8)))
|
||||
{
|
||||
bitmap[DP_ID_PLAY_MODE / 8] |= (1 << (DP_ID_PLAY_MODE % 8));
|
||||
out[valIdx++] = (uint8_t)dp->play_mode;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
/* DP6 震动触发开机 (bool, 1B, RW) */
|
||||
if (mask[DP_ID_SHAKE_WAKE / 8] & (1 << (DP_ID_SHAKE_WAKE % 8)))
|
||||
{
|
||||
bitmap[DP_ID_SHAKE_WAKE / 8] |= (1 << (DP_ID_SHAKE_WAKE % 8));
|
||||
out[valIdx++] = dp->shake_wake ? 1 : 0;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
/* DP8 预留DP1 (uint32, 4B, RW) */
|
||||
if (mask[DP_ID_RESERVA_DP1 / 8] & (1 << (DP_ID_RESERVA_DP1 % 8)))
|
||||
{
|
||||
bitmap[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8));
|
||||
jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp1);
|
||||
valIdx += 4;
|
||||
}
|
||||
/* DP9 预留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;
|
||||
}
|
||||
/* 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));
|
||||
jbWriteU32BE(&out[valIdx], (uint32_t)dp->reserva_dp3);
|
||||
valIdx += 4;
|
||||
}
|
||||
|
||||
return DP_BITMAP_SIZE + valIdx;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbUnpackDps — bitmap+values → dataPoint + event_info
|
||||
* 仅解包 WO / RW 方向的 DP
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static void jbUnpackDps(const uint8_t *bitmap, const uint8_t *values,
|
||||
uint16_t valLen, jb_data_point_t *dp,
|
||||
jb_event_info_t *info)
|
||||
{
|
||||
uint16_t valIdx = 0;
|
||||
if (info)
|
||||
{
|
||||
info->count = 0;
|
||||
}
|
||||
|
||||
/* DP0 开关 (bool, 1B, RW) */
|
||||
if (bitmap[DP_ID_POWER / 8] & (1 << (DP_ID_POWER % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
{
|
||||
dp->power = (values[valIdx++] != 0);
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_POWER;
|
||||
}
|
||||
}
|
||||
/* DP1 自动模式 (enum, 1B, RW) */
|
||||
if (bitmap[DP_ID_PLAY_MODE / 8] & (1 << (DP_ID_PLAY_MODE % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
{
|
||||
dp->play_mode = values[valIdx++];
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_PLAY_MODE;
|
||||
}
|
||||
}
|
||||
/* DP2 手动模式 (enum, 1B, WO) */
|
||||
if (bitmap[DP_ID_HAND_MODE / 8] & (1 << (DP_ID_HAND_MODE % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
{
|
||||
dp->hand_mode = values[valIdx++];
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_HAND_MODE;
|
||||
}
|
||||
}
|
||||
/* DP4 声音开关 (bool, 1B, RW) */
|
||||
if (bitmap[DP_ID_BEEP_TRIG / 8] & (1 << (DP_ID_BEEP_TRIG % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
{
|
||||
dp->beep_trig = (values[valIdx++] != 0);
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_BEEP_TRIG;
|
||||
}
|
||||
}
|
||||
/* DP6 震动触发开机 (bool, 1B, RW) */
|
||||
if (bitmap[DP_ID_SHAKE_WAKE / 8] & (1 << (DP_ID_SHAKE_WAKE % 8)))
|
||||
{
|
||||
if (valIdx < valLen)
|
||||
{
|
||||
dp->shake_wake = (values[valIdx++] != 0);
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_SHAKE_WAKE;
|
||||
}
|
||||
}
|
||||
/* DP7 勿扰模式开关 (raw, 13B, RW) */
|
||||
if (bitmap[DP_ID_NO_DISTURB_ENABLE / 8] & (1 << (DP_ID_NO_DISTURB_ENABLE % 8)))
|
||||
{
|
||||
if (valIdx + 13 <= valLen)
|
||||
{
|
||||
memcpy(dp->no_disturb_enable, &values[valIdx], 13);
|
||||
valIdx += 13;
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_NO_DISTURB_ENABLE;
|
||||
}
|
||||
}
|
||||
/* DP8 预留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;
|
||||
}
|
||||
}
|
||||
/* DP9 预留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;
|
||||
}
|
||||
}
|
||||
/* DP10 预留DP3 (uint32, 4B, RW) */
|
||||
if (bitmap[DP_ID_RESERVA_DP3 / 8] & (1 << (DP_ID_RESERVA_DP3 % 8)))
|
||||
{
|
||||
if (valIdx + 4 <= valLen)
|
||||
{
|
||||
dp->reserva_dp3 = (uint32_t)jbReadU32BE(&values[valIdx]);
|
||||
valIdx += 4;
|
||||
}
|
||||
if (info && info->count < DP_ID_MAX)
|
||||
{
|
||||
info->dp_ids[info->count++] = DP_ID_RESERVA_DP3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbBuildDiffMask — 比较上次与当前值,为变化的可上报 DP 置 mask 位
|
||||
* 返回: 1 = 有 DP 发生变化, 0 = 全部未变化
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static uint8_t jbBuildDiffMask(const jb_data_point_t *last,
|
||||
const jb_data_point_t *cur,
|
||||
uint8_t *mask)
|
||||
{
|
||||
uint8_t hasChange = 0;
|
||||
memset(mask, 0, DP_BITMAP_SIZE);
|
||||
|
||||
/* DP0 开关 */
|
||||
if (last->power != cur->power)
|
||||
{
|
||||
mask[DP_ID_POWER / 8] |= (1 << (DP_ID_POWER % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP1 自动模式 */
|
||||
if (last->play_mode != cur->play_mode)
|
||||
{
|
||||
mask[DP_ID_PLAY_MODE / 8] |= (1 << (DP_ID_PLAY_MODE % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
/* DP6 震动触发开机 */
|
||||
if (last->shake_wake != cur->shake_wake)
|
||||
{
|
||||
mask[DP_ID_SHAKE_WAKE / 8] |= (1 << (DP_ID_SHAKE_WAKE % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
/* DP8 预留DP1 */
|
||||
if (last->reserva_dp1 != cur->reserva_dp1)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP1 / 8] |= (1 << (DP_ID_RESERVA_DP1 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP9 预留DP2 */
|
||||
if (last->reserva_dp2 != cur->reserva_dp2)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP2 / 8] |= (1 << (DP_ID_RESERVA_DP2 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
/* DP10 预留DP3 */
|
||||
if (last->reserva_dp3 != cur->reserva_dp3)
|
||||
{
|
||||
mask[DP_ID_RESERVA_DP3 / 8] |= (1 << (DP_ID_RESERVA_DP3 % 8));
|
||||
hasChange = 1;
|
||||
}
|
||||
|
||||
return hasChange;
|
||||
}
|
||||
|
||||
/* 置全量掩码(所有可上报 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbSendReqWithAck — 发送请求帧并登记 ACK 重传
|
||||
*
|
||||
* 与 jbSendFrame 不同,本函数把完整帧缓存到 waitAck.buf,
|
||||
* 并启动 ACK 等待。主动上报 / OTA 等网关应答均走 REPORTCMD_V2,
|
||||
* 由 jbReportAckCheck() 清除等待;若 SEND_MAX_TIME 内未收到,
|
||||
* jbAckRetry() 自动重传,最多 SEND_MAX_NUM 次。
|
||||
* 返回 ble_send_data 结果(<0 出错)。
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static int32_t jbSendReqWithAck(uint8_t cmd, uint8_t sn,
|
||||
const uint8_t *payload, uint16_t pLen)
|
||||
{
|
||||
uint16_t lenField = pLen + 3; /* CMD + SN + payload + CKSUM */
|
||||
uint16_t total = lenField + 4; /* + 55 AA + LEN(2) */
|
||||
|
||||
if (total > MAX_PACKAGE_LEN)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t buf[MAX_PACKAGE_LEN];
|
||||
buf[0] = PKT_HEAD_0;
|
||||
buf[1] = PKT_HEAD_1;
|
||||
jbWriteU16BE(&buf[2], lenField);
|
||||
buf[4] = cmd;
|
||||
buf[5] = sn;
|
||||
if (payload && pLen > 0)
|
||||
{
|
||||
memcpy(&buf[6], payload, pLen);
|
||||
}
|
||||
buf[total - 1] = jbChecksum(buf, total);
|
||||
|
||||
/* 缓存整帧,供超时重传 */
|
||||
memcpy(jbProtocol.waitAck.buf, buf, total);
|
||||
jbProtocol.waitAck.len = total;
|
||||
jbProtocol.waitAck.active = 1;
|
||||
jbProtocol.waitAck.sn = sn;
|
||||
jbProtocol.waitAck.retry = 0;
|
||||
jbProtocol.waitAck.sendTime = jbGetTimerCount();
|
||||
|
||||
ble_send_data(buf, total);
|
||||
return (int32_t)total;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbAckRetry — ACK 超时重传
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static void jbAckRetry(void)
|
||||
{
|
||||
if (!jbProtocol.waitAck.active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (jbProtocol.waitAck.retry >= SEND_MAX_NUM)
|
||||
{
|
||||
memset(&jbProtocol.waitAck, 0, sizeof(jb_wait_ack_t));
|
||||
return;
|
||||
}
|
||||
if (jbGetTimerCount() - jbProtocol.waitAck.sendTime > SEND_MAX_TIME)
|
||||
{
|
||||
ble_send_data(jbProtocol.waitAck.buf, jbProtocol.waitAck.len);
|
||||
jbProtocol.waitAck.retry++;
|
||||
jbProtocol.waitAck.sendTime = jbGetTimerCount();
|
||||
}
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbReportAckCheck — 网关应答确认(主动上报 / OTA 共用)
|
||||
*
|
||||
* 网关通过 REPORTCMD_V2 回传(非 55AA)。成功条件:
|
||||
* cmd == 0
|
||||
* gateway_int_cnt == 1
|
||||
* gateway_int0 == 0
|
||||
* 满足则清除 waitAck,停止重传,并回调 jbOnAck(wait_cmd, 0)。
|
||||
*
|
||||
* 返回: 1=成功并清除等待; 0=未命中/条件不符。
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
int8_t jbReportAckCheck(uint16_t cmd, uint8_t gateway_int_cnt, int32_t gateway_int0)
|
||||
{
|
||||
if (!jbProtocol.waitAck.active)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (cmd == 0 && gateway_int_cnt == 1 && gateway_int0 == 0)
|
||||
{
|
||||
uint8_t wait_cmd = jbProtocol.waitAck.buf[4];
|
||||
memset(&jbProtocol.waitAck, 0, sizeof(jb_wait_ack_t));
|
||||
jbOnAck(wait_cmd, 0); /* result=0 表示应答成功 */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbSendReport — 发送主动上报 (0x07)
|
||||
*
|
||||
* mask 指定本次上报包含哪些 DP:
|
||||
* - 差分掩码(来自 jbBuildDiffMask) → 仅上报变化的 DP
|
||||
* - 全量掩码(来自 jbSetFullMask) → 定时全量同步
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static void jbSendReport(jb_data_point_t *data, const uint8_t *mask)
|
||||
{
|
||||
uint8_t payload[MAX_PACKAGE_LEN];
|
||||
uint16_t plen = jbPackDps(data, mask, payload);
|
||||
uint8_t sn = jbProtocol.sn++;
|
||||
jbSendReqWithAck(CMD_REPORT, sn, payload, plen);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbReportPolicy — 变化上报(差分) + 定时上报(全量)
|
||||
*
|
||||
* 策略:
|
||||
* 1. DP 发生变化 → 仅上报变化的 DP(差分掩码)
|
||||
* 2. 每隔 REPORT_PERIOD ms → 上报全部可上报 DP(全量同步)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
static void jbReportPolicy(jb_data_point_t *data)
|
||||
{
|
||||
uint32_t now = jbGetTimerCount();
|
||||
uint8_t diffMask[DP_BITMAP_SIZE];
|
||||
|
||||
/* ── 1. 变化上报(差分) ── */
|
||||
uint8_t hasChange = jbBuildDiffMask(&jbProtocol.lastData, data, diffMask);
|
||||
if (hasChange && !jbProtocol.waitAck.active &&
|
||||
(now - jbProtocol.lastChangeTime > REPORT_DEBOUNCE))
|
||||
{
|
||||
jbSendReport(data, diffMask);
|
||||
memcpy(&jbProtocol.lastData, data, sizeof(jb_data_point_t));
|
||||
jbProtocol.lastChangeTime = now;
|
||||
jbProtocol.lastReportTime = now;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ── 2. 定时全量上报 ── */
|
||||
if (!jbProtocol.waitAck.active &&
|
||||
(now - jbProtocol.lastReportTime > REPORT_PERIOD))
|
||||
{
|
||||
uint8_t fullMask[DP_BITMAP_SIZE];
|
||||
jbSetFullMask(fullMask);
|
||||
jbSendReport(data, fullMask);
|
||||
memcpy(&jbProtocol.lastData, data, sizeof(jb_data_point_t));
|
||||
jbProtocol.lastReportTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 命令处理函数(BLE → MCU 下行帧)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* ── 0x03 APP 下发控制 ── */
|
||||
static void jbHandleControl(uint8_t *frame, uint16_t len)
|
||||
{
|
||||
uint8_t sn = frame[5];
|
||||
uint8_t *bitmap = &frame[6];
|
||||
uint8_t *values = &frame[6 + DP_BITMAP_SIZE];
|
||||
uint16_t valLen = len - 7 - DP_BITMAP_SIZE;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* ── 0x05 APP 读取请求 ── */
|
||||
static void jbHandleRead(uint8_t *frame, uint16_t len,
|
||||
jb_data_point_t *data)
|
||||
{
|
||||
uint8_t sn = frame[5];
|
||||
uint8_t *reqBitmap = &frame[6];
|
||||
|
||||
uint8_t mask[DP_BITMAP_SIZE];
|
||||
memcpy(mask, reqBitmap, DP_BITMAP_SIZE);
|
||||
|
||||
/* bitmap 全 1(=0xFF...) 表示读取全部 DP */
|
||||
uint8_t allOnes = 1;
|
||||
for (int i = 0; i < DP_BITMAP_SIZE; i++)
|
||||
{
|
||||
if (mask[i] != 0xFF)
|
||||
{
|
||||
allOnes = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allOnes)
|
||||
{
|
||||
jbSetFullMask(mask);
|
||||
}
|
||||
|
||||
uint8_t payload[MAX_PACKAGE_LEN];
|
||||
uint16_t plen = jbPackDps(data, mask, payload);
|
||||
jbSendFrame(CMD_READ_ACK, sn, payload, plen);
|
||||
}
|
||||
|
||||
/* ── 0x30 OTA 升级请求 ── */
|
||||
static void jbHandleOtaNotify(uint8_t *frame, uint16_t len)
|
||||
{
|
||||
uint8_t sn = frame[5];
|
||||
uint32_t fwVersion = ((uint32_t)frame[6] << 16)
|
||||
| ((uint32_t)frame[7] << 8)
|
||||
| frame[8];
|
||||
uint32_t fwLength = jbReadU32BE(&frame[9]);
|
||||
uint32_t fwCrc32 = jbReadU32BE(&frame[13]);
|
||||
|
||||
jbOnOtaNotify(fwVersion, fwLength, fwCrc32);
|
||||
|
||||
/* 默认应答: 结果码 + 最大单包长度(2B) */
|
||||
/* maxDataLen 由 MCU 自身能力决定,填入 0x31 应答,BLE 据此分片 */
|
||||
uint8_t ack[3];
|
||||
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);
|
||||
}
|
||||
|
||||
/* ── 0x32 OTA 数据(含分片序号)── */
|
||||
static void jbHandleOtaData(uint8_t *frame, uint16_t len)
|
||||
{
|
||||
uint8_t sn = frame[5];
|
||||
uint16_t shardIdx = jbReadU16BE(&frame[6]);
|
||||
uint16_t totalShards = jbReadU16BE(&frame[8]);
|
||||
const uint8_t *pData = &frame[10];
|
||||
uint16_t dataLen = (len > 11) ? (len - 11) : 0;
|
||||
jbOnOtaData(pData, dataLen, shardIdx, totalShards);
|
||||
jbSendAck(CMD_OTA_DATA_ACK, sn, JB_OK);
|
||||
}
|
||||
|
||||
/* ── 0x36 BLE 通知停止 OTA ── */
|
||||
static void jbHandleOtaStop(uint8_t *frame, uint16_t len)
|
||||
{
|
||||
uint8_t sn = frame[5];
|
||||
jbOnOtaStop();
|
||||
jbSendAck(CMD_OTA_STOP_BLE_ACK, sn, JB_OK);
|
||||
}
|
||||
|
||||
/* 0x38 通知 BLE 停止 OTA(MCU 主动,等待 ACK 重传)*/
|
||||
int32_t jbNotifyOtaStop(void)
|
||||
{
|
||||
uint8_t sn = jbProtocol.sn++;
|
||||
return jbSendReqWithAck(CMD_OTA_STOP_MCU, sn, NULL, 0);
|
||||
}
|
||||
|
||||
/* 0x34 OTA 升级完成(result + MCU 版本 3B,等待 ACK 重传)*/
|
||||
int32_t jbSendOtaResult(uint8_t result, const uint8_t *mcuVersion)
|
||||
{
|
||||
uint8_t sn = jbProtocol.sn++;
|
||||
uint8_t payload[4];
|
||||
payload[0] = result;
|
||||
if (mcuVersion)
|
||||
{
|
||||
memcpy(&payload[1], mcuVersion, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&payload[1], 0, 3);
|
||||
}
|
||||
return jbSendReqWithAck(CMD_OTA_COMPLETE, sn, payload, 4);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* jbProtocolHandle — 协议主循环(在 while(1) 中调用)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
int32_t jbProtocolHandle(jb_data_point_t *data)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ACK 超时重传 */
|
||||
jbAckRetry();
|
||||
|
||||
/* 提取一帧 */
|
||||
uint16_t pktLen = 0;
|
||||
int8_t ret = jbGetOnePacket(jbProtocol.rxBuf, &pktLen);
|
||||
uint8_t cmd;
|
||||
if (ret == 0)
|
||||
{
|
||||
cmd = jbProtocol.rxBuf[4];
|
||||
|
||||
/* 按命令码统一分发 BLE → MCU 的所有帧(含 MCU 主动请求的应答)*/
|
||||
switch (cmd)
|
||||
{
|
||||
/* ── APP-BLE 数据 ── */
|
||||
case CMD_CONTROL:
|
||||
jbHandleControl(jbProtocol.rxBuf, pktLen);
|
||||
break;
|
||||
case CMD_READ:
|
||||
jbHandleRead(jbProtocol.rxBuf, pktLen, data);
|
||||
break;
|
||||
/* ── BLE-MCU OTA ── */
|
||||
case CMD_OTA_NOTIFY:
|
||||
jbHandleOtaNotify(jbProtocol.rxBuf, pktLen);
|
||||
break;
|
||||
case CMD_OTA_DATA:
|
||||
jbHandleOtaData(jbProtocol.rxBuf, pktLen);
|
||||
break;
|
||||
case CMD_OTA_STOP_BLE:
|
||||
jbHandleOtaStop(jbProtocol.rxBuf, pktLen);
|
||||
break;
|
||||
/* 主动上报 / OTA 完成&停止 的网关应答均走 REPORTCMD_V2 → jbReportAckCheck */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
jbReportPolicy(data);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
/* ================================================================
|
||||
* jb_protocol.h — 见宝 IOT 协议层(自动生成)
|
||||
* 设备: 侠客猫激光 | DP 数: 11 | Bitmap: 2B
|
||||
* 协议版本: V1.0 | 生成时间: 2026-07-31 17:08:51
|
||||
*
|
||||
* 帧格式: [55 AA] [LEN_H LEN_L] [CMD] [SN] [payload...] [CKSUM]
|
||||
* LEN = CMD(1) + SN(1) + payload + CKSUM(1) = payload + 3
|
||||
* CKSUM = sum(LEN_H .. payload_last) & 0xFF
|
||||
* Bitmap = 每个 DP 占 1 bit,bit 序号 = DP ID(0 起始)
|
||||
* Values = 按 bitmap 置位顺序排列,每个 DP 占完整 byte_length
|
||||
* ================================================================
|
||||
*/
|
||||
|
||||
#ifndef _JB_PROTOCOL_H
|
||||
#define _JB_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 协议常量
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
#define PKT_HEAD_0 0x55
|
||||
#define PKT_HEAD_1 0xAA
|
||||
#define MAX_PACKAGE_LEN 128
|
||||
#define JB_OTA_MAX_PAYLOAD 96 /* OTA 单包 Payload 上限(Byte); 须 <= MAX_PACKAGE_LEN - 11(0x32 帧开销) */
|
||||
|
||||
#define DP_COUNT 11
|
||||
#define DP_BITMAP_SIZE 2
|
||||
|
||||
#define SEND_MAX_TIME 2500 /* ACK 重传超时(ms);BLE Indication往返常需数百ms~1s,过短会误重传导致双应答 */
|
||||
#define SEND_MAX_NUM 3 /* 最大重传次数 */
|
||||
#define REPORT_DEBOUNCE 2000 /* 变化上报防抖时间(ms) */
|
||||
#define REPORT_PERIOD 600000 /* 定时全量上报周期(ms) */
|
||||
|
||||
/* Device identity: change these values for the target product.
|
||||
* JB_CATEGORY_CODE: 必须 4 字符 ASCII,供 BLE 广播 prodcode 使用
|
||||
* JB_PRODUCT_CODE : 必须 6 字符 ASCII,供 BLE 广播 pcode 使用
|
||||
*/
|
||||
#define JB_PROTOCOL_VERSION 0x0100 /* V1.0 */
|
||||
#define JB_CATEGORY_CODE "CBC0"
|
||||
#define JB_PRODUCT_CODE "PICBC0"
|
||||
#define JB_DEVICE_SN 0x00
|
||||
#define JB_DEVICE_CAPABILITY 0ULL
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 命令码(见《MCU方案接入协议通讯文档》)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
typedef enum
|
||||
{
|
||||
/* ── APP-BLE 数据(6) ── */
|
||||
CMD_CONTROL = 0x03, /* APP/BLE → MCU: 下发控制 */
|
||||
CMD_CONTROL_ACK = 0x04, /* MCU → APP/BLE: 控制应答 */
|
||||
CMD_READ = 0x05, /* APP/BLE → MCU: 读取请求 */
|
||||
CMD_READ_ACK = 0x06, /* MCU → APP/BLE: 读取应答 */
|
||||
CMD_REPORT = 0x07, /* MCU → APP/BLE: 主动上报 */
|
||||
CMD_REPORT_ACK = 0x08, /* APP/BLE → MCU: 上报应答 */
|
||||
/* ── OTA(10) ── */
|
||||
CMD_OTA_NOTIFY = 0x30, /* BLE → MCU: OTA 升级请求 */
|
||||
CMD_OTA_NOTIFY_ACK = 0x31, /* MCU → BLE: OTA 应答(含MaxLen) */
|
||||
CMD_OTA_DATA = 0x32, /* BLE → MCU: OTA 数据 */
|
||||
CMD_OTA_DATA_ACK = 0x33, /* MCU → BLE: OTA 数据应答 */
|
||||
CMD_OTA_COMPLETE = 0x34, /* MCU → BLE: OTA 完成 */
|
||||
CMD_OTA_COMPLETE_ACK = 0x35, /* BLE → MCU: OTA 完成应答 */
|
||||
CMD_OTA_STOP_BLE = 0x36, /* BLE → MCU: 停止 OTA */
|
||||
CMD_OTA_STOP_BLE_ACK = 0x37, /* MCU → BLE: 停止应答 */
|
||||
CMD_OTA_STOP_MCU = 0x38, /* MCU → BLE: 通知停止 OTA */
|
||||
CMD_OTA_STOP_MCU_ACK = 0x39, /* BLE → MCU: 停止应答 */
|
||||
} jb_cmd_t;
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 结果码
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
typedef enum
|
||||
{
|
||||
JB_OK = 0x00,
|
||||
JB_PARAM_ERR = 0x01,
|
||||
JB_BUSY = 0x02,
|
||||
JB_NOT_SUPPORT = 0x03,
|
||||
JB_CRC_ERR = 0x04,
|
||||
JB_FAIL = 0x05,
|
||||
/* ── OTA 专用错误码 ── */
|
||||
JB_OTA_NO_NEED = 0x20, /* 无需升级(版本一致) */
|
||||
JB_OTA_VER_LOW = 0x21, /* OTA 版本低于当前版本 */
|
||||
JB_OTA_SPACE_ERR = 0x22, /* Flash 空间不足 */
|
||||
JB_OTA_STATE_ERR = 0x23, /* OTA 状态错误 */
|
||||
JB_OTA_FILE_ERR = 0x24, /* OTA 文件检验失败 */
|
||||
JB_OTA_FAIL = 0x25, /* 升级失败 */
|
||||
} jb_result_t;
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* BLE 工作状态位 (0x14)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
#define WS_CONFIGURED (1 << 0) /* 已配网 */
|
||||
#define WS_INTERNET (1 << 1) /* 已连外网 */
|
||||
#define WS_APP_ONLINE (1 << 2) /* App 在线 */
|
||||
#define WS_BLE_CONNECTED (1 << 3) /* 手机 BLE 已连接 */
|
||||
#define WS_OTA_UPGRADING (1 << 4) /* OTA 升级中 */
|
||||
#define WS_PAIRING_MODE (1 << 5) /* 配对模式激活 */
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 设备能力位图 (0x02 Capability Bitmap, 8B 大端)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
#define CAP_BLE_OTA (1ULL << 0) /* BLE OTA */
|
||||
#define CAP_MCU_OTA (1ULL << 1) /* MCU OTA */
|
||||
#define CAP_APP_DIRECT (1ULL << 2) /* APP 直连 BLE */
|
||||
#define CAP_IPC_GATEWAY (1ULL << 3) /* IPC 网关连接 */
|
||||
#define CAP_PRODUCTION (1ULL << 4) /* 产测模式 */
|
||||
#define CAP_PARAM_CFG (1ULL << 5) /* 参数配置 */
|
||||
#define CAP_LOG (1ULL << 6) /* 日志功能 */
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 身份信息 (0x02) / MCU 信息 (0x41)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* DP ID 枚举(从 Excel 自动生成)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
typedef enum
|
||||
{
|
||||
DP_ID_POWER = 0, /* 开关 (bool, RW) */
|
||||
DP_ID_PLAY_MODE = 1, /* 自动模式 (enum, 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_RESERVA_DP1 = 8, /* 预留DP1 (uint32, RW) */
|
||||
DP_ID_RESERVA_DP2 = 9, /* 预留DP2 (uint32, RW) */
|
||||
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 1
|
||||
#define DP_LEN_ALM_LOW_BATTERY 1
|
||||
#define DP_LEN_BEEP_TRIG 1
|
||||
#define DP_LEN_BATTERY 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_RESERVA_DP3 4
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* DP 枚举值定义
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
/* 自动模式 */
|
||||
typedef enum
|
||||
{
|
||||
PLAY_MODE_0 = 0, /* 关 */
|
||||
PLAY_MODE_1 = 1, /* mode1 */
|
||||
PLAY_MODE_2 = 2, /* mode2 */
|
||||
PLAY_MODE_3 = 3, /* mode3 */
|
||||
PLAY_MODE_4 = 4, /* mode4 */
|
||||
} PLAY_MODE_t;
|
||||
|
||||
/* 手动模式 */
|
||||
typedef enum
|
||||
{
|
||||
HAND_MODE_0 = 0, /* 关 */
|
||||
HAND_MODE_1 = 1, /* 顺时针 */
|
||||
HAND_MODE_2 = 2, /* 逆时针 */
|
||||
} HAND_MODE_t;
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 数据结构
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* 数据点 — 所有 DP 的当前值 */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t power; /* DP0 开关 */
|
||||
uint8_t play_mode; /* DP1 自动模式 */
|
||||
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 勿扰模式开关 */
|
||||
uint32_t reserva_dp1; /* DP8 预留DP1 */
|
||||
uint32_t reserva_dp2; /* DP9 预留DP2 */
|
||||
uint32_t reserva_dp3; /* DP10 预留DP3 */
|
||||
} jb_data_point_t;
|
||||
|
||||
/* 控制事件信息 */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t count;
|
||||
uint8_t dp_ids[DP_ID_MAX];
|
||||
} jb_event_info_t;
|
||||
|
||||
/* ACK 等待 / 重传管理器 */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t active; /* 是否有等待中的请求 */
|
||||
uint8_t sn; /* 帧序列号 */
|
||||
uint8_t retry;
|
||||
uint8_t buf[MAX_PACKAGE_LEN];
|
||||
uint16_t len;
|
||||
uint32_t sendTime;
|
||||
} jb_wait_ack_t;
|
||||
|
||||
/* 协议全局状态 */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t sn; /* 设备 SN 计数器 */
|
||||
uint8_t rxBuf[MAX_PACKAGE_LEN];
|
||||
jb_wait_ack_t waitAck; /* ACK 重传管理器 */
|
||||
jb_data_point_t lastData; /* 上次上报快照 */
|
||||
uint32_t lastReportTime; /* 上次上报时刻 */
|
||||
uint32_t lastChangeTime; /* 上次变化上报时刻 */
|
||||
} jb_protocol_t;
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 全局实例
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
extern jb_protocol_t jbProtocol;
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 协议层 API(自动生成)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
void jbInit(void);
|
||||
int32_t jbPutData(uint8_t *buf, uint32_t len);
|
||||
|
||||
int32_t jbNotifyOtaStop(void);
|
||||
int32_t jbSendOtaResult(uint8_t result, const uint8_t *mcuVersion);
|
||||
|
||||
int32_t jbProtocolHandle(jb_data_point_t *data);
|
||||
|
||||
/*
|
||||
* 网关应答确认(主动上报 / OTA 共用,REPORTCMD_V2,非 55AA)
|
||||
* cmd: ble_proto 包 cmd
|
||||
* gateway_int_cnt: gateway int 个数
|
||||
* gateway_int0: gateway_int[0]
|
||||
* 成功条件: cmd==0 && gateway_int_cnt==1 && gateway_int0==0
|
||||
* 返回: 1=成功并清除等待; 0=未命中/条件不符
|
||||
*/
|
||||
int8_t jbReportAckCheck(uint16_t cmd, uint8_t gateway_int_cnt, int32_t gateway_int0);
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 硬件抽象(用户实现)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
uint32_t jbGetTimerCount(void); /* ms 计数器(定时器由 SOC SDK 提供) */
|
||||
|
||||
/* 发送接口:经 SOC SDK 提供的 BLE 发送封装(由用户/SDK 实现,非本生成代码范围)*/
|
||||
extern void ble_send_data(uint8_t *data, uint16_t len);
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 用户回调(用户实现)
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
/* 0x03 APP 下发控制事件 */
|
||||
int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *data);
|
||||
|
||||
/* BLE → MCU 事件回调 */
|
||||
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 停止 */
|
||||
|
||||
/* MCU → BLE 应答回调(收到 BLE 应答时触发)*/
|
||||
void jbOnAck(uint8_t cmd, uint8_t result); /* 任意请求 ACK(结果) */
|
||||
|
||||
#endif /* _JB_PROTOCOL_H */
|
||||
@@ -1,69 +0,0 @@
|
||||
/* ================================================================
|
||||
* jb_common.c — 工具函数实现
|
||||
* ================================================================
|
||||
*/
|
||||
#include "jb_common.h"
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 校验和
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
uint8_t jbChecksum(const uint8_t *frame, uint16_t totalLen)
|
||||
{
|
||||
if (!frame || totalLen < 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint16_t sum = 0;
|
||||
/* 从 LEN_H(buf[2]) 累加到最后一个 payload 字节(buf[totalLen-2]) */
|
||||
for (uint16_t i = 2; i < totalLen - 1; i++)
|
||||
{
|
||||
sum += frame[i];
|
||||
}
|
||||
return (uint8_t)(sum & 0xFF);
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 大端序读写
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
uint16_t jbReadU16BE(const uint8_t *buf)
|
||||
{
|
||||
if (!buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return ((uint16_t)buf[0] << 8) | buf[1];
|
||||
}
|
||||
|
||||
uint32_t jbReadU32BE(const uint8_t *buf)
|
||||
{
|
||||
if (!buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return ((uint32_t)buf[0] << 24)
|
||||
| ((uint32_t)buf[1] << 16)
|
||||
| ((uint32_t)buf[2] << 8)
|
||||
| buf[3];
|
||||
}
|
||||
|
||||
void jbWriteU16BE(uint8_t *buf, uint16_t val)
|
||||
{
|
||||
if (!buf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
buf[0] = (uint8_t)(val >> 8);
|
||||
buf[1] = (uint8_t)(val & 0xFF);
|
||||
}
|
||||
|
||||
void jbWriteU32BE(uint8_t *buf, uint32_t val)
|
||||
{
|
||||
if (!buf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)(val & 0xFF);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/* ================================================================
|
||||
* jb_common.h — 工具函数(校验和、大端序转换)
|
||||
*
|
||||
* 说明: 见宝协议采用大端序(Big-Endian)。
|
||||
* 多字节值(uint16/uint32)按高位在前传输。
|
||||
* ================================================================
|
||||
*/
|
||||
#ifndef _JB_COMMON_H
|
||||
#define _JB_COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 校验和
|
||||
* sum(LEN_H, LEN_L, CMD, SN, ...payload_last) & 0xFF
|
||||
* buf[0]=55, buf[1]=AA,累加范围从 buf[2] 到 buf[totalLen-2]
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
uint8_t jbChecksum(const uint8_t *frame, uint16_t totalLen);
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════
|
||||
* 大端序转换
|
||||
* ════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* 从字节数组读取 uint16(大端序)*/
|
||||
uint16_t jbReadU16BE(const uint8_t *buf);
|
||||
|
||||
/* 从字节数组读取 uint32(大端序)*/
|
||||
uint32_t jbReadU32BE(const uint8_t *buf);
|
||||
|
||||
/* 将 uint16 写入字节数组(大端序)*/
|
||||
void jbWriteU16BE(uint8_t *buf, uint16_t val);
|
||||
|
||||
/* 将 uint32 写入字节数组(大端序)*/
|
||||
void jbWriteU32BE(uint8_t *buf, uint32_t val);
|
||||
|
||||
#endif /* _JB_COMMON_H */
|
||||
@@ -1,75 +0,0 @@
|
||||
/* ================================================================
|
||||
* jb_ringbuffer.c — 环形缓冲区实现
|
||||
* ================================================================
|
||||
*/
|
||||
#include "jb_ringbuffer.h"
|
||||
|
||||
/* ── 初始化 ── */
|
||||
void jbRbInit(jb_ringbuffer_t *rb)
|
||||
{
|
||||
if (!rb)
|
||||
{
|
||||
return;
|
||||
}
|
||||
rb->write = rb->read = rb->count = 0;
|
||||
}
|
||||
|
||||
/* ── 压入一个字节 ── */
|
||||
void jbRbPush(jb_ringbuffer_t *rb, uint8_t byte)
|
||||
{
|
||||
if (!rb)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (rb->count >= JB_RB_CAPACITY)
|
||||
{
|
||||
return; /* 已满 — 丢弃 */
|
||||
}
|
||||
rb->buf[rb->write] = byte;
|
||||
rb->write = (rb->write + 1) % JB_RB_CAPACITY;
|
||||
rb->count++;
|
||||
}
|
||||
|
||||
/* ── 弹出一个字节 ── */
|
||||
uint8_t jbRbPop(jb_ringbuffer_t *rb)
|
||||
{
|
||||
if (!rb || rb->count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint8_t byte = rb->buf[rb->read];
|
||||
rb->read = (rb->read + 1) % JB_RB_CAPACITY;
|
||||
rb->count--;
|
||||
return byte;
|
||||
}
|
||||
|
||||
/* ── 查看指定偏移字节(不消费)── */
|
||||
uint8_t jbRbPeek(const jb_ringbuffer_t *rb, uint16_t offset)
|
||||
{
|
||||
if (!rb || offset >= rb->count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint16_t idx = (rb->read + offset) % JB_RB_CAPACITY;
|
||||
return rb->buf[idx];
|
||||
}
|
||||
|
||||
/* ── 可读字节数 ── */
|
||||
uint16_t jbRbAvailable(const jb_ringbuffer_t *rb)
|
||||
{
|
||||
if (!rb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return rb->count;
|
||||
}
|
||||
|
||||
/* ── 清空缓冲区 ── */
|
||||
void jbRbClear(jb_ringbuffer_t *rb)
|
||||
{
|
||||
if (!rb)
|
||||
{
|
||||
return;
|
||||
}
|
||||
rb->write = rb->read = rb->count = 0;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/* ================================================================
|
||||
* jb_ringbuffer.h — 环形缓冲区(UART 接收)
|
||||
* ================================================================
|
||||
*/
|
||||
#ifndef _JB_RINGBUFFER_H
|
||||
#define _JB_RINGBUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* 缓冲区配置 */
|
||||
#define JB_RB_CAPACITY 256 /* 缓冲区容量(2 的幂可优化取模运算)*/
|
||||
|
||||
/* 环形缓冲区实例 */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t buf[JB_RB_CAPACITY];
|
||||
uint16_t write; /* 写索引 */
|
||||
uint16_t read; /* 读索引 */
|
||||
uint16_t count; /* 已用字节数 */
|
||||
} jb_ringbuffer_t;
|
||||
|
||||
void jbRbInit(jb_ringbuffer_t *rb);
|
||||
void jbRbPush(jb_ringbuffer_t *rb, uint8_t byte);
|
||||
uint8_t jbRbPop(jb_ringbuffer_t *rb);
|
||||
uint8_t jbRbPeek(const jb_ringbuffer_t *rb, uint16_t offset);
|
||||
uint16_t jbRbAvailable(const jb_ringbuffer_t *rb);
|
||||
void jbRbClear(jb_ringbuffer_t *rb);
|
||||
|
||||
#endif /* _JB_RINGBUFFER_H */
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "app_main.h"
|
||||
#include "app_task.h"
|
||||
#include "user_cfg.h"
|
||||
#include "vm.h"
|
||||
#include "sys_time.h"
|
||||
|
||||
#include "jb_protocol.h"
|
||||
#include "jb_product.h"
|
||||
#include "jb_ringbuffer.h"
|
||||
#include "jb_common.h"
|
||||
#include "usr_le_product.h"
|
||||
|
||||
/* 向 usr_le_code 提供产品身份(换产品只改 jb_protocol.h 宏即可) */
|
||||
const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN] = {
|
||||
JB_CATEGORY_CODE[0], JB_CATEGORY_CODE[1],
|
||||
JB_CATEGORY_CODE[2], JB_CATEGORY_CODE[3]
|
||||
};
|
||||
const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = {
|
||||
JB_PRODUCT_CODE[0], JB_PRODUCT_CODE[1], JB_PRODUCT_CODE[2],
|
||||
JB_PRODUCT_CODE[3], JB_PRODUCT_CODE[4], JB_PRODUCT_CODE[5]
|
||||
};
|
||||
|
||||
void usr_timer_1_ms();
|
||||
static int jb_timer_id=0;
|
||||
|
||||
void usr_jb_init()
|
||||
{
|
||||
jbInit();
|
||||
userInit();
|
||||
if(jb_timer_id==0)jb_timer_id = sys_s_hi_timer_add(NULL, usr_timer_1_ms, TIMER_PERIOD_MS);
|
||||
}
|
||||
|
||||
void usr_timer_1_ms()
|
||||
{
|
||||
jbTimerIrq();
|
||||
}
|
||||
|
||||
void usr_jb_le_recieve_data(u8* data,u16 len)
|
||||
{
|
||||
jbPutData(data,len);
|
||||
}
|
||||
|
||||
void usr_timer_loop()///500ms
|
||||
{
|
||||
userHandle();
|
||||
jbProtocolHandle(&gDevData);
|
||||
}
|
||||
@@ -403,6 +403,11 @@ typedef struct bleproto_authsetup_req {
|
||||
uint8_t gwmac[6]; ///< 主控mac地址, 设备需要保存
|
||||
char devid[36 + 1]; ///< 主控分配的子设备id, 设备需要保存
|
||||
char authcode[32 + 1]; ///< 主控分配的子设备认证码, 设备需要保存
|
||||
/**
|
||||
* paired_flag:设备是否已完成配网(持久化在 VM)
|
||||
* 0 = 未配网:默认不广播,除非 usr_goto_pair=1(绑定广播)
|
||||
* 1 = 已配网:断连后发回连广播;AUTHSETUP 写三元组成功后置 1
|
||||
*/
|
||||
uint8_t paired_flag;
|
||||
// clang-format on
|
||||
} bleproto_authsetup_req_t;
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
#include "bleproto.h"
|
||||
#include "bleproto_api.h"
|
||||
#include "usr_le_product.h"
|
||||
#include "mcu_bridge.h"
|
||||
#define LOG_TAG_CONST APP
|
||||
#define LOG_TAG "[APP]"
|
||||
#define LOG_TAG "[LE_ADV]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
@@ -24,6 +25,27 @@
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
/******************************************************************************
|
||||
* 广播相关三个标志(务必区分):
|
||||
*
|
||||
* 1) usr_auth_data.paired_flag —— 配网结果(存 VM,掉电保持)
|
||||
* - 0:未配网
|
||||
* - 1:已配网(三元组已保存)
|
||||
*
|
||||
* 2) usr_var.usr_goto_pair —— 是否主动进入配网流程(RAM,掉电丢失)
|
||||
* - 0:非配网流程
|
||||
* - 1:MCU 0x10 / usr_goto_pair_mode() 触发,发【绑定广播】
|
||||
*
|
||||
* 3) usr_var.usr_adv_flag —— 广播内容是否需要刷新到协议栈(一次性)
|
||||
* - 1:usr_ble_adv_updata() 会重新 set adv data 并 enable
|
||||
* - 0:本周期不刷新
|
||||
*
|
||||
* 决策表(身份就绪后):
|
||||
* usr_goto_pair==1 → 绑定广播(重新配网)
|
||||
* paired_flag==0 且未配网 → 不广播
|
||||
* paired_flag==1 → 回连广播
|
||||
******************************************************************************/
|
||||
|
||||
extern u8 muti_adv_data[31];//={0};
|
||||
extern u8 muti_adv_data_len;
|
||||
|
||||
@@ -46,6 +68,10 @@ extern u8 usr_get_work_status();
|
||||
extern void usr_printf_sta();
|
||||
extern int muti_make_set_adv_data_updata();
|
||||
|
||||
/**
|
||||
* @brief 从 VM 读取配对信息到 usr_auth_data
|
||||
* @note 失败则清零,并将 paired_flag 置 0 写回
|
||||
*/
|
||||
void usr_get_pair_info()
|
||||
{
|
||||
int ret = 0xffff;
|
||||
@@ -53,46 +79,69 @@ void usr_get_pair_info()
|
||||
if(ret<=0)
|
||||
{
|
||||
memset(&usr_auth_data,0x00,sizeof(usr_auth_data));
|
||||
usr_auth_data.paired_flag=0;
|
||||
usr_auth_data.paired_flag=0; /* 未配网 */
|
||||
syscfg_write(CFG_USER_PAIR_INFO, (u8 *)&usr_auth_data, sizeof(usr_auth_data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 标记已配网并保存三元组到 VM
|
||||
* @note AUTHSETUP 成功后调用,paired_flag = 1
|
||||
*/
|
||||
void usr_write_pair_info()
|
||||
{
|
||||
usr_auth_data.paired_flag=1;
|
||||
usr_auth_data.paired_flag=1; /* 已配网 */
|
||||
syscfg_write(CFG_USER_PAIR_INFO, (u8 *)&usr_auth_data, sizeof(usr_auth_data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清除配对信息并延时复位
|
||||
*/
|
||||
void usr_clear_pair_info()
|
||||
{
|
||||
printf("usr_clear_pair_info\n");
|
||||
memset(&usr_auth_data,0x00,sizeof(usr_auth_data));
|
||||
usr_auth_data.paired_flag=0;
|
||||
usr_auth_data.paired_flag=0; /* 回到未配网 */
|
||||
syscfg_write(CFG_USER_PAIR_INFO, (u8 *)&usr_auth_data, sizeof(usr_auth_data));
|
||||
mcu_bridge_on_pair_cleared();
|
||||
sys_timeout_add(NULL,cpu_reset,600);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清除配对信息但不复位(用于重新配网)
|
||||
*/
|
||||
void usr_clear_pair_info_noreset()
|
||||
{
|
||||
printf("usr_clear_pair_info2\n");
|
||||
memset(&usr_auth_data,0x00,sizeof(usr_auth_data));
|
||||
usr_auth_data.paired_flag=0;
|
||||
usr_auth_data.paired_flag=0; /* 回到未配网,后续由 usr_goto_pair 决定是否绑广播 */
|
||||
syscfg_write(CFG_USER_PAIR_INFO, (u8 *)&usr_auth_data, sizeof(usr_auth_data));
|
||||
mcu_bridge_on_pair_cleared();
|
||||
}
|
||||
|
||||
extern void usr_set_adv_interval(u16 val);
|
||||
extern u16 usr_get_adv_interval();
|
||||
extern void ble_multi_trans_disconnect(void);
|
||||
extern void ble_trans_module_enable(u8 flag);
|
||||
void usr_ble_adv_init();
|
||||
|
||||
/**
|
||||
* @brief 进入配网模式:清配对 + 置 usr_goto_pair + 发绑定广播
|
||||
* @note MCU 0x10 配网请求最终会走到这里
|
||||
*/
|
||||
void usr_goto_pair_mode()
|
||||
{
|
||||
ble_multi_trans_disconnect();
|
||||
usr_clear_pair_info_noreset();
|
||||
usr_var.usr_goto_pair=1;
|
||||
usr_var.usr_goto_pair=1; /* 进入主动配网流程 → 绑定广播 */
|
||||
os_time_dly(5);
|
||||
usr_ble_adv_init();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 按当前标志刷新广播策略(不一定开广播)
|
||||
* @note 见文件头「三个标志」说明;未拿身份 / 未配网时保持不广播
|
||||
*/
|
||||
void usr_ble_adv_init()
|
||||
{
|
||||
int8_t txpower = 0;
|
||||
@@ -101,36 +150,48 @@ void usr_ble_adv_init()
|
||||
uint8_t gmac[6] = {0};
|
||||
uint8_t pcode[BLE_PROTO_ADV_LENGTH_PCODE];
|
||||
|
||||
/* 产品身份由应用层 g_usr_le_* 提供(见 usr_jb_main.c) */
|
||||
/* 产品身份由 MCU 桥写入 g_usr_le_* */
|
||||
memcpy(prodcode, g_usr_le_prodcode, BLEPROTO_ADV_TLV_LENGTH_PRODCODE);
|
||||
memcpy(pcode, g_usr_le_pcode, BLE_PROTO_ADV_LENGTH_PCODE);
|
||||
|
||||
usr_set_adv_interval(80);
|
||||
if(usr_var.usr_ota_succ_flag)return;
|
||||
//muti_adv_data
|
||||
if(usr_var.usr_goto_pair)
|
||||
{
|
||||
/* app_main 上电已置 usr_goto_pair=1 并清配对信息,此处发绑定广播供网关配网 */
|
||||
usr_clear_pair_info_noreset();
|
||||
printf("power on force to par flag= %d\n",usr_auth_data.paired_flag);
|
||||
{
|
||||
muti_adv_data_len=bleproto_advdata_encode4bind(muti_adv_data,txpower,manucode,pcode,prodcode);
|
||||
|
||||
/* 未拿到 MCU 身份:完全不广播 */
|
||||
if (!mcu_bridge_is_identity_ready()) {
|
||||
printf("usr_ble_adv_init: wait MCU identity, no adv\n");
|
||||
usr_var.usr_adv_flag = 0; /* 不请求刷新广播 */
|
||||
ble_trans_module_enable(0);
|
||||
if (le_timer_handle == 0) {
|
||||
le_timer_handle = sys_timer_add(NULL, usr_ble_adv_updata, 500);
|
||||
}
|
||||
usr_var.usr_adv_flag=1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(usr_var.usr_goto_pair)
|
||||
{
|
||||
/* 主动配网中:发绑定广播,请求刷新到协议栈 */
|
||||
usr_clear_pair_info_noreset();
|
||||
printf("goto pair bind adv, paired_flag= %d\n",usr_auth_data.paired_flag);
|
||||
muti_adv_data_len=bleproto_advdata_encode4bind(muti_adv_data,txpower,manucode,pcode,prodcode);
|
||||
usr_var.usr_adv_flag=1; /* 请求:写入绑定广播并开启 */
|
||||
}
|
||||
else
|
||||
{
|
||||
usr_get_pair_info();
|
||||
if(usr_auth_data.paired_flag==0)
|
||||
{
|
||||
muti_adv_data_len=bleproto_advdata_encode4bind(muti_adv_data,txpower,manucode,pcode,prodcode);
|
||||
/* 未配网且未进入配网流程:完全不广播 */
|
||||
printf("usr_ble_adv_init: not paired, no adv\n");
|
||||
usr_var.usr_adv_flag=0;
|
||||
ble_trans_module_enable(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 已配网:回连广播 */
|
||||
memcpy(gmac,usr_auth_data.gwmac,6);
|
||||
muti_adv_data_len=bleproto_advdata_encode4reconn(muti_adv_data,txpower,gmac,manucode,pcode,prodcode);
|
||||
usr_var.usr_adv_flag=1;
|
||||
usr_var.usr_adv_flag=1; /* 请求:写入回连广播并开启 */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +199,18 @@ void usr_ble_adv_init()
|
||||
if(le_timer_handle==0)le_timer_handle = sys_timer_add(NULL, usr_ble_adv_updata, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取是否已配网
|
||||
* @return 1=已配网(paired_flag),0=未配网
|
||||
*/
|
||||
/**
|
||||
* @brief 获取是否已配网
|
||||
* @return 1=已配网(paired_flag),0=未配网
|
||||
*/
|
||||
/**
|
||||
* @brief 获取是否已配网
|
||||
* @return paired_flag:1=已配网,0=未配网
|
||||
*/
|
||||
u8 usr_get_pair_flag()
|
||||
{
|
||||
return usr_auth_data.paired_flag;
|
||||
@@ -154,9 +227,12 @@ void usr_reconn_adv()
|
||||
muti_adv_data_len=bleproto_advdata_encode4reconn(muti_adv_data,txpower,gmac,manucode,pcode,prodcode);
|
||||
usr_adv_flag=1;
|
||||
}*/
|
||||
extern void ble_trans_module_enable(u8 flag);
|
||||
extern void usr_timer_loop();
|
||||
extern u8 usr_get_ota_status();
|
||||
|
||||
/**
|
||||
* @brief 周期处理广播刷新(由 500ms 定时器调用)
|
||||
* @note 仅当 usr_adv_flag==1 时:停广播 → 写入 muti_adv_data → 再开广播,并清 usr_adv_flag
|
||||
*/
|
||||
void usr_ble_adv_updata()
|
||||
{
|
||||
//printf("usr_ble_adv_updata\n");
|
||||
@@ -164,7 +240,7 @@ void usr_ble_adv_updata()
|
||||
if(usr_var.usr_adv_flag)
|
||||
{
|
||||
ble_trans_module_enable(0);
|
||||
usr_var.usr_adv_flag=0;
|
||||
usr_var.usr_adv_flag=0; /* 一次性触发,用完即清 */
|
||||
muti_make_set_adv_data(muti_adv_data,muti_adv_data_len);
|
||||
printf("###muti_adv_data = ");
|
||||
printf_buf(muti_adv_data,muti_adv_data_len);
|
||||
@@ -208,9 +284,6 @@ void usr_ble_adv_updata()
|
||||
if(usr_var.usr_ota_succ_flag==0)usr_ota_exit();
|
||||
}
|
||||
}
|
||||
|
||||
/* 协议层周期处理(上报/应答) */
|
||||
usr_timer_loop();
|
||||
}
|
||||
|
||||
void usr_soft_off()
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/******************************************************************************
|
||||
* @file usr_le_api.h
|
||||
* @brief usr_le_code 对外 API(广播 / 收发 / 配网)
|
||||
* @brief usr_le_code 对外 API(广播 / 收发 / 配网 / MCU 帧转发)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.03
|
||||
* @version V1.0.0
|
||||
* @date 2026.08.06
|
||||
* @version V1.1.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.03, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.06, cyWu, 增加 MCU 帧 BLE 发送接口,解耦模组桥
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __USR_LE_API_H__
|
||||
@@ -18,8 +19,12 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 初始化 BLE 广播数据(绑定广播或重连广播)
|
||||
* @note 根据配对状态与 usr_goto_pair 选择 bind/reconn 广播,并启动 500ms 周期更新
|
||||
* @brief 初始化/刷新 BLE 广播策略(不一定开启广播)
|
||||
* @note 决策依赖三个标志:
|
||||
* - paired_flag:是否已配网(VM)
|
||||
* - usr_goto_pair:是否主动配网中(发绑定广播)
|
||||
* - usr_adv_flag:是否请求把新广播包刷到协议栈
|
||||
* 详见 usr_le_adv.c 文件头注释
|
||||
*/
|
||||
void usr_ble_adv_init(void);
|
||||
|
||||
@@ -27,18 +32,25 @@ void usr_ble_adv_init(void);
|
||||
* @brief BLE 协议栈接收数据入口
|
||||
* @param data 接收缓冲区
|
||||
* @param len 本次接收长度
|
||||
* @note 组包后解析 bleproto,并分发 DEVICEINFO/AUTH/RUNCMD/OTA 等服务
|
||||
*/
|
||||
void usr_le_data_recieve(uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief 将 MCU 协议 55AA 帧封装为 bleproto 后经 GATT 发送
|
||||
* @param data 完整 55AA 帧
|
||||
* @param len 帧长度
|
||||
* @note 0x07/0x34/0x38 走 REPORTCMD_V2 主动上报;其余走 RUNCMD_V2 应答
|
||||
*/
|
||||
void usr_le_send_mcu_frame(uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief 进入配对/配网模式
|
||||
* @note 断开当前连接、清除配对信息(不复位),重新发绑定广播
|
||||
* @note 清配对信息,置 usr_goto_pair=1,发绑定广播(非回连)
|
||||
*/
|
||||
void usr_goto_pair_mode(void);
|
||||
|
||||
/**
|
||||
* @brief 清除配对信息但不复位
|
||||
* @brief 清除配对信息但不复位(paired_flag→0)
|
||||
*/
|
||||
void usr_clear_pair_info_noreset(void);
|
||||
|
||||
@@ -48,14 +60,13 @@ void usr_clear_pair_info_noreset(void);
|
||||
void usr_clear_pair_info(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前是否已配对
|
||||
* @return 1=已配对,0=未配对
|
||||
* @brief 获取是否已配网
|
||||
* @return paired_flag:1=已配网,0=未配网
|
||||
*/
|
||||
uint8_t usr_get_pair_flag(void);
|
||||
|
||||
/**
|
||||
* @brief 启动应用侧 OTA 流程
|
||||
* @note 置位 usr_goto_updata,并创建 1s 周期定时器驱动断连与 OTA 广播切换
|
||||
*/
|
||||
void usr_app_ota_init(void);
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/******************************************************************************
|
||||
* @file usr_le_product.h
|
||||
* @brief usr_le_code 产品身份配置接口(由应用层提供符号,模块内不写死)
|
||||
* @brief usr_le_code 产品身份配置接口(由 MCU 桥运行时填充)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.03
|
||||
* @version V1.0.0
|
||||
* @version V1.1.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.03, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.06, cyWu, 改为非 const,由 mcu_bridge 从 MCU 0x02 写入
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __USR_LE_PRODUCT_H__
|
||||
@@ -29,15 +30,15 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* @brief 产品类别码,对应 BLE 广播 prodcode(固定 4 字节 ASCII)
|
||||
* @note 应用层用 JB_CATEGORY_CODE 填充,见 usr_jb_main.c
|
||||
* @note 由 mcu_bridge 从 MCU 身份应答取前 4 字节写入
|
||||
*/
|
||||
extern const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN];
|
||||
extern uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN];
|
||||
|
||||
/**
|
||||
* @brief 平台产品码,对应 BLE 广播 pcode(固定 6 字节 ASCII)
|
||||
* @note 应用层用 JB_PRODUCT_CODE 填充,见 usr_jb_main.c
|
||||
* @note 由 mcu_bridge 从 MCU 身份应答取前 6 字节写入
|
||||
*/
|
||||
extern const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN];
|
||||
extern uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "bleproto.h"
|
||||
#include "bleproto_api.h"
|
||||
#include "ble_proto.h"
|
||||
#include "mcu_frame.h"
|
||||
#define LOG_TAG_CONST APP
|
||||
#define LOG_TAG "[APP]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
@@ -43,8 +44,12 @@ extern void app_audio_volume_set(u8 value);
|
||||
extern int dual_ota_app_data_deal(u32 msg, u8 *buf, u32 len);
|
||||
extern int uart_tr_send_data(u8 *data, u32 len);
|
||||
extern void usr_intterupt_close();
|
||||
extern void usr_jb_le_recieve_data(u8 *data, u16 len);
|
||||
extern int8_t jbReportAckCheck(u16 cmd, u8 gateway_int_cnt, int32_t gateway_int0);
|
||||
extern void mcu_bridge_on_paired(void);
|
||||
extern void mcu_bridge_on_pair_cleared(void);
|
||||
extern void mcu_bridge_on_app_frame(const uint8_t *data, uint16_t len);
|
||||
extern void mcu_bridge_on_gateway_report_ack(uint16_t cmd,
|
||||
uint8_t gateway_int_cnt,
|
||||
int32_t gateway_int0);
|
||||
|
||||
void usr_ota_deal_task();
|
||||
void usr_data_ana(bleproto_appdata_desc_t *desc);
|
||||
@@ -61,6 +66,14 @@ void usr_le_data_recieve(u8 *data, u16 len) /// BLE数据接收
|
||||
|
||||
int rc_result = 0;
|
||||
|
||||
if ((u32)usr_len + len > sizeof(rxbuf))
|
||||
{
|
||||
/* 累积超界:多半是丢包/半包导致 decode 一直返回 0,防止缓冲区溢出 */
|
||||
printf("### rxbuf overflow, usr_len=%u len=%u, reset\n", usr_len, len);
|
||||
usr_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&rxbuf[usr_len], data, len);
|
||||
usr_len += len;
|
||||
rc_result = bleproto_appdata_decode(rxbuf, usr_len, &desc);
|
||||
@@ -149,6 +162,7 @@ void usr_data_ana(bleproto_appdata_desc_t *desc)
|
||||
if (usr_auth_data.paired_flag == 0)
|
||||
{
|
||||
usr_write_pair_info();
|
||||
mcu_bridge_on_paired();
|
||||
printf("usr_auth_data %s %s ", usr_auth_data.authcode, usr_auth_data.devid);
|
||||
printf_buf(usr_auth_data.gwmac, 6);
|
||||
}
|
||||
@@ -305,16 +319,16 @@ void usr_data_ana(bleproto_appdata_desc_t *desc)
|
||||
break;
|
||||
case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2:
|
||||
{
|
||||
/* 网关对主动上报 / OTA 的应答(非 55AA):
|
||||
* cmd==0 && gateway_int_cnt==1 && gateway_int[0]==0 → 应答成功 */
|
||||
/* 网关对 MCU 主动上报的应答:成功后由桥接层回 MCU 0x08 */
|
||||
ble_proto_packet_t *rpt_ack = &desc->datast.reportcmd_v2_rsp;
|
||||
printf("E_BLEPROTO_SERVICE_ID_REPORTCMD_V2 cmd=%u cnt=%u int0=%ld\n",
|
||||
(unsigned)rpt_ack->cmd,
|
||||
(unsigned)rpt_ack->gateway_int_cnt,
|
||||
(long)((rpt_ack->gateway_int_cnt > 0) ? rpt_ack->gateway_int[0] : 0));
|
||||
jbReportAckCheck(rpt_ack->cmd,
|
||||
rpt_ack->gateway_int_cnt,
|
||||
(rpt_ack->gateway_int_cnt > 0) ? rpt_ack->gateway_int[0] : -1);
|
||||
mcu_bridge_on_gateway_report_ack(
|
||||
rpt_ack->cmd,
|
||||
rpt_ack->gateway_int_cnt,
|
||||
(rpt_ack->gateway_int_cnt > 0) ? rpt_ack->gateway_int[0] : -1);
|
||||
break;
|
||||
}
|
||||
case E_BLEPROTO_SERVICE_ID_OTADATA:
|
||||
@@ -431,7 +445,7 @@ void usr_ota_deal_task()
|
||||
static u8 s_last_runcmd_msgid = 0;
|
||||
void usr_run_cmd_code_v2(ble_proto_packet_t *runcmd_par, u8 usr_msg_id)
|
||||
{
|
||||
u8 jb_frame[128]; /* 与 jb_protocol.h MAX_PACKAGE_LEN 一致 */
|
||||
u8 mcu_frame[MCU_FRAME_MAX_LEN];
|
||||
u16 copy_len;
|
||||
|
||||
if (!runcmd_par || !runcmd_par->bytes_data || runcmd_par->device_bytes_len == 0)
|
||||
@@ -444,45 +458,40 @@ void usr_run_cmd_code_v2(ble_proto_packet_t *runcmd_par, u8 usr_msg_id)
|
||||
printf("runcmd_par id = %d, bytes_len = %u\n",
|
||||
runcmd_par->cmd, runcmd_par->device_bytes_len);
|
||||
|
||||
/* 先拷到本地再入 JB 环缓,避免零拷贝指针被后续逻辑覆盖 */
|
||||
copy_len = runcmd_par->device_bytes_len;
|
||||
if (copy_len > sizeof(jb_frame))
|
||||
if (copy_len > sizeof(mcu_frame))
|
||||
{
|
||||
printf("usr_run_cmd_code_v2 bytes too long %u\n", copy_len);
|
||||
return;
|
||||
}
|
||||
memcpy(jb_frame, runcmd_par->bytes_data, copy_len);
|
||||
memcpy(mcu_frame, runcmd_par->bytes_data, copy_len);
|
||||
|
||||
s_last_runcmd_msgid = usr_msg_id;
|
||||
usr_jb_le_recieve_data(jb_frame, copy_len);
|
||||
mcu_bridge_on_app_frame(mcu_frame, copy_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将 JB 协议帧封装为 bleproto V2 后通过 BLE 发送
|
||||
* @param data JB 协议原始帧(55 AA | LEN | CMD | ...)
|
||||
* @brief 将 MCU 协议帧封装为 bleproto V2 后通过 BLE 发送
|
||||
* @param data 55AA 完整帧
|
||||
* @param len 帧长度
|
||||
* @note 根据 JB CMD 区分主动上报 / 应答:
|
||||
* - 主动(0x07/0x34/0x38): REPORTCMD_V2 + REQ + cmd=100
|
||||
* - 应答(其余): RUNCMD_V2 + RSP + cmd=110
|
||||
* @note 主动上报(0x07/0x34/0x38) → REPORTCMD_V2;其余 → RUNCMD_V2 应答
|
||||
*/
|
||||
void ble_send_data(u8 *data, u16 len)
|
||||
void usr_le_send_mcu_frame(u8 *data, u16 len)
|
||||
{
|
||||
bleproto_appdata_desc_t encode_desc = {0};
|
||||
ble_proto_packet_t *pkt = NULL;
|
||||
u8 jb_cmd;
|
||||
u8 mcu_cmd;
|
||||
u8 is_active_send;
|
||||
int elen;
|
||||
|
||||
if (!data || len < 5)
|
||||
{
|
||||
printf("ble_send_data invalid param, len=%d\n", len);
|
||||
printf("usr_le_send_mcu_frame invalid param, len=%d\n", len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* JB帧: 55 AA | LEN_H LEN_L | CMD | SN | ...,CMD 在偏移 4 */
|
||||
jb_cmd = data[4];
|
||||
/* 主动上报 0x07;MCU 主动 OTA 完成/停止 0x34/0x38;其余按应答 */
|
||||
is_active_send = (jb_cmd == 0x07) || (jb_cmd == 0x34) || (jb_cmd == 0x38);
|
||||
mcu_cmd = data[4];
|
||||
is_active_send = (mcu_cmd == 0x07) || (mcu_cmd == 0x34) || (mcu_cmd == 0x38);
|
||||
|
||||
encode_desc.header.version = 0;
|
||||
encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
|
||||
@@ -490,7 +499,6 @@ void ble_send_data(u8 *data, u16 len)
|
||||
|
||||
if (is_active_send)
|
||||
{
|
||||
/* 主动发送:REPORTCMD_V2 / REQ / cmd=100 */
|
||||
encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_REQ;
|
||||
encode_desc.header.msgid = 0;
|
||||
encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_REPORTCMD_V2;
|
||||
@@ -502,7 +510,6 @@ void ble_send_data(u8 *data, u16 len)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 应答命令:RUNCMD_V2 / RSP / cmd=110,回填最新 msgid */
|
||||
encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_RSP;
|
||||
encode_desc.header.msgid = s_last_runcmd_msgid;
|
||||
encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_RUNCMD_V2;
|
||||
@@ -521,8 +528,8 @@ void ble_send_data(u8 *data, u16 len)
|
||||
pkt->bytes_data = data;
|
||||
|
||||
elen = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), &encode_desc);
|
||||
printf("ble_send_data jb_cmd=0x%02X active=%d encode_len=%d msgid=%d\n",
|
||||
jb_cmd, is_active_send, elen, encode_desc.header.msgid);
|
||||
printf("usr_le_send_mcu_frame cmd=0x%02X active=%d encode_len=%d msgid=%d\n",
|
||||
mcu_cmd, is_active_send, elen, encode_desc.header.msgid);
|
||||
if (elen > 0)
|
||||
{
|
||||
usr_ble_send_data(txbuf, elen);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,100 @@
|
||||
/******************************************************************************
|
||||
* @file mcu_bridge.h
|
||||
* @brief BLE+MCU 协议桥对外 API(模组侧唯一业务入口)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.06
|
||||
* @version V1.1.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.06, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.06, cyWu, 内部改为事件队列 + 独立任务驱动;
|
||||
* 所有 on_xxx 接口均可在任意任务上下文安全调用(生产者-消费者模型)
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __MCU_BRIDGE_H__
|
||||
#define __MCU_BRIDGE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mcu_cmd.h"
|
||||
|
||||
/*============================================================================*/
|
||||
/* 错误码 */
|
||||
/*============================================================================*/
|
||||
|
||||
typedef enum {
|
||||
MCU_BRIDGE_OK = 0,
|
||||
MCU_BRIDGE_ERR_PARAM,
|
||||
MCU_BRIDGE_ERR_BUSY,
|
||||
MCU_BRIDGE_ERR_TIMEOUT,
|
||||
MCU_BRIDGE_ERR_NOT_INIT,
|
||||
MCU_BRIDGE_ERR_UNKNOWN
|
||||
} McuBridge_Ret_t;
|
||||
|
||||
/*============================================================================*/
|
||||
/* 外部接口 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 初始化 MCU 协议桥(UART + 事件队列 + 独立任务)
|
||||
* @return McuBridge_Ret_t
|
||||
* @note 在 app_main 中调用一次即可;内部会创建 "mcu_bridge" 任务,
|
||||
* 所有身份/心跳/透传/状态机逻辑均在该任务单一上下文中处理
|
||||
*/
|
||||
McuBridge_Ret_t mcu_bridge_init(void);
|
||||
|
||||
/**
|
||||
* @brief UART 收到原始数据(由 mcu_uart 接收任务调用)
|
||||
* @param data 数据
|
||||
* @param len 长度
|
||||
* @note 仅做逐字节组帧;帧就绪后投递事件到 mcu_bridge 任务处理,
|
||||
* 可安全在 UART 接收任务上下文调用
|
||||
*/
|
||||
void mcu_bridge_on_uart_rx(const uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief APP/网关经 BLE 下发的 55AA 帧
|
||||
* @param data 帧数据
|
||||
* @param len 长度
|
||||
* @note 对 0x03/0x05:转发 MCU,等 0x04/0x06 后再回传 BLE;
|
||||
* 可安全在 BLE 协议栈任务上下文调用(内部投递事件异步处理)
|
||||
*/
|
||||
void mcu_bridge_on_app_frame(const uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief 是否已从 MCU 获取到设备身份
|
||||
* @return 1=已就绪,0=未就绪
|
||||
* @note 单字节只读快照,可在任意任务直接调用
|
||||
*/
|
||||
uint8_t mcu_bridge_is_identity_ready(void);
|
||||
|
||||
/**
|
||||
* @brief 配网成功通知(AUTHSETUP 写对后由 BLE 层调用)
|
||||
* @note 可安全在 BLE 协议栈任务上下文调用(内部投递事件异步处理)
|
||||
*/
|
||||
void mcu_bridge_on_paired(void);
|
||||
|
||||
/**
|
||||
* @brief 配对信息被清除通知
|
||||
* @note 可安全在 BLE 协议栈任务上下文调用(内部投递事件异步处理)
|
||||
*/
|
||||
void mcu_bridge_on_pair_cleared(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前工作状态字节
|
||||
* @return 工作状态 bitmap
|
||||
* @note 单字节只读快照,可在任意任务直接调用
|
||||
*/
|
||||
uint8_t mcu_bridge_get_work_status(void);
|
||||
|
||||
/**
|
||||
* @brief 网关对 REPORTCMD_V2 主动上报的应答
|
||||
* @param cmd bleproto 包 cmd
|
||||
* @param gateway_int_cnt gateway_int 个数
|
||||
* @param gateway_int0 gateway_int[0]
|
||||
* @note 成功条件:cmd==0 && cnt==1 && int0==0;
|
||||
* 成功后才向 MCU 回 0x08;可安全在 BLE 协议栈任务上下文调用
|
||||
*/
|
||||
void mcu_bridge_on_gateway_report_ack(uint16_t cmd,
|
||||
uint8_t gateway_int_cnt,
|
||||
int32_t gateway_int0);
|
||||
|
||||
#endif /* __MCU_BRIDGE_H__ */
|
||||
@@ -0,0 +1,110 @@
|
||||
/******************************************************************************
|
||||
* @file mcu_cmd.h
|
||||
* @brief MCU 接入协议命令字 / 结果码 / 工作状态位定义
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.06
|
||||
* @version V1.0.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.06, cyWu, 首次发布
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __MCU_CMD_H__
|
||||
#define __MCU_CMD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*============================================================================*/
|
||||
/* 工作状态 Bit(命令 0x14) */
|
||||
/*============================================================================*/
|
||||
|
||||
#define MCU_WS_CONFIGURED (1u << 0) /**< 已完成配网 */
|
||||
#define MCU_WS_INTERNET (1u << 1) /**< 已连互联网(云),预留:暂无法获取,固定为 0 */
|
||||
#define MCU_WS_APP_ONLINE (1u << 2) /**< APP 在线,预留:暂无法获取,固定为 0 */
|
||||
#define MCU_WS_BLE_CONNECTED (1u << 3) /**< 手机已连接 BLE,预留:暂无法获取,固定为 0 */
|
||||
#define MCU_WS_OTA_UPGRADING (1u << 4) /**< OTA 升级中 */
|
||||
#define MCU_WS_PAIRING_MODE (1u << 5) /**< 配网模式中 */
|
||||
|
||||
/*============================================================================*/
|
||||
/* 命令字 */
|
||||
/*============================================================================*/
|
||||
|
||||
typedef enum {
|
||||
/* 身份 */
|
||||
MCU_CMD_GET_IDENTITY = 0x01,
|
||||
MCU_CMD_GET_IDENTITY_ACK = 0x02,
|
||||
|
||||
/* 数据透传 */
|
||||
MCU_CMD_CONTROL = 0x03,
|
||||
MCU_CMD_CONTROL_ACK = 0x04,
|
||||
MCU_CMD_READ = 0x05,
|
||||
MCU_CMD_READ_ACK = 0x06,
|
||||
MCU_CMD_REPORT = 0x07,
|
||||
MCU_CMD_REPORT_ACK = 0x08,
|
||||
|
||||
/* 配网 / 心跳 / 状态 */
|
||||
MCU_CMD_PAIR_CFG = 0x10,
|
||||
MCU_CMD_PAIR_CFG_ACK = 0x11,
|
||||
MCU_CMD_HEARTBEAT = 0x12,
|
||||
MCU_CMD_HEARTBEAT_ACK = 0x13,
|
||||
MCU_CMD_WORK_STATUS = 0x14,
|
||||
MCU_CMD_WORK_STATUS_ACK = 0x15,
|
||||
|
||||
/* 模组管理(后续扩展) */
|
||||
MCU_CMD_RESET = 0x16,
|
||||
MCU_CMD_RESET_ACK = 0x17,
|
||||
MCU_CMD_REBOOT = 0x18,
|
||||
MCU_CMD_REBOOT_ACK = 0x19,
|
||||
MCU_CMD_MCU_REBOOT = 0x1A,
|
||||
MCU_CMD_MCU_REBOOT_ACK = 0x1B,
|
||||
MCU_CMD_GET_TIME = 0x1C,
|
||||
MCU_CMD_GET_TIME_ACK = 0x1D,
|
||||
|
||||
/* 扩展功能(后续扩展) */
|
||||
MCU_CMD_FACTORY = 0x20,
|
||||
MCU_CMD_FACTORY_ACK = 0x21,
|
||||
MCU_CMD_PHOTO = 0x22,
|
||||
MCU_CMD_PHOTO_ACK = 0x23,
|
||||
MCU_CMD_RECORD = 0x24,
|
||||
MCU_CMD_RECORD_ACK = 0x25,
|
||||
MCU_CMD_AUDIO = 0x26,
|
||||
MCU_CMD_AUDIO_ACK = 0x27,
|
||||
|
||||
/* OTA(后续扩展) */
|
||||
MCU_CMD_OTA_NOTIFY = 0x30,
|
||||
MCU_CMD_OTA_NOTIFY_ACK = 0x31,
|
||||
MCU_CMD_OTA_DATA = 0x32,
|
||||
MCU_CMD_OTA_DATA_ACK = 0x33,
|
||||
MCU_CMD_OTA_COMPLETE = 0x34,
|
||||
MCU_CMD_OTA_COMPLETE_ACK = 0x35,
|
||||
MCU_CMD_OTA_STOP_BLE = 0x36,
|
||||
MCU_CMD_OTA_STOP_BLE_ACK = 0x37,
|
||||
MCU_CMD_OTA_STOP_MCU = 0x38,
|
||||
MCU_CMD_OTA_STOP_MCU_ACK = 0x39,
|
||||
|
||||
/* MCU 信息 */
|
||||
MCU_CMD_GET_MCU_INFO = 0x40,
|
||||
MCU_CMD_GET_MCU_INFO_ACK = 0x41
|
||||
} McuCmd_t;
|
||||
|
||||
/*============================================================================*/
|
||||
/* 结果码 */
|
||||
/*============================================================================*/
|
||||
|
||||
typedef enum {
|
||||
MCU_RESULT_OK = 0x00,
|
||||
MCU_RESULT_PARAM_ERR = 0x01,
|
||||
MCU_RESULT_BUSY = 0x02,
|
||||
MCU_RESULT_NOT_SUPPORT = 0x03,
|
||||
MCU_RESULT_CRC_ERR = 0x04,
|
||||
MCU_RESULT_FAIL = 0x05,
|
||||
|
||||
/* OTA 专用 */
|
||||
MCU_RESULT_OTA_NO_NEED = 0x20,
|
||||
MCU_RESULT_OTA_VER_LOW = 0x21,
|
||||
MCU_RESULT_OTA_SPACE_ERR = 0x22,
|
||||
MCU_RESULT_OTA_STATE_ERR = 0x23,
|
||||
MCU_RESULT_OTA_FILE_ERR = 0x24,
|
||||
MCU_RESULT_OTA_FAIL = 0x25
|
||||
} McuResult_t;
|
||||
|
||||
#endif /* __MCU_CMD_H__ */
|
||||
@@ -0,0 +1,140 @@
|
||||
/******************************************************************************
|
||||
* @file mcu_frame.c
|
||||
* @brief MCU 接入协议 55AA 帧组包/解包
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.06
|
||||
* @version V1.0.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.06, cyWu, 首次发布
|
||||
******************************************************************************/
|
||||
|
||||
#include "mcu_frame.h"
|
||||
#include "mcu_util.h"
|
||||
#include <string.h>
|
||||
|
||||
/*============================================================================*/
|
||||
/* 私有变量 */
|
||||
/*============================================================================*/
|
||||
|
||||
static uint8_t s_state = 0; /* 0=寻头 1=收长度高 2=收长度低 3=收载荷 */
|
||||
static uint8_t s_prev = 0;
|
||||
static uint16_t s_expect = 0;
|
||||
static uint16_t s_idx = 0;
|
||||
static uint8_t s_buf[MCU_FRAME_MAX_LEN];
|
||||
|
||||
/*============================================================================*/
|
||||
/* 公有函数 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 复位帧解析状态机
|
||||
*/
|
||||
void mcu_frame_parser_reset(void)
|
||||
{
|
||||
s_state = 0;
|
||||
s_prev = 0;
|
||||
s_expect = 0;
|
||||
s_idx = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 组帧并写入 out(含包头与校验)
|
||||
* @param out 输出缓冲
|
||||
* @param out_max 缓冲最大长度
|
||||
* @param cmd 命令字
|
||||
* @param sn 序列号
|
||||
* @param payload 数据区,可为 NULL
|
||||
* @param plen 数据长度
|
||||
* @return 帧总长度;<0 失败
|
||||
*/
|
||||
int32_t mcu_frame_pack(uint8_t *out, uint16_t out_max,
|
||||
uint8_t cmd, uint8_t sn,
|
||||
const uint8_t *payload, uint16_t plen)
|
||||
{
|
||||
uint16_t len_field;
|
||||
uint16_t total;
|
||||
|
||||
if (!out) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* LEN = CMD + SN + payload + CKSUM */
|
||||
len_field = (uint16_t)(plen + 3);
|
||||
total = (uint16_t)(len_field + 4);
|
||||
|
||||
if (total > out_max || total > MCU_FRAME_MAX_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
out[0] = MCU_PKT_HEAD_0;
|
||||
out[1] = MCU_PKT_HEAD_1;
|
||||
mcu_util_write_u16_be(&out[2], len_field);
|
||||
out[4] = cmd;
|
||||
out[5] = sn;
|
||||
if (payload && plen > 0) {
|
||||
memcpy(&out[6], payload, plen);
|
||||
}
|
||||
out[total - 1] = mcu_util_checksum(out, total);
|
||||
return (int32_t)total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向解析器喂入原始字节,尝试提取完整帧
|
||||
* @param byte 输入字节
|
||||
* @param out 输出完整帧缓冲
|
||||
* @param out_len 输出帧长度
|
||||
* @return 1=得到完整帧,0=继续,-1=校验错误丢弃
|
||||
*/
|
||||
int8_t mcu_frame_feed(uint8_t byte, uint8_t *out, uint16_t *out_len)
|
||||
{
|
||||
if (!out || !out_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s_state == 0) {
|
||||
if (s_prev == MCU_PKT_HEAD_0 && byte == MCU_PKT_HEAD_1) {
|
||||
s_buf[0] = MCU_PKT_HEAD_0;
|
||||
s_buf[1] = MCU_PKT_HEAD_1;
|
||||
s_idx = 2;
|
||||
s_state = 1;
|
||||
}
|
||||
s_prev = byte;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s_state == 1) {
|
||||
s_buf[s_idx++] = byte;
|
||||
s_state = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s_state == 2) {
|
||||
s_buf[s_idx++] = byte;
|
||||
s_expect = mcu_util_read_u16_be(&s_buf[2]);
|
||||
if (s_expect < 3 || (s_expect + 4) > MCU_FRAME_MAX_LEN) {
|
||||
mcu_frame_parser_reset();
|
||||
s_prev = byte;
|
||||
return -1;
|
||||
}
|
||||
s_state = 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s_buf[s_idx++] = byte;
|
||||
if (s_idx >= (uint16_t)(s_expect + 4)) {
|
||||
uint16_t total = (uint16_t)(s_expect + 4);
|
||||
uint8_t ck = mcu_util_checksum(s_buf, total);
|
||||
int8_t ret;
|
||||
|
||||
if (ck == s_buf[total - 1]) {
|
||||
memcpy(out, s_buf, total);
|
||||
*out_len = total;
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
mcu_frame_parser_reset();
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/******************************************************************************
|
||||
* @file mcu_frame.h
|
||||
* @brief MCU 接入协议 55AA 帧组包/解包
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.06
|
||||
* @version V1.0.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.06, cyWu, 首次发布
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __MCU_FRAME_H__
|
||||
#define __MCU_FRAME_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mcu_cmd.h"
|
||||
|
||||
/*============================================================================*/
|
||||
/* 宏定义 */
|
||||
/*============================================================================*/
|
||||
|
||||
#define MCU_PKT_HEAD_0 (0x55)
|
||||
#define MCU_PKT_HEAD_1 (0xAA)
|
||||
#define MCU_FRAME_MAX_LEN (128)
|
||||
|
||||
/*============================================================================*/
|
||||
/* 外部接口 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 组帧并写入 out(含包头与校验)
|
||||
* @param out 输出缓冲
|
||||
* @param out_max 缓冲最大长度
|
||||
* @param cmd 命令字
|
||||
* @param sn 序列号
|
||||
* @param payload 数据区,可为 NULL
|
||||
* @param plen 数据长度
|
||||
* @return 帧总长度;<0 失败
|
||||
*/
|
||||
int32_t mcu_frame_pack(uint8_t *out, uint16_t out_max,
|
||||
uint8_t cmd, uint8_t sn,
|
||||
const uint8_t *payload, uint16_t plen);
|
||||
|
||||
/**
|
||||
* @brief 向解析器喂入原始字节,尝试提取完整帧
|
||||
* @param byte 输入字节
|
||||
* @param out 输出完整帧缓冲
|
||||
* @param out_len 输出帧长度
|
||||
* @return 1=得到完整帧,0=继续,-1=校验错误丢弃
|
||||
*/
|
||||
int8_t mcu_frame_feed(uint8_t byte, uint8_t *out, uint16_t *out_len);
|
||||
|
||||
/**
|
||||
* @brief 复位帧解析状态机
|
||||
*/
|
||||
void mcu_frame_parser_reset(void);
|
||||
|
||||
#endif /* __MCU_FRAME_H__ */
|
||||
@@ -0,0 +1,141 @@
|
||||
/******************************************************************************
|
||||
* @file mcu_uart.c
|
||||
* @brief BLE 模组与外部 MCU 的 UART 驱动(PA7 TX / PA8 RX, 9600)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.06
|
||||
* @version V1.3.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.06, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.07, cyWu, TX 使用静态对齐缓冲 + write()
|
||||
* - V1.2.0, 2026.08.07, cyWu, 对齐供应商 demo:关闭低功耗
|
||||
* - V1.3.0, 2026.08.07, cyWu, 发送与厂家一致,直接 write(data),去掉 TX 拷贝
|
||||
*
|
||||
* @note 串口收发期间由 mcu_bridge 的 LP target 挡住休眠;
|
||||
* 板级可开 SLEEP_EN,勿在无 LP 保护时直接开 DEEP_SLEEP。
|
||||
******************************************************************************/
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "asm/uart_dev.h"
|
||||
#include "asm/gpio.h"
|
||||
#include "mcu_uart.h"
|
||||
#include "mcu_bridge.h"
|
||||
#include "mcu_frame.h"
|
||||
|
||||
#define LOG_TAG_CONST APP
|
||||
#define LOG_TAG "[MCU_UART]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
#define LOG_DUMP_ENABLE
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
/*============================================================================*/
|
||||
/* 私有变量 */
|
||||
/*============================================================================*/
|
||||
|
||||
static uint8_t s_initialized = 0;
|
||||
static const uart_bus_t *s_uart_bus = NULL;
|
||||
static u8 s_rx_cbuf[MCU_UART_RX_CBUF_SIZE] __attribute__((aligned(4)));
|
||||
static u8 s_rx_tmp[MCU_UART_RX_CBUF_SIZE];
|
||||
static OS_MUTEX s_tx_lock;
|
||||
|
||||
/*============================================================================*/
|
||||
/* 私有函数 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief UART 接收任务:阻塞读串口,喂入协议桥
|
||||
* @param arg 未使用
|
||||
*/
|
||||
static void mcu_uart_rx_task(void *arg)
|
||||
{
|
||||
u32 rxcnt;
|
||||
|
||||
(void)arg;
|
||||
log_info("rx task start");
|
||||
|
||||
while (1) {
|
||||
if (!s_uart_bus) {
|
||||
os_time_dly(10);
|
||||
continue;
|
||||
}
|
||||
/* timeout=0:无数据时 pend,有 RX/OT 中断后唤醒 */
|
||||
rxcnt = s_uart_bus->read(s_rx_tmp, sizeof(s_rx_tmp), 0);
|
||||
if (rxcnt > 0) {
|
||||
mcu_bridge_on_uart_rx(s_rx_tmp, (uint16_t)rxcnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
/* 公有函数 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 打开 MCU 串口并创建接收任务
|
||||
* @return McuUart_Ret_t
|
||||
*/
|
||||
McuUart_Ret_t mcu_uart_init(void)
|
||||
{
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
if (s_initialized) {
|
||||
return MCU_UART_OK;
|
||||
}
|
||||
|
||||
u_arg.tx_pin = IO_PORTA_07;
|
||||
u_arg.rx_pin = IO_PORTA_08;
|
||||
u_arg.rx_cbuf = s_rx_cbuf;
|
||||
u_arg.rx_cbuf_size = MCU_UART_RX_CBUF_SIZE;
|
||||
u_arg.frame_length = MCU_UART_RX_CBUF_SIZE;
|
||||
u_arg.rx_timeout = 10; /* ms,帧间隙产生 OT */
|
||||
u_arg.isr_cbfun = NULL;
|
||||
u_arg.baud = MCU_UART_BAUD;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
s_uart_bus = uart_dev_open(&u_arg);
|
||||
if (s_uart_bus == NULL) {
|
||||
log_error("init open fail");
|
||||
return MCU_UART_ERR_OPEN;
|
||||
}
|
||||
|
||||
os_mutex_create(&s_tx_lock);
|
||||
os_task_create(mcu_uart_rx_task, NULL, 31, 1024, 0, "mcu_uart");
|
||||
|
||||
s_initialized = 1;
|
||||
log_info("init ok, PA7/PA8 @ %d", MCU_UART_BAUD);
|
||||
return MCU_UART_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向 MCU 发送数据
|
||||
* @param data 发送缓冲
|
||||
* @param len 长度
|
||||
* @return McuUart_Ret_t
|
||||
* @note 与 usr_hw_uart.c 一致:uart_bus->write(data, len)
|
||||
*/
|
||||
McuUart_Ret_t mcu_uart_send(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!s_initialized || !s_uart_bus) {
|
||||
return MCU_UART_ERR_NOT_INIT;
|
||||
}
|
||||
if (!data || len == 0 || len > MCU_FRAME_MAX_LEN) {
|
||||
return MCU_UART_ERR_PARAM;
|
||||
}
|
||||
|
||||
os_mutex_pend(&s_tx_lock, 0);
|
||||
s_uart_bus->write((void *)data, len);
|
||||
os_mutex_post(&s_tx_lock);
|
||||
|
||||
return MCU_UART_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取串口是否已初始化
|
||||
* @return 1=已初始化,0=未初始化
|
||||
*/
|
||||
uint8_t mcu_uart_is_ready(void)
|
||||
{
|
||||
return s_initialized;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/******************************************************************************
|
||||
* @file mcu_uart.h
|
||||
* @brief BLE 模组与外部 MCU 的 UART 驱动接口(PA7/PA8, 9600)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.06
|
||||
* @version V1.0.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.06, cyWu, 首次发布
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __MCU_UART_H__
|
||||
#define __MCU_UART_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*============================================================================*/
|
||||
/* 宏定义 */
|
||||
/*============================================================================*/
|
||||
|
||||
#define MCU_UART_BAUD (9600) /**< 协议默认波特率 */
|
||||
#define MCU_UART_RX_CBUF_SIZE (512) /**< DMA 循环缓冲,须为 2 的幂 */
|
||||
/* 引脚:TX=PA7(IO_PORTA_07),RX=PA8(IO_PORTA_08),在 mcu_uart.c 中配置 */
|
||||
|
||||
/*============================================================================*/
|
||||
/* 错误码 */
|
||||
/*============================================================================*/
|
||||
|
||||
typedef enum {
|
||||
MCU_UART_OK = 0,
|
||||
MCU_UART_ERR_PARAM,
|
||||
MCU_UART_ERR_BUSY,
|
||||
MCU_UART_ERR_TIMEOUT,
|
||||
MCU_UART_ERR_NOT_INIT,
|
||||
MCU_UART_ERR_OPEN,
|
||||
MCU_UART_ERR_UNKNOWN
|
||||
} McuUart_Ret_t;
|
||||
|
||||
/*============================================================================*/
|
||||
/* 外部接口 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 打开 MCU 串口并创建接收任务
|
||||
* @return McuUart_Ret_t
|
||||
*/
|
||||
McuUart_Ret_t mcu_uart_init(void);
|
||||
|
||||
/**
|
||||
* @brief 向 MCU 发送数据
|
||||
* @param data 发送缓冲
|
||||
* @param len 长度
|
||||
* @return McuUart_Ret_t
|
||||
*/
|
||||
McuUart_Ret_t mcu_uart_send(const uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief 获取串口是否已初始化
|
||||
* @return 1=已初始化,0=未初始化
|
||||
*/
|
||||
uint8_t mcu_uart_is_ready(void);
|
||||
|
||||
#endif /* __MCU_UART_H__ */
|
||||
@@ -0,0 +1,108 @@
|
||||
/******************************************************************************
|
||||
* @file mcu_util.c
|
||||
* @brief MCU 桥通用工具实现
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.06
|
||||
* @version V1.2.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.06, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.07, cyWu, get_ms 改用 timer_get_ms
|
||||
* - V1.2.0, 2026.08.10, cyWu, 删除空壳 timer_init
|
||||
******************************************************************************/
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "asm/timer.h"
|
||||
#include "mcu_util.h"
|
||||
|
||||
/*============================================================================*/
|
||||
/* 公有函数 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 获取开机以来的毫秒计数
|
||||
* @return 毫秒计数
|
||||
* @note 直接使用系统 tick 换算的毫秒,不受低功耗拉长 usr_timer 影响
|
||||
*/
|
||||
uint32_t mcu_util_get_ms(void)
|
||||
{
|
||||
return timer_get_ms();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 协议累加和校验
|
||||
* @param frame 完整帧(含 55 AA)
|
||||
* @param total_len 帧总长度
|
||||
* @return 校验字节
|
||||
*/
|
||||
uint8_t mcu_util_checksum(const uint8_t *frame, uint16_t total_len)
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
uint16_t i;
|
||||
|
||||
if (!frame || total_len < 4) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 2; i < (uint16_t)(total_len - 1); i++) {
|
||||
sum = (uint16_t)(sum + frame[i]);
|
||||
}
|
||||
return (uint8_t)(sum & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 大端读取 uint16
|
||||
* @param buf 字节缓冲
|
||||
* @return 数值
|
||||
*/
|
||||
uint16_t mcu_util_read_u16_be(const uint8_t *buf)
|
||||
{
|
||||
if (!buf) {
|
||||
return 0;
|
||||
}
|
||||
return (uint16_t)(((uint16_t)buf[0] << 8) | buf[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 大端读取 uint32
|
||||
* @param buf 字节缓冲
|
||||
* @return 数值
|
||||
*/
|
||||
uint32_t mcu_util_read_u32_be(const uint8_t *buf)
|
||||
{
|
||||
if (!buf) {
|
||||
return 0;
|
||||
}
|
||||
return ((uint32_t)buf[0] << 24)
|
||||
| ((uint32_t)buf[1] << 16)
|
||||
| ((uint32_t)buf[2] << 8)
|
||||
| (uint32_t)buf[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 大端写入 uint16
|
||||
* @param buf 字节缓冲
|
||||
* @param val 数值
|
||||
*/
|
||||
void mcu_util_write_u16_be(uint8_t *buf, uint16_t val)
|
||||
{
|
||||
if (!buf) {
|
||||
return;
|
||||
}
|
||||
buf[0] = (uint8_t)(val >> 8);
|
||||
buf[1] = (uint8_t)(val & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 大端写入 uint32
|
||||
* @param buf 字节缓冲
|
||||
* @param val 数值
|
||||
*/
|
||||
void mcu_util_write_u32_be(uint8_t *buf, uint32_t val)
|
||||
{
|
||||
if (!buf) {
|
||||
return;
|
||||
}
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)(val & 0xFF);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/******************************************************************************
|
||||
* @file mcu_util.h
|
||||
* @brief MCU 桥通用工具:校验和、大端序、毫秒节拍
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.08.06
|
||||
* @version V1.1.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.08.06, cyWu, 首次发布
|
||||
* - V1.1.0, 2026.08.10, cyWu, 删除空壳 timer_init
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __MCU_UTIL_H__
|
||||
#define __MCU_UTIL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*============================================================================*/
|
||||
/* 外部接口 */
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 获取开机以来的毫秒计数
|
||||
* @return 毫秒计数
|
||||
* @note 基于系统 timer_get_ms,不受低功耗拉长 usr_timer 影响
|
||||
*/
|
||||
uint32_t mcu_util_get_ms(void);
|
||||
|
||||
/**
|
||||
* @brief 协议累加和校验
|
||||
* @param frame 完整帧(含 55 AA)
|
||||
* @param total_len 帧总长度
|
||||
* @return 校验字节
|
||||
* @note 累加范围:LEN 字段起至校验和前一字节
|
||||
*/
|
||||
uint8_t mcu_util_checksum(const uint8_t *frame, uint16_t total_len);
|
||||
|
||||
/**
|
||||
* @brief 大端读取 uint16
|
||||
* @param buf 字节缓冲
|
||||
* @return 数值
|
||||
*/
|
||||
uint16_t mcu_util_read_u16_be(const uint8_t *buf);
|
||||
|
||||
/**
|
||||
* @brief 大端读取 uint32
|
||||
* @param buf 字节缓冲
|
||||
* @return 数值
|
||||
*/
|
||||
uint32_t mcu_util_read_u32_be(const uint8_t *buf);
|
||||
|
||||
/**
|
||||
* @brief 大端写入 uint16
|
||||
* @param buf 字节缓冲
|
||||
* @param val 数值
|
||||
*/
|
||||
void mcu_util_write_u16_be(uint8_t *buf, uint16_t val);
|
||||
|
||||
/**
|
||||
* @brief 大端写入 uint32
|
||||
* @param buf 字节缓冲
|
||||
* @param val 数值
|
||||
*/
|
||||
void mcu_util_write_u32_be(uint8_t *buf, uint32_t val);
|
||||
|
||||
#endif /* __MCU_UTIL_H__ */
|
||||
@@ -10,10 +10,10 @@ copy ..\..\ota.bin .
|
||||
copy ..\..\anc_coeff.bin .
|
||||
copy ..\..\anc_gains.bin .
|
||||
|
||||
..\..\isd_download.exe ..\..\isd_config.ini -tonorflash -dev br28 -boot 0x120000 -div8 -wait 300 -uboot ..\..\uboot.boot -app ..\..\app.bin -res ..\..\cfg_tool.bin tone.cfg p11_code.bin -uboot_compress -key RS-5B88.key
|
||||
..\..\isd_download.exe ..\..\isd_config.ini -tonorflash -dev br28 -boot 0x120000 -div8 -wait 300 -uboot ..\..\uboot.boot -app ..\..\app.bin -res ..\..\cfg_tool.bin tone.cfg p11_code.bin -uboot_compress
|
||||
|
||||
|
||||
:: -format all
|
||||
:: -format all -key RS-5B88.key
|
||||
::-reboot 2500
|
||||
|
||||
@rem 删除临时文件-format all
|
||||
|
||||
Reference in New Issue
Block a user