diff --git a/AC701N.cbp b/AC701N.cbp
index 32008f5..f2b466b 100644
--- a/AC701N.cbp
+++ b/AC701N.cbp
@@ -176,6 +176,7 @@
+
@@ -778,6 +779,10 @@
+
+
+
+
diff --git a/Makefile b/Makefile
index 88b7db4..87fb460 100644
--- a/Makefile
+++ b/Makefile
@@ -250,6 +250,7 @@ INCLUDES := \
-Iapps/usr_le_code/thirdpart/mjson \
-Iapps/usr_jb_proto/Protocol \
-Iapps/usr_jb_proto/Utils \
+ -Iapps/usr_periph \
-I$(SYS_INC_DIR) \
@@ -619,6 +620,7 @@ c_SRC_FILES := \
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_periph/usr_rtc.c \
# usr_le_code 静态库(协议编解码 + 广播/收发)
diff --git a/apps/common/device/key/iokey.c b/apps/common/device/key/iokey.c
index 03ee5e0..95d6b13 100644
--- a/apps/common/device/key/iokey.c
+++ b/apps/common/device/key/iokey.c
@@ -157,7 +157,77 @@ __attribute__((weak)) u8 iokey_filter_hook(u8 io_state)
{
return 0;
}
-u8 usr_first_power=0;
+
+/* 开机锁键剩余确认次数;非 0 时扫描一律返回 NO_KEY */
+static u8 s_boot_lock_cnt;
+
+/**
+ * @brief 启动/关闭开机锁键
+ * @param release_cnt >0:松开后连续确认次数;0:关闭
+ */
+void iokey_boot_lock_start(u8 release_cnt)
+{
+#if TCFG_IOKEY_BOOT_LOCK_ENABLE
+ s_boot_lock_cnt = release_cnt;
+#else
+ (void)release_cnt;
+ s_boot_lock_cnt = 0;
+#endif
+}
+
+/**
+ * @brief 立即关闭开机锁键
+ */
+void iokey_boot_lock_stop(void)
+{
+ s_boot_lock_cnt = 0;
+}
+
+/**
+ * @brief 扫描路径更新锁键:监视 port[0],松开则递减计数
+ * @return 1=仍锁定(应返回 NO_KEY),0=已解锁可正常扫描
+ */
+static u8 iokey_boot_lock_update(void)
+{
+#if !TCFG_IOKEY_BOOT_LOCK_ENABLE
+ return 0;
+#else
+ u8 key_io;
+ u8 io_level;
+ u8 released;
+
+ if (!s_boot_lock_cnt)
+ {
+ return 0;
+ }
+ if (!__this || (__this->num == 0))
+ {
+ return 1;
+ }
+
+ key_io = __this->port[0].key_type.one_io.port;
+ io_level = gpio_read(key_io);
+ if (__this->port[0].connect_way == ONE_PORT_TO_LOW)
+ {
+ released = io_level; /* 上拉输入,松开为高 */
+ }
+ else
+ {
+ released = !io_level; /* 下拉输入,松开为低 */
+ }
+
+ if (released)
+ {
+ s_boot_lock_cnt--;
+ if (s_boot_lock_cnt == 0)
+ {
+ puts("iokey boot lock released\n");
+ }
+ }
+ return 1; /* 本拍仍屏蔽;计数到 0 后下一拍才开放 */
+#endif
+}
+
u8 io_get_key_value(void)
{
int i;
@@ -173,12 +243,7 @@ u8 io_get_key_value(void)
if (!__this->enable) {
return NO_KEY;
}
- if(usr_first_power)
- {
- if(gpio_read(IO_PORTB_01))
- {
- usr_first_power--;
- }
+ if (iokey_boot_lock_update()) {
return NO_KEY;
}
//先扫描单IO接按键方式
@@ -266,7 +331,7 @@ _iokey_get_value_end:
int iokey_init(const struct iokey_platform_data *iokey_data)
{
int i;
- usr_first_power=10;
+
__this = iokey_data;
if (__this == NULL) {
return -EINVAL;
@@ -275,6 +340,12 @@ int iokey_init(const struct iokey_platform_data *iokey_data)
return KEY_NOT_SUPPORT;
}
+ /* 长按开机场景:等电源键(port[0])松开后再开放按键扫描 */
+#if TCFG_IOKEY_BOOT_LOCK_ENABLE
+ iokey_boot_lock_start(IOKEY_BOOT_LOCK_DEFAULT_CNT);
+#else
+ iokey_boot_lock_stop();
+#endif
key_io_reset();
return 0;
diff --git a/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.c b/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.c
index 5354771..0edd9c6 100644
--- a/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.c
+++ b/apps/common/third_party_profile/jieli/JL_rcsp/bt_trans_data/le_rcsp_adv_module.c
@@ -57,6 +57,7 @@
#include "chgbox_box.h"
#endif
+/* usr_le_code 库钩子:由静态库导出,供 RCSP BLE 栈回调,非应用层公开 API */
extern void usr_le_data_recieve(u8* data,u16 len);
extern void usr_ble_adv_init();
#if 1
@@ -526,19 +527,15 @@ static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_h
void usr_ble_send_data(u8* data,u16 len)
{
+ /* CCC 未写时 ATT 发数会失败(常见 app_send_fail:-93),等主机使能通知再发 */
+ if (get_ble_work_state() != BLE_ST_NOTIFY_IDICATE) {
+ log_info("ble send skip, wait CCC");
+ return;
+ }
if (app_send_user_data_check(len))
{
app_send_user_data(ATT_CHARACTERISTIC_15f1e601_a277_43fc_a484_dd39ef8a9100_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
}
- //printf("send rsp:");
- // printf_buf(data,len);
- printf("\n");
- for(u8 i=0;ibytes_data = (pkt->device_bytes_len > 0) ? p : NULL;
-
- printf("cmd = %d", pkt->cmd);
- printf("reserved = %d", pkt->reserved);
- printf("gateway_int_cnt = %d", pkt->gateway_int_cnt);
- printf("device_int_len = %d", pkt->device_int_len);
- printf("device_str_len = %d", pkt->device_str_len);
- printf("device_bytes_len = %d", pkt->device_bytes_len);
+ // printf("cmd = %d", pkt->cmd);
+ // printf("reserved = %d", pkt->reserved);
+ // printf("gateway_int_cnt = %d", pkt->gateway_int_cnt);
+ // printf("device_int_len = %d", pkt->device_int_len);
+ // printf("device_str_len = %d", pkt->device_str_len);
+ // printf("device_bytes_len = %d", pkt->device_bytes_len);
- /* int_data 指向 buf 内部,地址未必 4 字节对齐,
- * 不能直接解引用 int32_t*(对齐访问会触发硬件异常);
- * 必须按字节读取,用 get_be32 还原数值 */
- if (pkt->int_data && pkt->device_int_len >= 4) {
- const uint8_t *ip = (const uint8_t *)pkt->int_data;
- printf("int_data = ");
- for (uint16_t i = 0; i < pkt->device_int_len / 4u; i++) {
- printf("%08X ", (unsigned int)get_be32(ip + (uint32_t)i * 4u));
- }
- printf("\n");
- }
- /* str_data / bytes_data 不保证有 '\0',用 printf_buf 打印 hex */
- if (pkt->str_data && pkt->device_str_len > 0) {
- printf("str_data = ");
- for (size_t i = 0; i < pkt->device_str_len; i++) {
- printf("%02X ", *(pkt->str_data + i));
- }
- printf("\n");
- }
- if (pkt->bytes_data && pkt->device_bytes_len > 0) {
- printf("bytes_data = ");
- for (size_t i = 0; i < pkt->device_bytes_len; i++) {
- printf("%02X ", *(pkt->bytes_data + i));
- }
- printf("\n");
- }
- printf("crc = %04X", crc_recv);
- printf("\n");
+ // /* int_data 指向 buf 内部,地址未必 4 字节对齐,
+ // * 不能直接解引用 int32_t*(对齐访问会触发硬件异常);
+ // * 必须按字节读取,用 get_be32 还原数值 */
+ // if (pkt->int_data && pkt->device_int_len >= 4) {
+ // const uint8_t *ip = (const uint8_t *)pkt->int_data;
+ // printf("int_data = ");
+ // for (uint16_t i = 0; i < pkt->device_int_len / 4u; i++) {
+ // printf("%08X ", (unsigned int)get_be32(ip + (uint32_t)i * 4u));
+ // }
+ // printf("\n");
+ // }
+ // /* str_data / bytes_data 不保证有 '\0',用 printf_buf 打印 hex */
+ // if (pkt->str_data && pkt->device_str_len > 0) {
+ // printf("str_data = ");
+ // for (size_t i = 0; i < pkt->device_str_len; i++) {
+ // printf("%02X ", *(pkt->str_data + i));
+ // }
+ // printf("\n");
+ // }
+ // if (pkt->bytes_data && pkt->device_bytes_len > 0) {
+ // printf("bytes_data = ");
+ // for (size_t i = 0; i < pkt->device_bytes_len; i++) {
+ // printf("%02X ", *(pkt->bytes_data + i));
+ // }
+ // printf("\n");
+ // }
+ // printf("crc = %04X", crc_recv);
+ // printf("\n");
return BLE_PROTO_OK;
}
diff --git a/apps/usr_le_code/bleproto.c b/apps/usr_le_code/bleproto.c
index b53474d..89992ad 100644
--- a/apps/usr_le_code/bleproto.c
+++ b/apps/usr_le_code/bleproto.c
@@ -222,106 +222,113 @@ int bleproto_appdata_encode(uint8_t *txbuf,
int rc;
uint16_t txbuf_size = size;
- bleproto_appdata_t appdata;
+ /*
+ * appdata.data[] 在 SMALL 模式下约 2.3KB,供 JSON/OTA 编码中间缓冲。
+ * JB 55AA 透传可走 bleproto_appdata_wrap_raw,不必经本函数。
+ * 此处用 static,避免在调用方任务栈上临时分配。
+ */
+ static bleproto_appdata_t s_enc_appdata;
+ bleproto_appdata_t *appdata = &s_enc_appdata;
+
/* header */
{
- appdata.header = desc->header;
+ appdata->header = desc->header;
}
/* data */
- if (appdata.header.msgtype == BLEPROTO_APPDATA_MSGTYPE_REQ)
+ if (appdata->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_REQ)
{
- switch (appdata.header.serviceid)
+ switch (appdata->header.serviceid)
{
case E_BLEPROTO_SERVICE_ID_DEVICEINFO:
rc = bleproto_encjson_deviceinfo_req(&desc->datast.deviceinfo_req,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_AUTHSETUP:
rc = bleproto_encjson_authsetup_req(&desc->datast.authsetup_req,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_AUTHDELETE:
rc = bleproto_encjson_authdelete_req(&desc->datast.authdelete_req,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_RUNCMD:
rc = bleproto_encjson_runcmd_req(&desc->datast.runcmd_req,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_REPORTCMD:
rc = bleproto_encjson_reportcmd_req(&desc->datast.reportcmd_req,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_DOACTION:
rc = bleproto_encjson_doaction_req(&desc->datast.doaction_req,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_OTANOTIFY:
rc = bleproto_encjson_otanotify_req(&desc->datast.otanotify_req,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_OTADATA:
rc = bleproto_encjson_otadata_req(&desc->datast.otadata_req,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_RUNCMD_V2:
- rc = ble_proto_pack(&desc->datast.runcmd_v2_req, appdata.data, sizeof(appdata.data));
+ rc = ble_proto_pack(&desc->datast.runcmd_v2_req, appdata->data, sizeof(appdata->data));
break;
case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2:
- rc = ble_proto_pack(&desc->datast.reportcmd_v2_req, appdata.data, sizeof(appdata.data));
+ rc = ble_proto_pack(&desc->datast.reportcmd_v2_req, appdata->data, sizeof(appdata->data));
break;
case E_BLEPROTO_SERVICE_ID_OTADATA_V2:
- rc = ble_proto_pack(&desc->datast.otadata_v2_req, appdata.data, sizeof(appdata.data));
+ rc = ble_proto_pack(&desc->datast.otadata_v2_req, appdata->data, sizeof(appdata->data));
break;
default:
/* unkown serviceid */
return (-1);
}
}
- else if (appdata.header.msgtype == BLEPROTO_APPDATA_MSGTYPE_RSP)
+ else if (appdata->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_RSP)
{
- switch (appdata.header.serviceid)
+ switch (appdata->header.serviceid)
{
case E_BLEPROTO_SERVICE_ID_DEVICEINFO:
rc = bleproto_encjson_deviceinfo_rsp(&desc->datast.deviceinfo_rsp,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_AUTHSETUP:
rc = bleproto_encjson_authsetup_rsp(&desc->datast.authsetup_rsp,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_AUTHDELETE:
rc = bleproto_encjson_authdelete_rsp(&desc->datast.authdelete_rsp,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_RUNCMD:
rc = bleproto_encjson_runcmd_rsp(&desc->datast.runcmd_rsp,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_REPORTCMD:
rc = bleproto_encjson_reportcmd_rsp(&desc->datast.reportcmd_rsp,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_DOACTION:
rc = bleproto_encjson_doaction_rsp(&desc->datast.doaction_rsp,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_OTANOTIFY:
rc = bleproto_encjson_otanotify_rsp(&desc->datast.otanotify_rsp,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_OTADATA:
rc = bleproto_encbin_otadata_rsp(&desc->datast.otadata_rsp,
- appdata.data);
+ appdata->data);
break;
case E_BLEPROTO_SERVICE_ID_RUNCMD_V2:
- rc = ble_proto_pack(&desc->datast.runcmd_v2_rsp, appdata.data, sizeof(appdata.data));
+ rc = ble_proto_pack(&desc->datast.runcmd_v2_rsp, appdata->data, sizeof(appdata->data));
break;
case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2:
- rc = ble_proto_pack(&desc->datast.reportcmd_v2_rsp, appdata.data, sizeof(appdata.data));
+ rc = ble_proto_pack(&desc->datast.reportcmd_v2_rsp, appdata->data, sizeof(appdata->data));
break;
case E_BLEPROTO_SERVICE_ID_OTADATA_V2:
- rc = ble_proto_pack(&desc->datast.otadata_v2_rsp, appdata.data, sizeof(appdata.data));
+ rc = ble_proto_pack(&desc->datast.otadata_v2_rsp, appdata->data, sizeof(appdata->data));
break;
default:
/* unkown serviceid */
@@ -340,10 +347,10 @@ int bleproto_appdata_encode(uint8_t *txbuf,
}
/* datalen */
- appdata.header.datalen = (uint16_t)rc;
+ appdata->header.datalen = (uint16_t)rc;
/* appdata_serialize */
- return bleproto_appdata_serialize(&appdata, packetlen, txbuf, txbuf_size);
+ return bleproto_appdata_serialize(appdata, packetlen, txbuf, txbuf_size);
}
int bleproto_appdata_decode(uint8_t *rxbuf,
diff --git a/apps/usr_le_code/bleproto_packer.c b/apps/usr_le_code/bleproto_packer.c
index c82c16b..b1c6159 100644
--- a/apps/usr_le_code/bleproto_packer.c
+++ b/apps/usr_le_code/bleproto_packer.c
@@ -671,6 +671,55 @@ int bleproto_appdata_serialize(bleproto_appdata_t *appdata,
return (offset);
}
+int bleproto_appdata_wrap_raw(uint8_t *txbuf,
+ uint16_t txbuf_size,
+ const bleproto_appdata_header_t *header,
+ const uint8_t *payload,
+ uint16_t payload_len)
+{
+ uint16_t total;
+
+ if (!txbuf || !header) {
+ BLEPROTO_T_E("Invalid parameters");
+ return -1;
+ }
+ if (payload_len > 0 && !payload) {
+ BLEPROTO_T_E("Invalid payload");
+ return -1;
+ }
+ /* 单帧 this_frame_len 为 uint8,超过 255 需走分包 serialize */
+ if (payload_len > 255u) {
+ BLEPROTO_T_E("payload too long for single frame");
+ return -1;
+ }
+
+ total = (uint16_t)(BLEPROTO_APPDATA_HEADR_LEN + payload_len);
+ if (txbuf_size < total) {
+ BLEPROTO_T_E("txbuf too short");
+ return -1;
+ }
+
+ /* buf[0]: version[2:0] | datafmt[3:3] | msgtype[7:4] */
+ txbuf[0] = UTILS_BITFIELD_SET(header->version, 2, 0) |
+ UTILS_BITFIELD_SET(header->datafmt, 3, 3) |
+ UTILS_BITFIELD_SET(header->msgtype, 7, 4);
+ /* buf[1]: msgid[3:0] | encrypt[4:4] | reserve[7:5] */
+ txbuf[1] = UTILS_BITFIELD_SET(header->msgid, 3, 0) |
+ UTILS_BITFIELD_SET(header->encrypt, 4, 4) |
+ UTILS_BITFIELD_SET(header->reserve, 7, 5);
+ txbuf[2] = 1; /* totalframe */
+ txbuf[3] = 0; /* frameseq:单帧为 0 */
+ txbuf[4] = (uint8_t)payload_len; /* this frame payload len */
+ txbuf[5] = header->serviceid;
+ proto_bytes_put_le16(&txbuf[6], payload_len);
+
+ if (payload_len > 0) {
+ memcpy(&txbuf[BLEPROTO_APPDATA_HEADR_LEN], payload, payload_len);
+ }
+
+ return (int)total;
+}
+
int bleproto_appdata_deserialize(uint8_t * buf,
uint16_t len,
bleproto_appdata_t *appdata)
@@ -1958,8 +2007,12 @@ int bleproto_encbin_otadata_rsp(const bleproto_otadata_rsp_t *p,
data[offset++] = (uint8_t)((p->len >> 16) & 0xFF);
data[offset++] = (uint8_t)((p->len >> 24) & 0xFF);
- /* serialize data */
+ /* serialize data(data 为外部指针,不再内嵌数组) */
if (p->len > 0 && p->len <= BLEPROTO_APPDATA_OTADATA_SZ) {
+ if (!p->data) {
+ BLEPROTO_T_E("otadata_rsp.data is NULL");
+ return -1;
+ }
memcpy(&data[offset], p->data, p->len);
offset += p->len;
}
@@ -2984,10 +3037,12 @@ int bleproto_debin_otadata_rsp(const uint8_t * data,
return -1;
}
- /* deserialize data */
+ /* 零拷贝:指向输入缓冲,调用方须在下次 decode 前用完 */
if (rsp->len > 0) {
- memcpy(rsp->data, &data[offset], rsp->len);
+ rsp->data = &data[offset];
offset += rsp->len;
+ } else {
+ rsp->data = NULL;
}
return offset;
diff --git a/apps/usr_le_code/bleproto_packer.h b/apps/usr_le_code/bleproto_packer.h
index 9b5661f..8ec82c1 100644
--- a/apps/usr_le_code/bleproto_packer.h
+++ b/apps/usr_le_code/bleproto_packer.h
@@ -483,7 +483,12 @@ typedef struct bleproto_otadata_rsp {
int id; ///< file_id
int32_t offset; ///< 当前读取到的数据偏移
uint32_t len; ///< 当次读取数据的大小
- uint8_t data[BLEPROTO_APPDATA_OTADATA_SZ]; ///< 读取的数据
+ /**
+ * 固件数据指针(不内嵌大数组,避免 bleproto_appdata_desc_t 膨胀到 2KB+)
+ * - decode:指向 appdata 内部缓冲(零拷贝),下次 decode 前有效
+ * - encode:由调用方提供可读缓冲
+ */
+ const uint8_t *data;
} bleproto_otadata_rsp_t;
/****************************************************************************/
/* Public Data */
@@ -580,6 +585,22 @@ int bleproto_appdata_serialize(bleproto_appdata_t *appdata,
uint8_t * buf,
uint16_t size);
+/**
+ * @brief 将已打包好的 payload 包装成单帧 appdata(不分包)
+ * @param txbuf 输出缓冲
+ * @param txbuf_size 输出缓冲大小
+ * @param header 应用层头(datalen/totalframe/frameseq 由本函数填写)
+ * @param payload 已序列化的 service 数据;可为 NULL(payload_len==0)
+ * @param payload_len payload 长度,须 <=255(单帧 pthis_frame_len 为 u8)
+ * @return >0 总字节数;<0 失败
+ * @note 小包场景(JB 55AA 透传等)用此接口,避免 bleproto_appdata_t 大缓冲
+ */
+int bleproto_appdata_wrap_raw(uint8_t *txbuf,
+ uint16_t txbuf_size,
+ const bleproto_appdata_header_t *header,
+ const uint8_t *payload,
+ uint16_t payload_len);
+
/**
* @brief 反序列化应用数据
*
diff --git a/apps/usr_le_code/lib/libusr_le_code.a b/apps/usr_le_code/lib/libusr_le_code.a
index 5509907..f337979 100644
Binary files a/apps/usr_le_code/lib/libusr_le_code.a and b/apps/usr_le_code/lib/libusr_le_code.a differ
diff --git a/apps/usr_le_code/usr_le_adv.c b/apps/usr_le_code/usr_le_adv.c
index befd16e..9faa88c 100644
--- a/apps/usr_le_code/usr_le_adv.c
+++ b/apps/usr_le_code/usr_le_adv.c
@@ -1,102 +1,163 @@
+/******************************************************************************
+ * @file usr_le_adv.c
+ * @brief BLE 广播 / 配对 / OTA 广播切换
+ * @author cyWu <1917507415@qq.com>
+ * @date 2026.08.19
+ * @version V1.1.0
+ * @history
+ * - V1.0.0, 2026.08.03, cyWu, 首次发布
+ * - V1.1.0, 2026.08.19, cyWu, 对齐模组注释与助手;保留 SOC 上电绑广播策略
+ ******************************************************************************/
+
#include "system/includes.h"
#include "app_config.h"
-#include "asm/pwm_led.h"
-#include "tone_player.h"
-#include "ui_manage.h"
#include "app_main.h"
-#include "app_task.h"
-#include "asm/charge.h"
-#include "app_power_manage.h"
-#include "app_charge.h"
-#include "user_cfg.h"
-
-#include "audio.h"
#include "vm.h"
#include "bleproto.h"
#include "bleproto_api.h"
#include "usr_le_product.h"
-#define LOG_TAG_CONST APP
-#define LOG_TAG "[APP]"
+
+#define LOG_TAG_CONST APP
+#define LOG_TAG "[LE_ADV]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
-/* #define LOG_DUMP_ENABLE */
-#define LOG_CLI_ENABLE
#include "debug.h"
-extern u8 muti_adv_data[31];//={0};
+/******************************************************************************
+ * 广播相关三个标志(务必区分):
+ *
+ * 1) usr_auth_data.paired_flag —— 配网结果(存 VM,掉电保持)
+ * - 0:未配网
+ * - 1:已配网(三元组已保存)
+ *
+ * 2) usr_var.usr_goto_pair —— 是否主动进入配网流程(RAM,掉电丢失)
+ * - 0:非配网流程
+ * - 1:app_main 上电 / usr_goto_pair_mode() 触发,发【绑定广播】
+ *
+ * 3) usr_var.usr_adv_flag —— 广播内容是否需要刷新到协议栈(一次性)
+ * - 1:usr_ble_adv_updata() 会重新 set adv data 并 enable
+ * - 0:本周期不刷新
+ *
+ * SOC 决策表(与模组不同:未配网也发绑定广播,便于上电配网):
+ * usr_goto_pair==1 → 绑定广播
+ * paired_flag==0 → 绑定广播
+ * paired_flag==1 → 回连广播
+ ******************************************************************************/
+
+extern u8 muti_adv_data[31];
extern u8 muti_adv_data_len;
/* 定义在 usr_le_recieve.c,库内共用,不对外导出 */
extern bleproto_authsetup_req_t usr_auth_data;
-extern u8 usr_get_full();
-extern u16 usr_get_conn_service();
-extern int muti_make_set_adv_data(u8* data,u8 data_len);
-extern u8 usr_get_ldoin_all();
+extern u16 usr_get_conn_service(void);
+extern int muti_make_set_adv_data(u8 *data, u8 data_len);
+extern int muti_make_set_adv_data_updata(void);
+extern void usr_set_adv_interval(u16 val);
+extern u16 usr_get_adv_interval(void);
+extern void ble_multi_trans_disconnect(void);
+extern void ble_trans_module_enable(u8 flag);
+extern void usr_timer_loop(void);
+extern u8 usr_get_ota_status(void);
+extern void usr_ota_exit(void);
-void usr_ble_adv_updata();
+void usr_ble_adv_init(void);
+void usr_ble_adv_updata(void);
-static int le_timer_handle=0;
-static int le_timer_handle2=0;
+static int le_timer_handle = 0;
-
-extern u8 get_ldo5v_online_hw(void);
-extern u8 usr_get_work_status();
-extern void usr_printf_sta();
-extern int muti_make_set_adv_data_updata();
-
-void usr_get_pair_info()
+/**
+ * @brief BLE 是否已连接
+ * @return 1=已连接,0=未连接
+ */
+uint8_t usr_ble_is_connected(void)
{
- int ret = 0xffff;
+ return (usr_get_conn_service() != 0) ? 1u : 0u;
+}
+
+/**
+ * @brief 从 VM 读取配对信息到 usr_auth_data
+ * @note 失败则清零,并将 paired_flag 置 0 写回
+ */
+void usr_get_pair_info(void)
+{
+ int ret;
+
ret = syscfg_read(CFG_USER_PAIR_INFO, (u8 *)&usr_auth_data, sizeof(usr_auth_data));
- if(ret<=0)
+ if (ret <= 0)
{
- memset(&usr_auth_data,0x00,sizeof(usr_auth_data));
- usr_auth_data.paired_flag=0;
+ memset(&usr_auth_data, 0x00, sizeof(usr_auth_data));
+ usr_auth_data.paired_flag = 0;
syscfg_write(CFG_USER_PAIR_INFO, (u8 *)&usr_auth_data, sizeof(usr_auth_data));
}
}
-void usr_write_pair_info()
+
+/**
+ * @brief 标记已配网并保存三元组到 VM
+ * @note AUTHSETUP 成功后调用,paired_flag = 1
+ */
+void usr_write_pair_info(void)
{
- 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));
}
-void usr_clear_pair_info()
+/**
+ * @brief 清除配对信息并延时复位
+ */
+void usr_clear_pair_info(void)
{
- printf("usr_clear_pair_info\n");
- memset(&usr_auth_data,0x00,sizeof(usr_auth_data));
- usr_auth_data.paired_flag=0;
+ printf("usr_clear_pair_info_reset\n");
+ memset(&usr_auth_data, 0x00, sizeof(usr_auth_data));
+ usr_auth_data.paired_flag = 0;
syscfg_write(CFG_USER_PAIR_INFO, (u8 *)&usr_auth_data, sizeof(usr_auth_data));
- sys_timeout_add(NULL,cpu_reset,600);
+ sys_timeout_add(NULL, cpu_reset, 600);
}
-void usr_clear_pair_info_noreset()
+
+/**
+ * @brief 清除配对信息但不复位(用于重新配网)
+ */
+void usr_clear_pair_info_noreset(void)
{
- printf("usr_clear_pair_info2\n");
- memset(&usr_auth_data,0x00,sizeof(usr_auth_data));
- usr_auth_data.paired_flag=0;
+ printf("usr_clear_pair_info_noreset\n");
+ memset(&usr_auth_data, 0x00, sizeof(usr_auth_data));
+ usr_auth_data.paired_flag = 0;
syscfg_write(CFG_USER_PAIR_INFO, (u8 *)&usr_auth_data, sizeof(usr_auth_data));
}
-extern void usr_set_adv_interval(u16 val);
-extern u16 usr_get_adv_interval();
-extern void ble_multi_trans_disconnect(void);
-void usr_ble_adv_init();
-void usr_goto_pair_mode()
+/**
+ * @brief 进入配网模式:清配对 + 置 usr_goto_pair + 发绑定广播
+ */
+void usr_goto_pair_mode(void)
{
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();
}
-
-void usr_ble_adv_init()
+/**
+ * @brief 断开 BLE 并停止广播(复位/重启前)
+ */
+void usr_ble_disconnect_and_stop_adv(void)
{
- int8_t txpower = 0;
- uint8_t manucode[BLEPROTO_ADV_TLV_LENGTH_MANUCODE] = { 0 };
+ printf("usr_ble_disconnect_and_stop_adv\n");
+ ble_multi_trans_disconnect();
+ usr_var.usr_goto_pair = 0;
+ usr_var.usr_adv_flag = 0;
+ ble_trans_module_enable(0);
+}
+
+/**
+ * @brief 按当前标志刷新广播策略并启动周期更新
+ * @note 见文件头「三个标志」;SOC 未配网也发绑定广播
+ */
+void usr_ble_adv_init(void)
+{
+ int8_t txpower = 0;
+ uint8_t manucode[BLEPROTO_ADV_TLV_LENGTH_MANUCODE] = {0};
uint8_t prodcode[BLEPROTO_ADV_TLV_LENGTH_PRODCODE];
uint8_t gmac[6] = {0};
uint8_t pcode[BLE_PROTO_ADV_LENGTH_PCODE];
@@ -106,106 +167,111 @@ void usr_ble_adv_init()
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)
+ if (usr_var.usr_ota_succ_flag)
+ {
+ return;
+ }
+
+ 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);
- }
- usr_var.usr_adv_flag=1;
+ 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)
+ if (usr_auth_data.paired_flag == 0)
{
- muti_adv_data_len=bleproto_advdata_encode4bind(muti_adv_data,txpower,manucode,pcode,prodcode);
- usr_var.usr_adv_flag=0;
+ /* SOC:未配网也发绑定广播(模组此处为不广播) */
+ muti_adv_data_len = bleproto_advdata_encode4bind(muti_adv_data, txpower,
+ manucode, pcode, prodcode);
+ usr_var.usr_adv_flag = 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;
+ 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_ble_adv_updata();
- if(le_timer_handle==0)le_timer_handle = sys_timer_add(NULL, usr_ble_adv_updata, 500);
+ if (le_timer_handle == 0)
+ {
+ le_timer_handle = sys_timer_add(NULL, usr_ble_adv_updata, 500);
+ }
}
-u8 usr_get_pair_flag()
+/**
+ * @brief 获取是否已配网
+ * @return 1=已配网,0=未配网
+ */
+u8 usr_get_pair_flag(void)
{
return usr_auth_data.paired_flag;
}
-/*
-void usr_reconn_adv()
+
+/**
+ * @brief 周期处理广播刷新(由 500ms 定时器调用)
+ * @note 仅当 usr_adv_flag==1 时:停广播 → 写入 muti_adv_data → 再开广播
+ */
+void usr_ble_adv_updata(void)
{
- int8_t txpower = 0;
- uint8_t gmac[6]={0};
- uint8_t manucode[BLEPROTO_ADV_TLV_LENGTH_MANUCODE] = { 0 };
- uint8_t prodcode[BLEPROTO_ADV_TLV_LENGTH_PRODCODE] = {'C', 'B', 'F', 'D'};
- uint8_t pcode[6]={'P','C','B','F','D','0'};
- memcpy(gmac,usr_auth_data.gwmac,6);
- 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();
-void usr_ble_adv_updata()
-{
- //printf("usr_ble_adv_updata\n");
- static u16 usr_goto_slow_adv=0;
- if(usr_var.usr_adv_flag)
+ static u16 usr_goto_slow_adv = 0;
+
+ if (usr_var.usr_adv_flag)
{
ble_trans_module_enable(0);
- usr_var.usr_adv_flag=0;
- muti_make_set_adv_data(muti_adv_data,muti_adv_data_len);
+ 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);
+ printf_buf(muti_adv_data, muti_adv_data_len);
ble_trans_module_enable(1);
}
- if(usr_get_conn_service()==0)
+ if (!usr_ble_is_connected())
{
- if(usr_get_adv_interval()==80)
+ /* 未连接:回连快广播(80)持续约 60s(500ms×120)后切慢广播 */
+ if (usr_get_adv_interval() == 80)
{
- if((usr_var.usr_goto_pair==0)&&(usr_auth_data.paired_flag))
+ if ((usr_var.usr_goto_pair == 0) && usr_auth_data.paired_flag)
{
- if(usr_var.usr_ota_succ_flag==0)
+ if (usr_var.usr_ota_succ_flag == 0)
{
usr_goto_slow_adv++;
- printf("usr_goto_slow_adv = %d\n",usr_goto_slow_adv);
+ printf("usr_goto_slow_adv = %d\n", usr_goto_slow_adv);
}
- if(usr_goto_slow_adv>=120)
+ if (usr_goto_slow_adv >= 120)
{
- usr_goto_slow_adv=0;
- usr_set_adv_interval(80*10);
- usr_var.usr_adv_flag=1;
+ usr_goto_slow_adv = 0;
+ usr_set_adv_interval(80 * 10);
+ usr_var.usr_adv_flag = 1;
}
}
}
else
{
- usr_goto_slow_adv=0;
+ usr_goto_slow_adv = 0;
}
}
else
{
- usr_goto_slow_adv=0;
+ usr_goto_slow_adv = 0;
}
-
- if(usr_get_ota_status()==0)
+ if (usr_get_ota_status() == 0)
{
- if(usr_get_conn_service()==0)
+ if (!usr_ble_is_connected())
{
- if(usr_var.usr_ota_succ_flag==0)usr_ota_exit();
+ if (usr_var.usr_ota_succ_flag == 0)
+ {
+ usr_ota_exit();
+ }
}
}
@@ -213,36 +279,36 @@ void usr_ble_adv_updata()
usr_timer_loop();
}
-void usr_soft_off()
+void usr_soft_off(void)
{
sys_enter_soft_poweroff(NULL);
}
-void usr_ble_adv_updata_OTA()
+void usr_ble_adv_updata_OTA(void)
{
- //printf("usr_ble_adv_updata\n");
ble_trans_module_enable(0);
- usr_var.usr_adv_flag=0;
+ usr_var.usr_adv_flag = 0;
extern u8 usr_mac_addr[6];
extern int le_controller_set_mac(void *addr);
- usr_mac_addr[0]=usr_mac_addr[0]+1;
- le_controller_set_mac(usr_mac_addr); //修改BLE地址
+ usr_mac_addr[0] = usr_mac_addr[0] + 1;
+ le_controller_set_mac(usr_mac_addr);
muti_make_set_adv_data_updata();
printf("###muti_adv_data = ");
- printf_buf(muti_adv_data,muti_adv_data_len);
+ printf_buf(muti_adv_data, muti_adv_data_len);
ble_trans_module_enable(1);
}
-void usr_ota_process()
+void usr_ota_process(void)
{
static u8 cnt = 0;
+
if (cnt == 0)
{
ble_multi_trans_disconnect();
}
- if (usr_get_conn_service() == 0)
+ if (!usr_ble_is_connected())
{
cnt++;
if (cnt == 2)
@@ -261,7 +327,10 @@ void usr_ota_process()
}
}
-void usr_app_ota_init()
+/**
+ * @brief 旧版 RCSP/JSON OTA 入口;产品 JB 0x30/0x32 路径不要调用
+ */
+void usr_app_ota_init(void)
{
usr_var.usr_goto_updata = 1;
if (usr_var.ota_timer == 0)
diff --git a/apps/usr_le_code/usr_le_api.h b/apps/usr_le_code/usr_le_api.h
index 5e5b20f..4ccb3ba 100644
--- a/apps/usr_le_code/usr_le_api.h
+++ b/apps/usr_le_code/usr_le_api.h
@@ -1,11 +1,15 @@
/******************************************************************************
* @file usr_le_api.h
- * @brief usr_le_code 静态库对外 API(广播 / 收发 / 配网)
+ * @brief usr_le_code 静态库对外应用 API(配网 / 配对 / OTA)
* @author cyWu <1917507415@qq.com>
* @date 2026.08.03
- * @version V1.0.0
+ * @version V1.0.1
* @history
* - V1.0.0, 2026.08.03, cyWu, 首次发布
+ * - V1.0.1, 2026.08.19, cyWu, 收敛公开 API,移除 BLE 栈钩子声明
+ *
+ * @note usr_ble_adv_init / usr_le_data_recieve 为 BLE/RCSP 协议栈链接钩子,
+ * 由库内部实现并导出符号,不作为应用层公开接口。
******************************************************************************/
#ifndef __USR_LE_API_H__
@@ -17,20 +21,6 @@
extern "C" {
#endif
-/**
- * @brief 初始化 BLE 广播数据(绑定广播或重连广播)
- * @note 根据配对状态与 usr_goto_pair 选择 bind/reconn 广播,并启动 500ms 周期更新
- */
-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 进入配对/配网模式
* @note 断开当前连接、清除配对信息(不复位),重新发绑定广播
diff --git a/apps/usr_le_code/usr_le_recieve.c b/apps/usr_le_code/usr_le_recieve.c
index 5a28e16..9c6eaa1 100644
--- a/apps/usr_le_code/usr_le_recieve.c
+++ b/apps/usr_le_code/usr_le_recieve.c
@@ -1,181 +1,202 @@
+/******************************************************************************
+ * @file usr_le_recieve.c
+ * @brief BLE 收包入口:bleproto 解析后分发配网 / 对时 / JB 协议 / 组应答
+ * @author cyWu <1917507415@qq.com>
+ * @date 2026.08.19
+ * @version V1.1.0
+ * @history
+ * - V1.0.0, 2026.08.03, cyWu, 首次发布
+ * - V1.1.0, 2026.08.19, cyWu, 对齐模组结构;废弃 JSON OTA;修 AUTHDELETE serviceid
+ ******************************************************************************/
+
#include "system/includes.h"
#include "app_config.h"
-#include "asm/pwm_led.h"
-#include "tone_player.h"
-#include "ui_manage.h"
#include "app_main.h"
-#include "app_task.h"
-#include "asm/charge.h"
-#include "app_power_manage.h"
-#include "app_charge.h"
-#include "user_cfg.h"
-#include "key_event_deal.h"
-#include "audio.h"
-#include "update.h"
#include "vm.h"
#include "bleproto.h"
#include "bleproto_api.h"
#include "ble_proto.h"
+#include "usr_rtc.h"
+#include "usr_le_api.h"
+#include "jb_protocol.h"
+
#define LOG_TAG_CONST APP
-#define LOG_TAG "[APP]"
+#define LOG_TAG "[USR_LE]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
-/* #define LOG_DUMP_ENABLE */
-#define LOG_CLI_ENABLE
#include "debug.h"
-#define FIRM_PACK_LEN 2048 // 128
+/* 拼 GATT 分包:业务包 ≈ bleproto头 + V2 开销 + JB 帧(<=128),1024 足够 */
+#define USR_LE_RX_BUF_LEN 1024
+#define USR_LE_V2_WRAP_OVERHEAD 32u /* V2 头开销,JB 帧最大 128 → 约 160 */
+#define USR_LE_V2_CMD_REPORT 100u /* REPORTCMD_V2 内层 cmd */
+#define USR_LE_V2_CMD_RUN 110u /* RUNCMD_V2 内层 cmd */
+#define USR_LE_JB_CMD_OFF 4u /* 55 AA | LEN_H LEN_L | CMD */
-static u8 start_data[10] = {0x55, 0xAA, 0xFE, 0x61, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00};
-static u8 end_data[2] = {0xaa, 0x55};
-static int encode_len = 0x00;
+static int encode_len = 0;
static u8 txbuf[384] = {0};
-static u8 rxbuf[FIRM_PACK_LEN + 1024] = {0};
-static u8 ota_source_data[FIRM_PACK_LEN * 2] = {0};
-
-extern u16 usr_get_conn_service();
-extern void ble_multi_trans_disconnect(void);
-extern void usr_ble_send_data(u8 *data, u16 len); /// BLE发送接口,MTU 244
-extern void usr_write_pair_info();
-extern void usr_clear_pair_info();
-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);
-
-void usr_ota_deal_task();
-void usr_data_ana(bleproto_appdata_desc_t *desc);
-void usr_run_cmd_code_v2(ble_proto_packet_t *runcmd_par, u8 usr_msg_id);
+static u8 rxbuf[USR_LE_RX_BUF_LEN] = {0};
+static u8 s_last_runcmd_msgid = 0; /* RUNCMD_V2 应答须回填最近 msgid */
bleproto_authsetup_req_t usr_auth_data;
-void usr_le_data_recieve(u8 *data, u16 len) /// BLE数据接收
-{
- // log_info("le recieve: %d",len);
- // printf_buf(data, len);
- static u16 usr_len = 0;
- bleproto_appdata_desc_t desc;
+extern void usr_ble_send_data(u8 *data, u16 len);
+extern u8 usr_ble_is_notify_ready(void);
+extern void usr_write_pair_info(void);
+extern void usr_clear_pair_info(void);
+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);
+static void usr_data_ana(bleproto_appdata_desc_t *desc);
+static void usr_run_cmd_code_v2(ble_proto_packet_t *runcmd_par, u8 usr_msg_id);
+
+/**
+ * @brief 填 bleproto 应答头
+ * @param out 输出 desc
+ * @param in 请求 desc(取 msgid)
+ * @param serviceid 服务号
+ */
+static void usr_le_fill_rsp_header(bleproto_appdata_desc_t *out,
+ const bleproto_appdata_desc_t *in,
+ uint8_t serviceid)
+{
+ out->header.version = 0;
+ out->header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
+ out->header.msgtype = BLEPROTO_APPDATA_MSGTYPE_RSP;
+ out->header.msgid = in->header.msgid;
+ out->header.encrypt = 0;
+ out->header.serviceid = serviceid;
+}
+
+/**
+ * @brief 编码并经 BLE 发出
+ * @param desc 已填好的应答
+ */
+static void usr_le_encode_and_send(bleproto_appdata_desc_t *desc)
+{
+ encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), desc);
+ if (encode_len > 0)
+ {
+ printf("encode_len = %d\n", encode_len);
+ usr_ble_send_data(txbuf, encode_len);
+ }
+ else
+ {
+ printf("encode_len fail %d\n", encode_len);
+ }
+}
+
+/**
+ * @brief 是否走网关主动上报(REPORTCMD_V2)
+ * @param jb_cmd 55AA 命令字
+ * @return 1=主动上报,0=RUNCMD 应答
+ */
+static uint8_t usr_le_is_gateway_report_cmd(uint8_t jb_cmd)
+{
+ return (jb_cmd == CMD_REPORT ||
+ jb_cmd == CMD_OTA_COMPLETE ||
+ jb_cmd == CMD_OTA_STOP_MCU)
+ ? 1u
+ : 0u;
+}
+
+/**
+ * @brief BLE 收包入口
+ * @param data 收包数据
+ * @param len 数据长度
+ */
+void usr_le_data_recieve(u8 *data, u16 len)
+{
+ static u16 usr_len = 0;
+ /* desc 含 ycmd 等 union,放 static,避免每次收包在栈上开大块 */
+ static bleproto_appdata_desc_t s_rx_desc;
int rc_result = 0;
+ if (!data || len == 0)
+ {
+ return;
+ }
+ if ((u32)usr_len + len > sizeof(rxbuf))
+ {
+ 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);
- // printf("rc_result_le## = %d\n",rc_result);
+ rc_result = bleproto_appdata_decode(rxbuf, usr_len, &s_rx_desc);
if (rc_result < 0)
{
- // 接收到了非法的数据包,无法解析
printf("### invild pack\n");
usr_len = 0;
}
else if (rc_result == 0)
{
- // 接收的数据不完整,继续接收数据
printf("### keep recieving\n");
}
- else //(rc_result > 0)
+ else
{
- // 数据解析成功
printf("### pack recieved ok\n");
usr_len = 0;
- usr_data_ana(&desc);
+ usr_data_ana(&s_rx_desc);
}
}
-void usr_data_ana(bleproto_appdata_desc_t *desc)
+/**
+ * @brief 解析 bleproto 服务并分发
+ * @param desc 已 decode 的包
+ */
+static void usr_data_ana(bleproto_appdata_desc_t *desc)
{
- bleproto_appdata_desc_t encode_desc = {0};
- printf("#############334 desc->header.serviceid = %d\n", desc->header.serviceid);
- if (desc->header.msgtype /*desc.header.msgtype*/ == BLEPROTO_APPDATA_MSGTYPE_REQ)
+ static bleproto_appdata_desc_t s_encode_desc;
+
+ memset(&s_encode_desc, 0, sizeof(s_encode_desc));
+ printf("desc serviceid=%d msgtype=%d\n",
+ desc->header.serviceid, desc->header.msgtype);
+
+ if (desc->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_REQ)
{
switch (desc->header.serviceid)
{
+ case E_BLEPROTO_SERVICE_ID_DEVICEINFO: {
+ bleproto_deviceinfo_req_t *req = &desc->datast.deviceinfo_req;
+ bleproto_deviceinfo_rsp_t *rsp = &s_encode_desc.datast.deviceinfo_rsp;
- case E_BLEPROTO_SERVICE_ID_DEVICEINFO:
+ /* 网关从子设备连上开始计时,每 12 小时经 DEVICEINFO 同步一次 */
+ usr_rtc_set_from_unix(req->t, (int32_t)req->gmtoff);
- encode_desc.header.version = 0;
- encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
- encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_RSP;
- encode_desc.header.msgid = desc->header.msgid; // 这里的msg_id为上面解析到的包的msg_id;
- encode_desc.header.encrypt = 0;
- encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_DEVICEINFO;
-
- // deviceinfo rsp序列化
- bleproto_deviceinfo_rsp_t *rsp = &encode_desc.datast.deviceinfo_rsp;
- {
- // 填写设备相关信息
- rsp->hbcycle = 1000;
- strcpy(rsp->swv, "V1.0.0.00");
- strcpy(rsp->hwv, "V1.0.0.00");
- rsp->longcon = 1;
- rsp->prototype = 4;
- }
- encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), &encode_desc);
- if (encode_len > 0)
- {
- printf("encode_len = %d\n", encode_len);
- // 调用蓝牙协议栈发送数据接口,将数据一包一包的发送出去
- // 第一包:packetlen
- // 第二包:packetlen
- // ......
- // 第N包: totallen - (packetlen * (N -1))
- usr_ble_send_data(txbuf, encode_len);
- }
- else
- {
- printf("2encode_len = %d\n", encode_len);
- }
- // printf("E_BLEPROTO_SERVICE_ID_DEVICEINFO\n");
+ usr_le_fill_rsp_header(&s_encode_desc, desc, E_BLEPROTO_SERVICE_ID_DEVICEINFO);
+ rsp->hbcycle = 1000;
+ strcpy(rsp->swv, "V1.0.0.00");
+ strcpy(rsp->hwv, "V1.0.0.00");
+ rsp->longcon = 1;
+ rsp->prototype = 4;
+ usr_le_encode_and_send(&s_encode_desc);
break;
- case E_BLEPROTO_SERVICE_ID_AUTHSETUP:
- // 设备处理,回复响应
+ }
+ case E_BLEPROTO_SERVICE_ID_AUTHSETUP: {
+ bleproto_authsetup_rsp_t *au_rsp = &s_encode_desc.datast.authsetup_rsp;
+
printf("E_BLEPROTO_SERVICE_ID_AUTHSETUP\n");
- encode_desc.header.version = 0;
- encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
- encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_RSP;
- encode_desc.header.msgid = desc->header.msgid; // 这里的msg_id为上面解析到的包的msg_id;
- encode_desc.header.encrypt = 0;
- encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_AUTHSETUP;
-
- bleproto_authsetup_rsp_t *au_rsp = &encode_desc.datast.authsetup_rsp;
+ usr_le_fill_rsp_header(&s_encode_desc, desc, E_BLEPROTO_SERVICE_ID_AUTHSETUP);
au_rsp->errcode = 0;
-
memcpy(&usr_auth_data, &desc->datast.authsetup_req, sizeof(usr_auth_data));
+ if (usr_auth_data.paired_flag == 0)
{
- // 保存三元组
- if (usr_auth_data.paired_flag == 0)
- {
- usr_write_pair_info();
- printf("usr_auth_data %s %s ", usr_auth_data.authcode, usr_auth_data.devid);
- printf_buf(usr_auth_data.gwmac, 6);
- }
- }
-
- encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), &encode_desc);
- if (encode_len > 0)
- {
- printf("encode_len = %d\n", encode_len);
- usr_ble_send_data(txbuf, encode_len);
- }
- else
- {
- printf("2encode_len = %d\n", encode_len);
+ usr_write_pair_info();
+ printf("usr_auth_data %s %s ", usr_auth_data.authcode, usr_auth_data.devid);
+ printf_buf(usr_auth_data.gwmac, 6);
}
+ usr_le_encode_and_send(&s_encode_desc);
break;
- case E_BLEPROTO_SERVICE_ID_AUTHDELETE:
- // 设备处理,回复响应
- printf("E_BLEPROTO_SERVICE_ID_AUTHDELETE\n");
- encode_desc.header.version = 0;
- encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
- encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_RSP;
- encode_desc.header.msgid = desc->header.msgid; // 这里的msg_id为上面解析到的包的msg_id;
- encode_desc.header.encrypt = 0;
- encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_AUTHSETUP;
+ }
+ case E_BLEPROTO_SERVICE_ID_AUTHDELETE: {
+ bleproto_authdelete_rsp_t *aude_rsp = &s_encode_desc.datast.authdelete_rsp;
- bleproto_authdelete_rsp_t *aude_rsp = &encode_desc.datast.authdelete_rsp;
+ printf("E_BLEPROTO_SERVICE_ID_AUTHDELETE\n");
+ usr_le_fill_rsp_header(&s_encode_desc, desc, E_BLEPROTO_SERVICE_ID_AUTHDELETE);
memcpy(aude_rsp->gwmac, usr_auth_data.gwmac, 6);
if (!memcmp(usr_auth_data.authcode, desc->datast.authdelete_req.authcode, 32))
{
@@ -186,20 +207,10 @@ void usr_data_ana(bleproto_appdata_desc_t *desc)
{
aude_rsp->errcode = 501;
}
-
- encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), &encode_desc);
- if (encode_len > 0)
- {
- printf("encode_len = %d\n", encode_len);
- usr_ble_send_data(txbuf, encode_len);
- }
- else
- {
- printf("2encode_len = %d\n", encode_len);
- }
+ usr_le_encode_and_send(&s_encode_desc);
break;
+ }
case E_BLEPROTO_SERVICE_ID_RUNCMD:
- // 设备处理,回复响应
printf("E_BLEPROTO_SERVICE_ID_RUNCMD\n");
break;
case E_BLEPROTO_SERVICE_ID_RUNCMD_V2:
@@ -207,108 +218,31 @@ void usr_data_ana(bleproto_appdata_desc_t *desc)
usr_run_cmd_code_v2(&desc->datast.runcmd_v2_req, desc->header.msgid);
break;
case E_BLEPROTO_SERVICE_ID_OTANOTIFY:
- printf("E_BLEPROTO_SERVICE_ID_OTANOTIFY\n");
- encode_desc.header.version = 0;
- encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
- encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_RSP;
- encode_desc.header.msgid = desc->header.msgid; // 这里的msg_id为上面解析到的包的msg_id;
- encode_desc.header.encrypt = 0;
- encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_OTANOTIFY;
- encode_desc.datast.doaction_rsp.errcode = 0;
-
- bleproto_otanotify_rsp_t *in_ota_rsp = &encode_desc.datast.otanotify_rsp;
-
- bleproto_otanotify_req_t *in_ota_data2 = &desc->datast.otanotify_req;
- printf("in_ota_data id = %d\n", in_ota_data2->id);
- printf("in_ota_data ver = %s\n", in_ota_data2->version);
- printf("in_ota_data size= %d\n", in_ota_data2->size);
- printf("in_ota_data md5 = %s\n", in_ota_data2->md5);
- {
- in_ota_rsp->errcode = 0;
- // 执行命令
- }
-
- usr_var.usr_ota_data_id = in_ota_data2->id; // int
- usr_var.usr_ota_data_size = in_ota_data2->size;
- encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), &encode_desc);
- if (encode_len > 0)
- {
- printf("encode_len = %d\n", encode_len);
- usr_ble_send_data(txbuf, encode_len);
- }
- else
- {
- printf("2encode_len = %d\n", encode_len);
- }
-
- usr_var.usr_allow_to_flash = 0;
- usr_var.usr_data_index = 0;
- start_data[2] = usr_var.usr_ota_data_size & 0x000000ff;
- start_data[3] = (usr_var.usr_ota_data_size >> 8) & 0x000000ff;
- start_data[4] = (usr_var.usr_ota_data_size >> 16) & 0x000000ff;
- start_data[5] = (usr_var.usr_ota_data_size >> 24) & 0x000000ff;
- dual_ota_app_data_deal(0, start_data, 10);
- printf("#### buf total size = %d\n", usr_var.usr_ota_data_size);
- printf_buf(start_data, 10);
-
- encode_desc.header.version = 0;
- encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
- encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_REQ;
- encode_desc.header.msgid = 0; // desc->header.msgid;
- encode_desc.header.encrypt = 0;
- encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_OTADATA;
- encode_desc.datast.doaction_rsp.errcode = 0;
-
- encode_desc.datast.otadata_req.id = usr_var.usr_ota_data_id;
- encode_desc.datast.otadata_req.offset = usr_var.usr_data_index;
- encode_desc.datast.otadata_req.maxsize = FIRM_PACK_LEN;
- encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), &encode_desc);
- if (encode_len > 0)
- {
- usr_ble_send_data(txbuf, encode_len);
- }
- else
- {
- printf("2encode_len err = %d\n", encode_len);
- }
-
- if (usr_var.usr_double_ota_timer_id == 0)
- {
- clk_set("sys", 48 * 1000000L);
- usr_var.usr_double_ota_timer_id = 1;
- // clk_set("sys", 120 * 1000000L);
- os_task_create(usr_ota_deal_task, NULL, 31, FIRM_PACK_LEN, 0, "usr_ota");
- }
-
- break;
case E_BLEPROTO_SERVICE_ID_OTADATA:
- printf("E_BLEPROTO_SERVICE_ID_OTADATA\n");
- break;
case E_BLEPROTO_SERVICE_ID_OTADATA_V2:
- printf("E_BLEPROTO_SERVICE_ID_OTADATA\n");
+ /* JSON OTA 已废弃,SOC 走 JB 0x30/0x32 */
+ printf("JSON OTA deprecated, use JB 0x30/0x32\n");
break;
-
default:
- printf("err !!! default event desc->header.serviceid =%d\n", desc->header.serviceid);
+ printf("err !!! default event desc->header.serviceid =%d\n",
+ desc->header.serviceid);
break;
}
+ return;
}
- else if (desc->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_RSP)
+
+ if (desc->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_RSP)
{
- printf("BLEPROTO_APPDATA_MSGTYPE_RSP\n");
switch (desc->header.serviceid)
{
case E_BLEPROTO_SERVICE_ID_REPORTCMD:
- // 主控回复的响应,设备处理
- printf("E_BLEPROTO_SERVICE_ID_REPORTCMD\n");
- printf("cmd id = %d", desc->datast.reportcmd_rsp.errcode);
+ printf("E_BLEPROTO_SERVICE_ID_REPORTCMD errcode=%d\n",
+ desc->datast.reportcmd_rsp.errcode);
break;
- case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2:
- {
- /* 网关对主动上报 / OTA 的应答(非 55AA):
- * cmd==0 && gateway_int_cnt==1 && gateway_int[0]==0 → 应答成功 */
+ case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2: {
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",
+
+ printf("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));
@@ -318,120 +252,23 @@ void usr_data_ana(bleproto_appdata_desc_t *desc)
break;
}
case E_BLEPROTO_SERVICE_ID_OTADATA:
- bleproto_otadata_rsp_t *ota_data_rsp = &desc->datast.otadata_rsp;
- // printf("errcode = %d offset = %d len = %d\n",ota_data_rsp->errcode,ota_data_rsp->offset,ota_data_rsp->len);
- uart_tr_send_data(ota_data_rsp->data, ota_data_rsp->len);
- memcpy(&ota_source_data[usr_var.usr_allow_to_flash], ota_data_rsp->data, ota_data_rsp->len);
- usr_var.usr_allow_to_flash += ota_data_rsp->len;
- usr_var.usr_start_write_flash = 0;
- if (usr_var.usr_allow_to_flash >= (FIRM_PACK_LEN * 2)) // 0 - 1024
- // 1024 - 2048
- // 2048 - 3072
- // 3072 - 4096
- {
- usr_var.usr_start_write_flash = 1;
- }
- else
- {
- usr_var.usr_data_index += FIRM_PACK_LEN;
- if (usr_var.usr_data_index >= usr_var.usr_ota_data_size)
- {
- usr_var.usr_start_write_flash = 2;
- break;
- }
- // bleproto_appdata_desc_t encode_desc = { 0 };
- encode_desc.header.version = 0;
- encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
- encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_REQ;
- encode_desc.header.msgid = 0; // desc->header.msgid;
- encode_desc.header.encrypt = 0;
- encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_OTADATA;
- encode_desc.datast.doaction_rsp.errcode = 0;
-
- encode_desc.datast.otadata_req.id = usr_var.usr_ota_data_id;
- encode_desc.datast.otadata_req.offset = usr_var.usr_data_index;
- encode_desc.datast.otadata_req.maxsize = FIRM_PACK_LEN;
- encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), &encode_desc);
- if (encode_len > 0)
- {
- usr_ble_send_data(txbuf, encode_len);
- }
- else
- {
- printf("2encode_len err = %d\n", encode_len);
- }
- }
+ printf("JSON OTA deprecated, use JB 0x32\n");
break;
default:
- printf("E_BLEPROTO_SERVICE_ID_REPORTCMD\n");
+ printf("unhandled RSP serviceid=%d\n", desc->header.serviceid);
break;
}
}
}
-void usr_ota_deal_task()
+/**
+ * @brief APP RUNCMD_V2:55AA 字节流转交 JB 协议层
+ * @param runcmd_par 内层包
+ * @param usr_msg_id bleproto msgid
+ */
+static void usr_run_cmd_code_v2(ble_proto_packet_t *runcmd_par, u8 usr_msg_id)
{
- os_time_dly(5);
- bleproto_appdata_desc_t encode_desc = {0};
- while (1)
- {
- if (usr_var.usr_ota_succ_flag == 0)
- {
- if (usr_var.usr_start_write_flash == 1)
- {
- // OS_ENTER_CRITICAL();
- usr_var.usr_data_index += FIRM_PACK_LEN;
- usr_var.usr_start_write_flash = 0;
- dual_ota_app_data_deal(0, ota_source_data, usr_var.usr_allow_to_flash);
- os_time_dly(1);
- // OS_EXIT_CRITICAL();
- // printf("usr_var.usr_allow_to_flash = %d\n",usr_var.usr_allow_to_flash);
- usr_var.usr_allow_to_flash = 0;
-
- encode_desc.header.version = 0;
- encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
- encode_desc.header.msgtype = BLEPROTO_APPDATA_MSGTYPE_REQ;
- encode_desc.header.msgid = 0; // desc->header.msgid;
- encode_desc.header.encrypt = 0;
- encode_desc.header.serviceid = E_BLEPROTO_SERVICE_ID_OTADATA;
- encode_desc.datast.doaction_rsp.errcode = 0;
-
- encode_desc.datast.otadata_req.id = usr_var.usr_ota_data_id;
- encode_desc.datast.otadata_req.offset = usr_var.usr_data_index;
- encode_desc.datast.otadata_req.maxsize = FIRM_PACK_LEN;
- encode_len = bleproto_appdata_encode(txbuf, sizeof(txbuf), sizeof(txbuf), &encode_desc);
- if (encode_len > 0)
- {
- usr_ble_send_data(txbuf, encode_len);
- }
- else
- {
- printf("2encode_len err = %d\n", encode_len);
- }
- }
- else if (usr_var.usr_start_write_flash == 2)
- {
- printf("usr_start_write_flash = %d\n", usr_var.usr_start_write_flash);
- usr_var.usr_start_write_flash = 0;
- // OS_ENTER_CRITICAL();
- dual_ota_app_data_deal(0, ota_source_data, usr_var.usr_allow_to_flash);
- // OS_EXIT_CRITICAL();
- printf("usr_var.usr_allow_to_flash = %d\n", usr_var.usr_allow_to_flash);
- usr_var.usr_allow_to_flash = 0;
- os_time_dly(30);
- dual_ota_app_data_deal(0, end_data, 2);
- }
- }
- os_time_dly(10);
- // putchar('6');
- }
-}
-
-/* 最近一次收到 RUNCMD_V2 请求的 msgid,应答时回填 */
-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 jb_frame[MAX_PACKAGE_LEN];
u16 copy_len;
if (!runcmd_par || !runcmd_par->bytes_data || runcmd_par->device_bytes_len == 0)
@@ -444,7 +281,6 @@ 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))
{
@@ -461,16 +297,17 @@ void usr_run_cmd_code_v2(ble_proto_packet_t *runcmd_par, u8 usr_msg_id)
* @brief 将 JB 协议帧封装为 bleproto V2 后通过 BLE 发送
* @param data JB 协议原始帧(55 AA | LEN | CMD | ...)
* @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 应答
+ * 对外符号名保持 ble_send_data,供 jb_protocol 调用
*/
void ble_send_data(u8 *data, u16 len)
{
- bleproto_appdata_desc_t encode_desc = {0};
- ble_proto_packet_t *pkt = NULL;
+ ble_proto_packet_t pkt;
+ bleproto_appdata_header_t hdr;
+ u8 v2_buf[MAX_PACKAGE_LEN + USR_LE_V2_WRAP_OVERHEAD];
u8 jb_cmd;
u8 is_active_send;
+ int plen;
int elen;
if (!data || len < 5)
@@ -478,54 +315,62 @@ void ble_send_data(u8 *data, u16 len)
printf("ble_send_data invalid param, len=%d\n", len);
return;
}
+ if (len > MAX_PACKAGE_LEN)
+ {
+ printf("ble_send_data frame too long %u\n", len);
+ return;
+ }
+ if (!usr_ble_is_notify_ready())
+ {
+ printf("ble_send_data wait CCC cmd=0x%02X\n", data[USR_LE_JB_CMD_OFF]);
+ 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);
+ jb_cmd = data[USR_LE_JB_CMD_OFF];
+ is_active_send = usr_le_is_gateway_report_cmd(jb_cmd);
- encode_desc.header.version = 0;
- encode_desc.header.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
- encode_desc.header.encrypt = 0;
+ memset(&pkt, 0, sizeof(pkt));
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.version = 0;
+ hdr.datafmt = BLEPROTO_APPDATA_DATAFMT_JSON;
+ hdr.encrypt = 0;
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;
-
- pkt = &encode_desc.datast.reportcmd_v2_req;
- pkt->cmd = 100;
- pkt->reserved = 0;
- pkt->gateway_int_cnt = 0;
+ hdr.msgtype = BLEPROTO_APPDATA_MSGTYPE_REQ;
+ hdr.msgid = 0;
+ hdr.serviceid = E_BLEPROTO_SERVICE_ID_REPORTCMD_V2;
+ pkt.cmd = USR_LE_V2_CMD_REPORT;
+ pkt.gateway_int_cnt = 0;
}
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;
-
- pkt = &encode_desc.datast.runcmd_v2_rsp;
- pkt->cmd = 110;
- pkt->reserved = 0;
- pkt->gateway_int_cnt = 2;
- pkt->gateway_int[0] = 0;
- pkt->gateway_int[1] = 0;
+ hdr.msgtype = BLEPROTO_APPDATA_MSGTYPE_RSP;
+ hdr.msgid = s_last_runcmd_msgid;
+ hdr.serviceid = E_BLEPROTO_SERVICE_ID_RUNCMD_V2;
+ pkt.cmd = USR_LE_V2_CMD_RUN;
+ pkt.gateway_int_cnt = 2;
+ pkt.gateway_int[0] = 0;
+ pkt.gateway_int[1] = 0;
}
- pkt->device_int_len = 0;
- pkt->device_str_len = 0;
- pkt->device_bytes_len = len;
- pkt->bytes_data = data;
+ pkt.device_bytes_len = 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);
- if (elen > 0)
+ plen = ble_proto_pack(&pkt, v2_buf, sizeof(v2_buf));
+ if (plen <= 0)
{
- usr_ble_send_data(txbuf, elen);
- printf_buf(txbuf, elen);
+ printf("ble_send_data pack fail %d\n", plen);
+ return;
}
+
+ elen = bleproto_appdata_wrap_raw(txbuf, sizeof(txbuf), &hdr, v2_buf, (uint16_t)plen);
+ printf("ble_send_data jb_cmd=0x%02X active=%d encode_len=%d msgid=%d\n",
+ jb_cmd, is_active_send, elen, hdr.msgid);
+ if (elen <= 0)
+ {
+ return;
+ }
+ usr_ble_send_data(txbuf, elen);
+ printf_buf(txbuf, elen);
}
diff --git a/apps/usr_periph/usr_rtc.c b/apps/usr_periph/usr_rtc.c
new file mode 100644
index 0000000..d44dbe4
--- /dev/null
+++ b/apps/usr_periph/usr_rtc.c
@@ -0,0 +1,363 @@
+/******************************************************************************
+ * @file usr_rtc.c
+ * @brief 板级 RTC 外设实现(BR28 硬件 rtc_dev_ops)
+ * @author cyWu <1917507415@qq.com>
+ * @date 2026.08.19
+ * @version V1.1.0
+ * @history
+ * - V1.0.0, 2026.08.19, cyWu, 从模组固件移植至 SOC SDK
+ * - V1.1.0, 2026.08.19, cyWu, 精简公共接口与缓存逻辑
+ ******************************************************************************/
+
+#include "system/includes.h"
+#include "app_config.h"
+#include "usr_rtc.h"
+#include "asm/rtc.h"
+
+#define LOG_TAG_CONST APP
+#define LOG_TAG "[USR_RTC]"
+#define LOG_ERROR_ENABLE
+#define LOG_DEBUG_ENABLE
+#define LOG_INFO_ENABLE
+#include "debug.h"
+
+/*============================================================================*/
+/* 私有宏 / 类型 */
+/*============================================================================*/
+
+#define USR_RTC_TZ_MAGIC (0x52544331u) /**< 'RTC1',校验 VM 时区 */
+
+typedef struct {
+ uint32_t magic;
+ int32_t tz_s;
+} UsrRtcTzVm_t;
+
+typedef struct {
+ uint8_t inited;
+ uint8_t tz_valid;
+ int32_t tz_s;
+ void *dev;
+} UsrRtc_t;
+
+/*============================================================================*/
+/* 私有变量 */
+/*============================================================================*/
+
+static UsrRtc_t s_rtc;
+
+/*============================================================================*/
+/* 私有函数声明 */
+/*============================================================================*/
+
+static uint8_t usr_rtc_is_leap(uint16_t year);
+static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month);
+static uint8_t usr_rtc_year_ok(uint16_t year);
+static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
+ struct sys_time *t);
+static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t);
+static void usr_rtc_load_tz(void);
+static void usr_rtc_save_tz(int32_t tz_s);
+
+/*============================================================================*/
+/* 公有函数 */
+/*============================================================================*/
+
+/**
+ * @brief 打开 rtc 设备并加载时区
+ * @return UsrRtc_Ret_t
+ */
+UsrRtc_Ret_t usr_rtc_init(void)
+{
+ struct sys_time t;
+
+ if (s_rtc.inited)
+ {
+ return USR_RTC_OK;
+ }
+
+#if TCFG_APP_RTC_EN
+ s_rtc.dev = dev_open("rtc", NULL);
+ if (!s_rtc.dev)
+ {
+ log_error("open rtc fail");
+ return USR_RTC_ERR_NOT_INIT;
+ }
+#else
+ log_error("TCFG_APP_RTC_EN=0");
+ return USR_RTC_ERR_NOT_INIT;
+#endif
+
+ usr_rtc_load_tz();
+ s_rtc.inited = 1;
+
+ memset(&t, 0, sizeof(t));
+ read_sys_time(&t);
+ log_info("rtc open %u-%02u-%02u %02u:%02u:%02u tz=%ld tz_ok=%u",
+ t.year, t.month, t.day, t.hour, t.min, t.sec,
+ (long)s_rtc.tz_s, s_rtc.tz_valid);
+ return USR_RTC_OK;
+}
+
+/**
+ * @brief 获取当前本地时间
+ * @param t 成功时赋值;失败不改动
+ * @return 1/0
+ */
+uint8_t usr_rtc_get_time(struct sys_time *t)
+{
+ struct sys_time tmp;
+
+ if (!t || !s_rtc.inited || !s_rtc.tz_valid)
+ {
+ return 0;
+ }
+
+ memset(&tmp, 0, sizeof(tmp));
+ read_sys_time(&tmp);
+ if (!usr_rtc_year_ok(tmp.year))
+ {
+ return 0;
+ }
+
+ *t = tmp;
+ return 1;
+}
+
+/**
+ * @brief UTC 秒 + 时区 → 本地日历写入 RTC
+ * @param unix_utc UTC 秒
+ * @param tz_s 时区偏移秒
+ * @return UsrRtc_Ret_t
+ */
+UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s)
+{
+ struct sys_time t;
+ UsrRtc_Ret_t ret;
+
+ if (!s_rtc.inited)
+ {
+ return USR_RTC_ERR_NOT_INIT;
+ }
+ if (unix_utc == 0)
+ {
+ log_debug("unix=0, ignore");
+ return USR_RTC_ERR_PARAM;
+ }
+
+ /* 网关采样到写入大约慢 1s,在 UTC 上补偿 */
+ unix_utc += USR_RTC_SYNC_COMPENSATE_S;
+ if ((tz_s > USR_RTC_TZ_ABS_MAX_S) || (tz_s < -USR_RTC_TZ_ABS_MAX_S))
+ {
+ log_error("tz out of range %ld", (long)tz_s);
+ return USR_RTC_ERR_PARAM;
+ }
+ if (unix_utc > 0xFFFFFFFFull)
+ {
+ log_error("unix too large");
+ return USR_RTC_ERR_PARAM;
+ }
+
+ usr_rtc_unix_to_calendar((uint32_t)unix_utc, tz_s, &t);
+ if (!usr_rtc_year_ok(t.year))
+ {
+ log_error("year %u not in %u~%u, wait sync",
+ t.year, USR_RTC_YEAR_MIN, USR_RTC_YEAR_MAX);
+ return USR_RTC_ERR_INVALID;
+ }
+
+ ret = usr_rtc_write(&t);
+ if (ret != USR_RTC_OK)
+ {
+ return ret;
+ }
+
+ usr_rtc_save_tz(tz_s);
+ log_info("set rtc %u-%02u-%02u %02u:%02u:%02u tz=%ld",
+ t.year, t.month, t.day, t.hour, t.min, t.sec, (long)tz_s);
+ return USR_RTC_OK;
+}
+
+/*============================================================================*/
+/* 私有函数 */
+/*============================================================================*/
+
+/**
+ * @brief 写硬件日历
+ * @param t 本地日历
+ * @return UsrRtc_Ret_t
+ */
+static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t)
+{
+ struct sys_time tmp;
+
+ if (!t)
+ {
+ return USR_RTC_ERR_PARAM;
+ }
+ if (!s_rtc.inited)
+ {
+ return USR_RTC_ERR_NOT_INIT;
+ }
+ if (!usr_rtc_year_ok(t->year) || (t->month < 1) || (t->month > 12) ||
+ (t->day < 1) || (t->hour > 23) || (t->min > 59) || (t->sec > 59))
+ {
+ return USR_RTC_ERR_PARAM;
+ }
+ if (t->day > usr_rtc_days_in_month(t->year, t->month))
+ {
+ return USR_RTC_ERR_PARAM;
+ }
+
+ tmp = *t;
+ write_sys_time(&tmp);
+ return USR_RTC_OK;
+}
+
+/**
+ * @brief 是否闰年
+ * @param year 公历年
+ * @return 1/0
+ */
+static uint8_t usr_rtc_is_leap(uint16_t year)
+{
+ if ((year % 400u) == 0)
+ {
+ return 1;
+ }
+ if ((year % 100u) == 0)
+ {
+ return 0;
+ }
+ return ((year % 4u) == 0) ? 1 : 0;
+}
+
+/**
+ * @brief 某月天数
+ * @param year 年
+ * @param month 月 1~12
+ * @return 天数,非法月返回 0
+ */
+static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month)
+{
+ static const uint8_t days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ if ((month < 1) || (month > 12))
+ {
+ return 0;
+ }
+ if ((month == 2) && usr_rtc_is_leap(year))
+ {
+ return 29;
+ }
+ return days[month - 1];
+}
+
+/**
+ * @brief 年份是否在合法窗口
+ * @param year 年
+ * @return 1/0
+ */
+static uint8_t usr_rtc_year_ok(uint16_t year)
+{
+ return ((year >= USR_RTC_YEAR_MIN) && (year <= USR_RTC_YEAR_MAX)) ? 1 : 0;
+}
+
+/**
+ * @brief UTC 秒 + 时区 → 本地日历
+ * @param unix_utc UTC 秒
+ * @param tz_s 时区偏移
+ * @param t 输出
+ */
+static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
+ struct sys_time *t)
+{
+ int64_t local;
+ uint32_t days;
+ uint32_t tod;
+ uint16_t y;
+ uint8_t m;
+ uint8_t dim;
+
+ memset(t, 0, sizeof(*t));
+ local = (int64_t)unix_utc + (int64_t)tz_s;
+ if (local < 0)
+ {
+ local = 0;
+ }
+
+ tod = (uint32_t)(local % 86400);
+ days = (uint32_t)(local / 86400);
+ t->sec = (uint8_t)(tod % 60u);
+ t->min = (uint8_t)((tod / 60u) % 60u);
+ t->hour = (uint8_t)(tod / 3600u);
+
+ y = 1970;
+ while (1)
+ {
+ uint32_t diy = usr_rtc_is_leap(y) ? 366u : 365u;
+ if (days < diy)
+ {
+ break;
+ }
+ days -= diy;
+ y++;
+ if (y > 4095u)
+ {
+ break;
+ }
+ }
+ t->year = y;
+
+ for (m = 1; m <= 12u; m++)
+ {
+ dim = usr_rtc_days_in_month(y, m);
+ if (days < dim)
+ {
+ break;
+ }
+ days -= dim;
+ }
+ t->month = m;
+ t->day = (uint8_t)(days + 1u);
+}
+
+/**
+ * @brief 从 VM 加载时区
+ */
+static void usr_rtc_load_tz(void)
+{
+ UsrRtcTzVm_t vm;
+ int ret;
+
+ s_rtc.tz_valid = 0;
+ s_rtc.tz_s = 0;
+ memset(&vm, 0, sizeof(vm));
+ ret = syscfg_read(CFG_USER_TIM_FLAG, (u8 *)&vm, sizeof(vm));
+ if ((ret == (int)sizeof(vm)) && (vm.magic == USR_RTC_TZ_MAGIC))
+ {
+ if ((vm.tz_s <= USR_RTC_TZ_ABS_MAX_S) && (vm.tz_s >= -USR_RTC_TZ_ABS_MAX_S))
+ {
+ s_rtc.tz_s = vm.tz_s;
+ s_rtc.tz_valid = 1;
+ log_info("tz from vm %ld", (long)s_rtc.tz_s);
+ return;
+ }
+ }
+ log_debug("tz vm empty");
+}
+
+/**
+ * @brief 时区写入 VM
+ * @param tz_s 时区偏移秒
+ */
+static void usr_rtc_save_tz(int32_t tz_s)
+{
+ UsrRtcTzVm_t vm;
+
+ s_rtc.tz_s = tz_s;
+ s_rtc.tz_valid = 1;
+ vm.magic = USR_RTC_TZ_MAGIC;
+ vm.tz_s = tz_s;
+ syscfg_write(CFG_USER_TIM_FLAG, (u8 *)&vm, sizeof(vm));
+}
diff --git a/apps/usr_periph/usr_rtc.h b/apps/usr_periph/usr_rtc.h
new file mode 100644
index 0000000..9c5de7e
--- /dev/null
+++ b/apps/usr_periph/usr_rtc.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ * @file usr_rtc.h
+ * @brief 板级 RTC:硬件对时 + 客户读本地日历
+ * @author cyWu <1917507415@qq.com>
+ * @date 2026.08.19
+ * @version V1.1.0
+ * @history
+ * - V1.0.0, 2026.08.19, cyWu, 从模组固件移植至 SOC SDK
+ * - V1.1.0, 2026.08.19, cyWu, 精简接口;usr_rtc_get_time 返回本地日历
+ ******************************************************************************/
+
+#ifndef __USR_RTC_H__
+#define __USR_RTC_H__
+
+#include
+#include "system/sys_time.h"
+
+/*============================================================================*/
+/* 宏定义 */
+/*============================================================================*/
+
+#define USR_RTC_YEAR_MIN (2026u) /**< 合法年份下限 */
+#define USR_RTC_YEAR_MAX (2098u) /**< 合法年份上限 */
+#define USR_RTC_TZ_ABS_MAX_S (57600) /**< 时区偏移绝对值上限(±16h) */
+#define USR_RTC_SYNC_COMPENSATE_S (1u) /**< 网关对时延迟补偿(秒) */
+
+/*============================================================================*/
+/* 错误码(init / set_from_unix) */
+/*============================================================================*/
+
+typedef enum {
+ USR_RTC_OK = 0,
+ USR_RTC_ERR_PARAM,
+ USR_RTC_ERR_NOT_INIT,
+ USR_RTC_ERR_INVALID, /**< 年份非法,等待 App 对时 */
+} UsrRtc_Ret_t;
+
+/*============================================================================*/
+/* 外部接口 */
+/*============================================================================*/
+
+/**
+ * @brief 打开 "rtc" 设备并加载时区
+ * @return UsrRtc_Ret_t
+ * @note app_main 启动时调用一次即可
+ */
+UsrRtc_Ret_t usr_rtc_init(void);
+
+/**
+ * @brief 获取当前本地时间(客户常用)
+ * @param t 成功时写入年月日时分秒;失败时不改动
+ * @return 1=已对时且读成功,0=未初始化/未对时/参数非法
+ */
+uint8_t usr_rtc_get_time(struct sys_time *t);
+
+/**
+ * @brief App/网关 DEVICEINFO:UTC 秒 + 时区写入 RTC
+ * @param unix_utc UTC Unix 秒;0 无效
+ * @param tz_s 时区偏移秒(东八区 28800)
+ * @return UsrRtc_Ret_t
+ */
+UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s);
+
+#endif /* __USR_RTC_H__ */
diff --git a/cpu/br28/tools/download/earphone/download_app_ota.bat b/cpu/br28/tools/download/earphone/download_app_ota.bat
index 1e15e05..bb583c5 100644
--- a/cpu/br28/tools/download/earphone/download_app_ota.bat
+++ b/cpu/br28/tools/download/earphone/download_app_ota.bat
@@ -10,10 +10,9 @@ 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
diff --git a/include_lib/system/device/iokey.h b/include_lib/system/device/iokey.h
index c9f0082..e9c7374 100644
--- a/include_lib/system/device/iokey.h
+++ b/include_lib/system/device/iokey.h
@@ -48,6 +48,23 @@ struct iokey_platform_data {
extern int iokey_init(const struct iokey_platform_data *iokey_data);
extern u8 io_get_key_value(void);
+/* 开机锁键:长按开机不松手时屏蔽全部按键,避免误触长按关机。
+ * 默认监视 port[0](请把电源键配成第 0 个)。
+ * 松开并连续确认 release_cnt 次扫描后解锁(扫描约 10ms 一次,默认 10 ≈ 100ms)。
+ *
+ * 关闭方式:
+ * 1) 编译关闭:在 board/app_config 里 #define TCFG_IOKEY_BOOT_LOCK_ENABLE 0
+ * 2) 运行关闭:iokey_boot_lock_stop() 或 iokey_boot_lock_start(0)
+ */
+#ifndef TCFG_IOKEY_BOOT_LOCK_ENABLE
+#define TCFG_IOKEY_BOOT_LOCK_ENABLE 1
+#endif
+#ifndef IOKEY_BOOT_LOCK_DEFAULT_CNT
+#define IOKEY_BOOT_LOCK_DEFAULT_CNT 10
+#endif
+void iokey_boot_lock_start(u8 release_cnt); /* >0 启动;0=关闭 */
+void iokey_boot_lock_stop(void); /* 立即关闭锁键 */
+
#endif
diff --git a/tools/package_release.py b/tools/package_release.py
index 18ec760..b586101 100644
--- a/tools/package_release.py
+++ b/tools/package_release.py
@@ -492,6 +492,7 @@ def write_readme(readme_path: Path, version: str, module_stats: List[dict]) -> N
"│ ├── common/ # SDK 公共模块",
"│ ├── earphone/ # 耳机应用",
"│ ├── usr_jb_proto/ # 应用协议层",
+ "│ ├── usr_periph/ # 板级外设(RTC 等,源码开放)",
"│ └── usr_le_code/ # BLE 协议库(库文件 + 公开头文件)",
"├── cpu/ # 芯片相关代码与工具",
"├── include_lib/ # SDK 头文件",
diff --git a/version.txt b/version.txt
index 3eefcb9..7dea76e 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.0.0
+1.0.1