/****************************************************************************** * @file usr_le_recieve.c * @brief BLE 收包入口:bleproto 解析后分发配网 / 对时 / JB 协议 / 组应答 * @author cyWu <1917507415@qq.com> * @date 2026.09.09 * @version V1.2.0 * @history * - V1.0.0, 2026.08.03, cyWu, 首次发布 * - V1.1.0, 2026.08.19, cyWu, 对齐模组结构;废弃 JSON OTA;修 AUTHDELETE serviceid * - V1.2.0, 2026.09.09, cyWu, JB 上报超 255 走 wrap_raw 自动分包;加大 txbuf ******************************************************************************/ #include "system/includes.h" #include "app_config.h" #include "app_main.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 "[USR_LE]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE #define LOG_INFO_ENABLE #include "debug.h" /* 收:GATT 拼包缓冲。发:V2 + bleproto 多帧(单帧总长 247,与 ATT 对齐) */ #define USR_LE_RX_BUF_LEN 1024 #define USR_LE_V2_WRAP_OVERHEAD 32u /* V2 头开销 */ #define USR_LE_V2_MAX_LEN (512u + USR_LE_V2_WRAP_OVERHEAD) #define USR_LE_APPDATA_PACKETLEN 247u /* 对齐 ATT_LOCAL_PAYLOAD_SIZE:8B头+239B数据 */ #define USR_LE_APPDATA_FRAME_PAYLOAD (USR_LE_APPDATA_PACKETLEN - 8u) #define USR_LE_TX_BUF_LEN (USR_LE_V2_MAX_LEN + \ 8u * ((USR_LE_V2_MAX_LEN + USR_LE_APPDATA_FRAME_PAYLOAD - 1u) / \ USR_LE_APPDATA_FRAME_PAYLOAD)) #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 int encode_len = 0; static u8 txbuf[USR_LE_TX_BUF_LEN]; 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; 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), USR_LE_APPDATA_PACKETLEN, 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, &s_rx_desc); if (rc_result < 0) { printf("### invild pack\n"); usr_len = 0; } else if (rc_result == 0) { printf("### keep recieving\n"); } else { printf("### pack recieved ok\n"); usr_len = 0; usr_data_ana(&s_rx_desc); } } /** * @brief 解析 bleproto 服务并分发 * @param desc 已 decode 的包 */ static void usr_data_ana(bleproto_appdata_desc_t *desc) { 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; /* 网关从子设备连上开始计时,每 12 小时经 DEVICEINFO 同步一次 */ usr_rtc_set_from_unix(req->t, (int32_t)req->gmtoff); 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: { bleproto_authsetup_rsp_t *au_rsp = &s_encode_desc.datast.authsetup_rsp; printf("E_BLEPROTO_SERVICE_ID_AUTHSETUP\n"); 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) { usr_write_pair_info(); usr_var.usr_goto_pair = 0; // 新增:退出强制配网 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: { bleproto_authdelete_rsp_t *aude_rsp = &s_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)) { aude_rsp->errcode = 0; usr_clear_pair_info(); } else { aude_rsp->errcode = 501; } 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: printf("E_BLEPROTO_SERVICE_ID_RUNCMD_V2\n"); usr_run_cmd_code_v2(&desc->datast.runcmd_v2_req, desc->header.msgid); break; case E_BLEPROTO_SERVICE_ID_OTANOTIFY: case E_BLEPROTO_SERVICE_ID_OTADATA: case E_BLEPROTO_SERVICE_ID_OTADATA_V2: /* 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); break; } return; } if (desc->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_RSP) { switch (desc->header.serviceid) { case E_BLEPROTO_SERVICE_ID_REPORTCMD: printf("E_BLEPROTO_SERVICE_ID_REPORTCMD errcode=%d\n", desc->datast.reportcmd_rsp.errcode); break; case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2: { ble_proto_packet_t *rpt_ack = &desc->datast.reportcmd_v2_rsp; 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)); jbReportAckCheck(rpt_ack->cmd, rpt_ack->gateway_int_cnt, (rpt_ack->gateway_int_cnt > 0) ? rpt_ack->gateway_int[0] : -1); break; } case E_BLEPROTO_SERVICE_ID_OTADATA: printf("JSON OTA deprecated, use JB 0x32\n"); break; default: printf("unhandled RSP serviceid=%d\n", desc->header.serviceid); break; } } } /** * @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) { u8 jb_frame[MAX_PACKAGE_LEN]; u16 copy_len; if (!runcmd_par || !runcmd_par->bytes_data || runcmd_par->device_bytes_len == 0) { printf("usr_run_cmd_code_v2 invalid bytes, len=%u\n", runcmd_par ? runcmd_par->device_bytes_len : 0); return; } printf("runcmd_par id = %d, bytes_len = %u\n", runcmd_par->cmd, runcmd_par->device_bytes_len); copy_len = runcmd_par->device_bytes_len; if (copy_len > sizeof(jb_frame)) { printf("usr_run_cmd_code_v2 bytes too long %u\n", copy_len); return; } memcpy(jb_frame, runcmd_par->bytes_data, copy_len); s_last_runcmd_msgid = usr_msg_id; usr_jb_le_recieve_data(jb_frame, copy_len); } /** * @brief 将 JB 协议帧封装为 bleproto V2 后通过 BLE 发送 * @param data JB 协议原始帧(55 AA | LEN | CMD | ...) * @param len 帧长度 * @note 主动上报(0x07/0x34/0x38) → REPORTCMD_V2;其余 → RUNCMD_V2 应答 * 对外符号名保持 ble_send_data,供 jb_protocol 调用 */ void ble_send_data(u8 *data, u16 len) { 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) { 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_cmd = data[USR_LE_JB_CMD_OFF]; is_active_send = usr_le_is_gateway_report_cmd(jb_cmd); 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) { 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 { 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_bytes_len = len; pkt.bytes_data = data; plen = ble_proto_pack(&pkt, v2_buf, sizeof(v2_buf)); if (plen <= 0) { printf("ble_send_data pack fail %d\n", plen); return; } elen = bleproto_appdata_wrap_raw(txbuf, sizeof(txbuf), USR_LE_APPDATA_PACKETLEN, &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); }