Files
2026-09-01 17:31:15 +08:00

530 lines
21 KiB
C

/****************************************************************************/
/* 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. */
/* */
/****************************************************************************/