/****************************************************************************/ /* bleproto.c * * Copyright (C) 2024 四川迈科创智科技有限公司 * ****************************************************************************/ /****************************************************************************/ /* Included Files */ /****************************************************************************/ #include "bleproto.h" /****************************************************************************/ /* Trace Definitions */ /****************************************************************************/ /****************************************************************************/ /* Pre-processor Definitions */ /****************************************************************************/ /****************************************************************************/ /* Private Types */ /****************************************************************************/ /****************************************************************************/ /* Private Function Prototypes */ /****************************************************************************/ /****************************************************************************/ /* Private Data */ /****************************************************************************/ /****************************************************************************/ /* Public Data */ /****************************************************************************/ /****************************************************************************/ /* Private Functions */ /****************************************************************************/ /****************************************************************************/ /* Public Functions */ /****************************************************************************/ const char *libbleproto_version(void) { return BLEPROTO_API_VERSION; } uint8_t bleproto_advdata_encode4bind( uint8_t data[31], int8_t txpower, uint8_t manucode[BLEPROTO_ADV_TLV_LENGTH_MANUCODE], uint8_t pcode[BLE_PROTO_ADV_LENGTH_PCODE], uint8_t prodcode[BLEPROTO_ADV_TLV_LENGTH_PRODCODE]) { bleproto_adv_t adv = {0}; /* adv1 */ { adv.adv1.length = 0x02; adv.adv1.ad_type = BLEPROTO_ADV_TYPE_FLAGS; adv.adv1.ad_data = 0x06; } /* adv2 */ // clang-format off { adv.adv2.length = 0x1B; adv.adv2.ad_type = BLEPROTO_ADV_TYPE_SVC_DATA_UUID16; adv.adv2.ad_data.service_data.uuid = BLEPROTO_ADV_SERVICE_UUID_TOBIND; /* spec_data */ bleproto_adv_specdata_t *spec_data = &adv.adv2.ad_data.service_data.spec_data; spec_data->version = BLEPORTO_ADV_SERVICE_SPEC_DATA_VER; spec_data->business = BELPROTO_ADV_SERVICE_SPEC_DATA_BUSINESS_NEARFIND; spec_data->rfu[0] = 0; spec_data->rfu[1] = 0; spec_data->txpower = txpower; spec_data->manucode.type = BLEPROTO_ADV_TLV_TYPE_MANUCODE; spec_data->manucode.length = BLEPROTO_ADV_TLV_LENGTH_MANUCODE; memcpy(spec_data->manucode.value, manucode, BLEPROTO_ADV_TLV_LENGTH_MANUCODE); spec_data->prodcode.type = BLEPROTO_ADV_TLV_TYPE_PRODCODE; spec_data->prodcode.length = BLEPROTO_ADV_TLV_LENGTH_PRODCODE; memcpy(spec_data->prodcode.value, prodcode, BLEPROTO_ADV_TLV_LENGTH_PRODCODE); spec_data->separator = 0xFF; memcpy(spec_data->selfdata, pcode, BLE_PROTO_ADV_LENGTH_PCODE); // spec_data->selfdata[0] = 0X30; // spec_data->selfdata[1] = 0X30; // spec_data->selfdata[2] = 0X30; // spec_data->selfdata[3] = 0X30; // spec_data->selfdata[4] = 0X30; // spec_data->selfdata[5] = 0X30; } // clang-format on return bleproto_advdata_serialize(&adv, data, 31); } void bleproto_advdata_encode4heartbeat( uint8_t data[31], int8_t txpower, uint8_t gwmac[6], uint8_t manucode[BLEPROTO_ADV_TLV_LENGTH_MANUCODE], uint8_t pcode[BLE_PROTO_ADV_LENGTH_PCODE], uint8_t prodcode[BLEPROTO_ADV_TLV_LENGTH_PRODCODE]) { bleproto_adv_t adv = {0}; /* adv1 */ { adv.adv1.length = 0x02; adv.adv1.ad_type = BLEPROTO_ADV_TYPE_FLAGS; adv.adv1.ad_data = 0x06; } /* adv2 */ // clang-format off { adv.adv2.length = 0x1B; adv.adv2.ad_type = BLEPROTO_ADV_TYPE_MFG_DATA; /* mfg_data */ bleproto_advdata_mfg_t *mfg_data = &adv.adv2.ad_data.mfg_data; memcpy(mfg_data->siot, pcode, BLE_PROTO_ADV_LENGTH_PCODE); #if 0 mfg_data->siot[0] = 'S'; mfg_data->siot[1] = 'I'; mfg_data->siot[2] = 'O'; mfg_data->siot[3] = 'T'; mfg_data->siot[4] = '-'; mfg_data->siot[5] = '1'; #endif /* HEARTBEAT */ mfg_data->flag = BLEPROTO_ADV_FLAG_HEARTBEAT; mfg_data->txpower = txpower; memcpy(mfg_data->gwmac, gwmac, 6); mfg_data->manucode.type = BLEPROTO_ADV_TLV_TYPE_MANUCODE; mfg_data->manucode.length = BLEPROTO_ADV_TLV_LENGTH_MANUCODE; memcpy(mfg_data->manucode.value, manucode, BLEPROTO_ADV_TLV_LENGTH_MANUCODE); mfg_data->prodcode.type = BLEPROTO_ADV_TLV_TYPE_PRODCODE; mfg_data->prodcode.length = BLEPROTO_ADV_TLV_LENGTH_PRODCODE; memcpy(mfg_data->prodcode.value, prodcode, BLEPROTO_ADV_TLV_LENGTH_PRODCODE); } // clang-format on (void)bleproto_advdata_serialize(&adv, data, 31); } uint8_t bleproto_advdata_encode4reconn( uint8_t data[31], int8_t txpower, uint8_t gwmac[6], uint8_t manucode[BLEPROTO_ADV_TLV_LENGTH_MANUCODE], uint8_t pcode[BLE_PROTO_ADV_LENGTH_PCODE], uint8_t prodcode[BLEPROTO_ADV_TLV_LENGTH_PRODCODE]) { bleproto_adv_t adv = {0}; /* adv1 */ { adv.adv1.length = 0x02; adv.adv1.ad_type = BLEPROTO_ADV_TYPE_FLAGS; adv.adv1.ad_data = 0x06; } /* adv2 */ // clang-format off { adv.adv2.length = 0x1B; adv.adv2.ad_type = BLEPROTO_ADV_TYPE_MFG_DATA; /* mfg_data */ bleproto_advdata_mfg_t *mfg_data = &adv.adv2.ad_data.mfg_data; memcpy(mfg_data->siot, pcode, BLE_PROTO_ADV_LENGTH_PCODE); #if 0 mfg_data->siot[0] = 'S'; mfg_data->siot[1] = 'I'; mfg_data->siot[2] = 'O'; mfg_data->siot[3] = 'T'; mfg_data->siot[4] = '-'; mfg_data->siot[5] = '1'; #endif /* RECONNECT */ mfg_data->flag = BLEPROTO_ADV_FLAG_RECONNECT; mfg_data->txpower = txpower; memcpy(mfg_data->gwmac, gwmac, 6); mfg_data->manucode.type = BLEPROTO_ADV_TLV_TYPE_MANUCODE; mfg_data->manucode.length = BLEPROTO_ADV_TLV_LENGTH_MANUCODE; memcpy(mfg_data->manucode.value, manucode, BLEPROTO_ADV_TLV_LENGTH_MANUCODE); mfg_data->prodcode.type = BLEPROTO_ADV_TLV_TYPE_PRODCODE; mfg_data->prodcode.length = BLEPROTO_ADV_TLV_LENGTH_PRODCODE; memcpy(mfg_data->prodcode.value, prodcode, BLEPROTO_ADV_TLV_LENGTH_PRODCODE); } // clang-format on return bleproto_advdata_serialize(&adv, data, 31); } int bleproto_advdata_decode(const uint8_t *data, uint8_t len, bleproto_adv_t *adv) { return bleproto_advdata_deserialize(data, len, adv); } int bleproto_appdata_encode(uint8_t *txbuf, uint16_t size, uint8_t packetlen, bleproto_appdata_desc_t *desc) { int rc; uint16_t txbuf_size = size; /* * 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; } /* data */ if (appdata->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_REQ) { switch (appdata->header.serviceid) { case E_BLEPROTO_SERVICE_ID_DEVICEINFO: rc = bleproto_encjson_deviceinfo_req(&desc->datast.deviceinfo_req, appdata->data); break; case E_BLEPROTO_SERVICE_ID_AUTHSETUP: rc = bleproto_encjson_authsetup_req(&desc->datast.authsetup_req, appdata->data); break; case E_BLEPROTO_SERVICE_ID_AUTHDELETE: rc = bleproto_encjson_authdelete_req(&desc->datast.authdelete_req, appdata->data); break; case E_BLEPROTO_SERVICE_ID_RUNCMD: rc = bleproto_encjson_runcmd_req(&desc->datast.runcmd_req, appdata->data); break; case E_BLEPROTO_SERVICE_ID_REPORTCMD: rc = bleproto_encjson_reportcmd_req(&desc->datast.reportcmd_req, appdata->data); break; case E_BLEPROTO_SERVICE_ID_DOACTION: rc = bleproto_encjson_doaction_req(&desc->datast.doaction_req, appdata->data); break; case E_BLEPROTO_SERVICE_ID_OTANOTIFY: rc = bleproto_encjson_otanotify_req(&desc->datast.otanotify_req, appdata->data); break; case E_BLEPROTO_SERVICE_ID_OTADATA: rc = bleproto_encjson_otadata_req(&desc->datast.otadata_req, appdata->data); break; case E_BLEPROTO_SERVICE_ID_RUNCMD_V2: 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)); break; case E_BLEPROTO_SERVICE_ID_OTADATA_V2: 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) { switch (appdata->header.serviceid) { case E_BLEPROTO_SERVICE_ID_DEVICEINFO: rc = bleproto_encjson_deviceinfo_rsp(&desc->datast.deviceinfo_rsp, appdata->data); break; case E_BLEPROTO_SERVICE_ID_AUTHSETUP: rc = bleproto_encjson_authsetup_rsp(&desc->datast.authsetup_rsp, appdata->data); break; case E_BLEPROTO_SERVICE_ID_AUTHDELETE: rc = bleproto_encjson_authdelete_rsp(&desc->datast.authdelete_rsp, appdata->data); break; case E_BLEPROTO_SERVICE_ID_RUNCMD: rc = bleproto_encjson_runcmd_rsp(&desc->datast.runcmd_rsp, appdata->data); break; case E_BLEPROTO_SERVICE_ID_REPORTCMD: rc = bleproto_encjson_reportcmd_rsp(&desc->datast.reportcmd_rsp, appdata->data); break; case E_BLEPROTO_SERVICE_ID_DOACTION: rc = bleproto_encjson_doaction_rsp(&desc->datast.doaction_rsp, appdata->data); break; case E_BLEPROTO_SERVICE_ID_OTANOTIFY: rc = bleproto_encjson_otanotify_rsp(&desc->datast.otanotify_rsp, appdata->data); break; case E_BLEPROTO_SERVICE_ID_OTADATA: rc = bleproto_encbin_otadata_rsp(&desc->datast.otadata_rsp, appdata->data); break; case E_BLEPROTO_SERVICE_ID_RUNCMD_V2: 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)); break; case E_BLEPROTO_SERVICE_ID_OTADATA_V2: rc = ble_proto_pack(&desc->datast.otadata_v2_rsp, appdata->data, sizeof(appdata->data)); break; default: /* unkown serviceid */ return (-1); } } else { /* unkown msgtype */ return (-1); } /* failed to encjson struct */ if (rc <= 0) { return (-1); } /* datalen */ appdata->header.datalen = (uint16_t)rc; /* appdata_serialize */ return bleproto_appdata_serialize(appdata, packetlen, txbuf, txbuf_size); } int bleproto_appdata_decode(uint8_t *rxbuf, uint16_t len, bleproto_appdata_desc_t *desc) { int rc, rlen; /* * V2(ble_proto_unpack) 零拷贝:bytes_data 等指向 appdata.data。 * 若用栈局部变量,函数返回后指针悬空,usr_run_cmd_code_v2 会踩坏数据。 * 使用 static,保证 desc 内指针在下次 decode 前有效。 */ static bleproto_appdata_t s_appdata; bleproto_appdata_t *appdata = &s_appdata; /* appdata_deserialize */ rlen = bleproto_appdata_deserialize(rxbuf, len, appdata); if (rlen <= 0) { return (rlen); } /* header */ { desc->header = appdata->header; } /* data */ if (appdata->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_REQ) { switch (appdata->header.serviceid) { case E_BLEPROTO_SERVICE_ID_DEVICEINFO: rc = bleproto_decjson_deviceinfo_req(appdata->data, appdata->header.datalen, &desc->datast.deviceinfo_req); break; case E_BLEPROTO_SERVICE_ID_AUTHSETUP: rc = bleproto_decjson_authsetup_req(appdata->data, appdata->header.datalen, &desc->datast.authsetup_req); break; case E_BLEPROTO_SERVICE_ID_AUTHDELETE: rc = bleproto_decjson_authdelete_req(appdata->data, appdata->header.datalen, &desc->datast.authdelete_req); break; case E_BLEPROTO_SERVICE_ID_RUNCMD: rc = bleproto_decjson_runcmd_req(appdata->data, appdata->header.datalen, &desc->datast.runcmd_req); break; case E_BLEPROTO_SERVICE_ID_REPORTCMD: rc = bleproto_decjson_reportcmd_req(appdata->data, appdata->header.datalen, &desc->datast.reportcmd_req); break; case E_BLEPROTO_SERVICE_ID_DOACTION: rc = bleproto_decjson_doaction_req(appdata->data, appdata->header.datalen, &desc->datast.doaction_req); break; case E_BLEPROTO_SERVICE_ID_OTANOTIFY: rc = bleproto_decjson_otanotify_req(appdata->data, appdata->header.datalen, &desc->datast.otanotify_req); break; case E_BLEPROTO_SERVICE_ID_OTADATA: rc = bleproto_decjson_otadata_req(appdata->data, appdata->header.datalen, &desc->datast.otadata_req); break; case E_BLEPROTO_SERVICE_ID_RUNCMD_V2: printf("runcmd_v2_req \n"); rc = ble_proto_unpack(appdata->data, appdata->header.datalen, &desc->datast.runcmd_v2_req); printf("runcmd_v2_req rc = %d \n", rc); break; case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2: printf("reportcmd_v2_req \n"); rc = ble_proto_unpack(appdata->data, appdata->header.datalen, &desc->datast.reportcmd_v2_req); printf("reportcmd_v2_req rc = %d \n", rc); break; case E_BLEPROTO_SERVICE_ID_OTADATA_V2: printf("otadata_v2_req \n"); rc = ble_proto_unpack(appdata->data, appdata->header.datalen, &desc->datast.otadata_v2_req); printf("otadata_v2_req rc = %d \n", rc); break; default: /* unkown serviceid */ return (-1); } } else if (appdata->header.msgtype == BLEPROTO_APPDATA_MSGTYPE_RSP) { switch (appdata->header.serviceid) { case E_BLEPROTO_SERVICE_ID_DEVICEINFO: rc = bleproto_decjson_deviceinfo_rsp(appdata->data, appdata->header.datalen, &desc->datast.deviceinfo_rsp); break; case E_BLEPROTO_SERVICE_ID_AUTHSETUP: rc = bleproto_decjson_authsetup_rsp(appdata->data, appdata->header.datalen, &desc->datast.authsetup_rsp); break; case E_BLEPROTO_SERVICE_ID_AUTHDELETE: rc = bleproto_decjson_authdelete_rsp(appdata->data, appdata->header.datalen, &desc->datast.authdelete_rsp); break; case E_BLEPROTO_SERVICE_ID_RUNCMD: rc = bleproto_decjson_runcmd_rsp(appdata->data, appdata->header.datalen, &desc->datast.runcmd_rsp); break; case E_BLEPROTO_SERVICE_ID_REPORTCMD: rc = bleproto_decjson_reportcmd_rsp(appdata->data, appdata->header.datalen, &desc->datast.reportcmd_rsp); break; case E_BLEPROTO_SERVICE_ID_DOACTION: rc = bleproto_decjson_doaction_rsp(appdata->data, appdata->header.datalen, &desc->datast.doaction_rsp); break; case E_BLEPROTO_SERVICE_ID_OTANOTIFY: rc = bleproto_decjson_otanotify_rsp(appdata->data, appdata->header.datalen, &desc->datast.otanotify_rsp); break; case E_BLEPROTO_SERVICE_ID_OTADATA: rc = bleproto_debin_otadata_rsp(appdata->data, appdata->header.datalen, &desc->datast.otadata_rsp); break; case E_BLEPROTO_SERVICE_ID_RUNCMD_V2: printf("runcmd_v2_rsp \n"); rc = ble_proto_unpack(appdata->data, appdata->header.datalen, &desc->datast.runcmd_v2_rsp); printf("runcmd_v2_rsp rc = %d \n", rc); break; case E_BLEPROTO_SERVICE_ID_REPORTCMD_V2: printf("reportcmd_v2_rsp \n"); rc = ble_proto_unpack(appdata->data, appdata->header.datalen, &desc->datast.reportcmd_v2_rsp); printf("reportcmd_v2_rsp rc = %d \n", rc); break; case E_BLEPROTO_SERVICE_ID_OTADATA_V2: printf("otadata_v2_rsp \n"); rc = ble_proto_unpack(appdata->data, appdata->header.datalen, &desc->datast.otadata_v2_rsp); printf("otadata_v2_rsp rc = %d \n", rc); break; default: /* unkown serviceid */ return (-1); } } else { /* unkown msgtype */ return (-1); } /* failed to decjson struct */ if (rc < 0) { return (-1); } return (rlen); } /****************************************************************************/ /* */ /* End of file. */ /* */ /****************************************************************************/