1 Commits
Author SHA1 Message Date
wuchuyuan aa724c6758 客户侧能力:RTC、开机锁键与 BLE 协议收敛
1、新增 usr_periph RTC,DEVICEINFO 自动对时;对外精简为 get_time(sys_time*),开发板 RTC 时钟改用 LRC
2、iokey 开机锁键改为公开 start/stop 接口,板级宏 TCFG_IOKEY_BOOT_LOCK_ENABLE 可关闭
3、对齐模组 BLE 收发/组包与公开 API,更新 libusr_le_code.a;Release 包命名调整为 JBao_JL7016_SOC_SDK_Vx.x.x
2026-08-19 15:26:35 +08:00
21 changed files with 1118 additions and 600 deletions
+5
View File
@@ -176,6 +176,7 @@
<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_periph" />
</Compiler>
<Linker>
<Add option="-flto" />
@@ -778,6 +779,10 @@
<Unit filename="apps/usr_jb_proto/usr_jb_main.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="apps/usr_periph/usr_rtc.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="apps/usr_periph/usr_rtc.h" />
<Unit filename="apps/usr_le_code/ble_proto.h" />
<Unit filename="apps/usr_le_code/bleproto.h" />
<Unit filename="apps/usr_le_code/bleproto_api.h" />
+2
View File
@@ -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 静态库(协议编解码 + 广播/收发)
+79 -8
View File
@@ -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;
@@ -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;i<len;i++)
{
printf("%c",data[i]);
}
printf("\n");
}
static int app_send_user_data(u16 handle, u8 *data, u16 len, u8 handle_type)
{
@@ -961,6 +958,16 @@ u16 usr_get_conn_service()
{
return con_handle;
}
/**
* @brief 主机是否已写 CCC,允许 GATT notify/indicate
* @return 1=可发数(BLE_ST_NOTIFY_IDICATE),0=还不行
*/
u8 usr_ble_is_notify_ready(void)
{
return (get_ble_work_state() == BLE_ST_NOTIFY_IDICATE) ? 1 : 0;
}
void ble_app_disconnect(void)
{
ble_disconnect(NULL);
+2
View File
@@ -16,6 +16,7 @@
#include "bt_profile_cfg.h"
#include "dev_manager/dev_manager.h"
#include "update_loader_download.h"
#include "usr_rtc.h"
#ifndef CONFIG_MEDIA_NEW_ENABLE
#ifndef CONFIG_MEDIA_DEVELOP_ENABLE
@@ -292,6 +293,7 @@ void app_main()
}
app_var_init();
usr_rtc_init(); /* 打开硬件 RTC,网关 DEVICEINFO 对时走 usr_rtc_set_from_unix */
usr_jb_init();
#if TCFG_MC_BIAS_AUTO_ADJUST
+1 -1
View File
@@ -730,7 +730,7 @@ struct port_wakeup port0 = {
.pullup_down_enable = ENABLE, //配置I/O 内部上下拉是否使能
.edge = FALLING_EDGE, //唤醒方式选择,可选:上升沿\下降沿
.filter = PORT_FLT_8ms,
.iomap = IO_PORTB_01, //唤醒口选择
.iomap = TCFG_IOKEY_POWER_ONE_PORT, //唤醒口选择
};
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
@@ -107,6 +107,7 @@
// iokey 配置 //
//*********************************************************************************//
#define TCFG_IOKEY_ENABLE 1 //是否使能IO按键
#define TCFG_IOKEY_BOOT_LOCK_ENABLE 1 //开机锁键:长按开机不松手时屏蔽按键,避免误触关机;不需要则改 0,默认第 0 个端口
#define TCFG_IOKEY_POWER_CONNECT_WAY ONE_PORT_TO_LOW //按键一端接低电平一端接IO
+34 -35
View File
@@ -205,42 +205,41 @@ int ble_proto_unpack(const uint8_t *buf, size_t len, ble_proto_packet_t *pkt)
pkt->bytes_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;
}
+37 -30
View File
@@ -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,
+58 -3
View File
@@ -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 datadata 为外部指针,不再内嵌数组) */
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;
+22 -1
View File
@@ -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 数据;可为 NULLpayload_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 反序列化应用数据
*
Binary file not shown.
+186 -117
View File
@@ -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:非配网流程
* - 1app_main 上电 / usr_goto_pair_mode() 触发,发【绑定广播】
*
* 3) usr_var.usr_adv_flag —— 广播内容是否需要刷新到协议栈(一次性)
* - 1usr_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)
+6 -16
View File
@@ -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 断开当前连接、清除配对信息(不复位),重新发绑定广播
+221 -376
View File
@@ -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_V255AA 字节流转交 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];
/* 主动上报 0x07MCU 主动 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);
}
+363
View File
@@ -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));
}
+64
View File
@@ -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 <stdint.h>
#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/网关 DEVICEINFOUTC 秒 + 时区写入 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__ */
@@ -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
+17
View File
@@ -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
+1
View File
@@ -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 头文件",
+1 -1
View File
@@ -1 +1 @@
1.0.0
1.0.1