Files
JBao_Sprayer_FW/apps/usr_le_code/bleproto_packer.c
T

3093 lines
90 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/****************************************************************************/
/* bleproto_packer.c
*
* Copyright (C) 2024 四川迈科创智科技有限公司
*
****************************************************************************/
/****************************************************************************/
/* Included Files */
/****************************************************************************/
#include "bleproto.h"
#include "system/includes.h"
#include "inttypes.h"
/****************************************************************************/
/* Trace Definitions */
/****************************************************************************/
/****************************************************************************/
/* Pre-processor Definitions */
/****************************************************************************/
/**
* @def UTILS_BITFIELD_GET
* @brief get bitfield value.
*
* @note MUSTBE `s`<=`e`.
*
* @param[in] v - The value to get.
* @param[in] e - The end-bit number.
* @param[in] s - The start-bit number.
*
* @code
* uint8_t ctrl;
* - bit7-2: type
* - bit1-0: id
* type = UTILS_BITFIELD_GET(ctrl, 7, 2);
* id = UTILS_BITFIELD_GET(ctrl, 1, 0);
* @endcode
*/
/**
* @def UTILS_BITFIELD_SET
* @brief set bitfield value.
*
* @note MUSTBE `s`<=`e`.
*
* @param[in] v - The value to set.
* @param[in] e - The end-bit number.
* @param[in] s - The start-bit number.
*
* @code
* uint8_t ctrl;
* - bit7-2: type
* - bit1-0: id
* ctrl = UTILS_BITFIELD_SET(type, 7, 2) | UTILS_BITFIELD_SET(id, 1, 0);
* @endcode
*/
/* Helper bitfield encode/decode macros */
#define UTILS_STATIC_ASSERT_OR_ZERO(cond) (sizeof(char[1 - 2 * !(cond)]) - 1)
#define UTILS_BITFILED_CHECK(e, s) UTILS_STATIC_ASSERT_OR_ZERO((e) >= (s))
#define UTILS_BITFIELD_MASK(e, s) \
(UTILS_BITFILED_CHECK(e, s) + (((1UL << ((e) - (s) + 1)) - 1UL) << (s)))
#define UTILS_BITFIELD_GET(v, e, s) \
(UTILS_BITFILED_CHECK(e, s) + \
(((v) >> (s)) & UTILS_BITFIELD_MASK(((e) - (s)), 0)))
#define UTILS_BITFIELD_SET(v, e, s) \
(UTILS_BITFILED_CHECK(e, s) + \
(((v)&UTILS_BITFIELD_MASK(((e) - (s)), 0)) << (s)))
#define UTILS_BITFIELD_CLR(v, e, s) \
(UTILS_BITFILED_CHECK(e, s) + ((v) & (~(UTILS_BITFIELD_MASK(e, s)))))
#define UTILS_BITFIELD_UPD(oldv, e, s, newv) \
(UTILS_BITFILED_CHECK(e, s) + \
(UTILS_BITFIELD_CLR(oldv, e, s) | UTILS_BITFIELD_SET(newv, e, s)))
/**
* @def UTILS_MIN
* @brief Calculates the minimum of x and y.
*/
#define UTILS_MIN(x, y) ((x) < (y) ? (x) : (y))
/****************************************************************************/
/* Private Types */
/****************************************************************************/
/****************************************************************************/
/* Private Function Prototypes */
/****************************************************************************/
/****************************************************************************/
/* Private Data */
/****************************************************************************/
/****************************************************************************/
/* Public Data */
/****************************************************************************/
/****************************************************************************/
/* Private Functions */
/****************************************************************************/
static uint8_t hex_char_to_int(char c)
{
// 将十六进制字符转换为对应的数值
if (c >= '0' && c <= '9') {
return c - '0';
} else if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
} else if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
// 非十六进制字符,返回无效值
return 0xFF;
}
/* utils */
static void proto_bytes_put_le16(uint8_t dst[2], uint16_t val)
{
dst[0] = val;
dst[1] = val >> 8;
}
static uint16_t proto_bytes_get_le16(const uint8_t src[2])
{
return ((uint16_t)src[1] << 8) | src[0];
}
static int proto_strhex_to_byte(const char *str, uint8_t *bytes, size_t size)
{
// string转bytes
if (str == NULL || bytes == NULL) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
size_t str_len = strlen(str);
if (str_len % 2 != 0 || str_len / 2 > size) {
BLEPROTO_T_E("Invalid string length or buffer size");
return -1;
}
for (size_t i = 0; i < str_len; i += 2) {
uint8_t high = hex_char_to_int(str[i]);
uint8_t low = hex_char_to_int(str[i + 1]);
if (high == 0xFF || low == 0xFF) {
BLEPROTO_T_E("Invalid hex character");
return -1;
}
bytes[i / 2] = (high << 4) | low;
}
return (int)(str_len / 2);
}
/****************************************************************************/
/* Public Functions */
/****************************************************************************/
int bleproto_advdata_serialize(bleproto_adv_t *adv,
uint8_t * data,
uint8_t size)
{
uint8_t offset = 0;
/* check params */
if (!adv || !data || size < BLEPROTO_ADV_MAX_SZ) {
BLEPROTO_T_E("Invalid parameters");
return (-1);
}
/* check adv2 type */
if (adv->adv2.ad_type != BLEPROTO_ADV_TYPE_SVC_DATA_UUID16 &&
adv->adv2.ad_type != BLEPROTO_ADV_TYPE_MFG_DATA) {
BLEPROTO_T_E("Invalid adv2.adv_type");
return (-1);
}
/* clear */
memset(data, 0, size);
/* adv1 */
{
/* rewrite member */
adv->adv1.length = 0x02;
adv->adv1.ad_type = BLEPROTO_ADV_TYPE_FLAGS;
adv->adv1.ad_data = 0x06;
data[offset++] = adv->adv1.length;
data[offset++] = adv->adv1.ad_type;
data[offset++] = adv->adv1.ad_data;
}
/* adv2 */
adv->adv2.length = BLEPROTO_ADV_MAX_SZ - 3 - 1;
{
/* adv2 length */
data[offset++] = adv->adv2.length;
/* adv2 type */
data[offset++] = adv->adv2.ad_type;
}
if (adv->adv2.ad_type == BLEPROTO_ADV_TYPE_SVC_DATA_UUID16) {
/* uuid, little endian */
proto_bytes_put_le16(&data[offset],
adv->adv2.ad_data.service_data.uuid);
offset += 2;
/////////////////////////////////////////
// spec_data
/////////////////////////////////////////
bleproto_adv_specdata_t *spec_data =
&adv->adv2.ad_data.service_data.spec_data;
/* version */
data[offset++] = spec_data->version;
/* business */
data[offset++] = spec_data->business;
/* rfu */
data[offset++] = 0;
data[offset++] = 0;
/* txpower */
data[offset++] = (uint8_t)spec_data->txpower;
/* manucode */
{
spec_data->manucode.type = BLEPROTO_ADV_TLV_TYPE_MANUCODE;
spec_data->manucode.length = BLEPROTO_ADV_TLV_LENGTH_MANUCODE;
data[offset++] = spec_data->manucode.type;
data[offset++] = spec_data->manucode.length;
memcpy(&data[offset],
spec_data->manucode.value,
BLEPROTO_ADV_TLV_LENGTH_MANUCODE);
offset += BLEPROTO_ADV_TLV_LENGTH_MANUCODE;
}
/* prodcode */
{
spec_data->prodcode.type = BLEPROTO_ADV_TLV_TYPE_PRODCODE;
spec_data->prodcode.length = BLEPROTO_ADV_TLV_LENGTH_PRODCODE;
data[offset++] = spec_data->prodcode.type;
data[offset++] = spec_data->prodcode.length;
memcpy(&data[offset],
spec_data->prodcode.value,
BLEPROTO_ADV_TLV_LENGTH_PRODCODE);
offset += BLEPROTO_ADV_TLV_LENGTH_PRODCODE;
}
/* separator */
{
spec_data->separator = 0xFF;
data[offset++] = spec_data->separator;
}
/* selfdata */
{
memcpy(&data[offset],
spec_data->selfdata,
sizeof(spec_data->selfdata));
offset += (uint8_t)sizeof(spec_data->selfdata);
}
} else if (adv->adv2.ad_type == BLEPROTO_ADV_TYPE_MFG_DATA) {
bleproto_advdata_mfg_t *mfg_data = &adv->adv2.ad_data.mfg_data;
/* siot */
data[offset++] = mfg_data->siot[0];
data[offset++] = mfg_data->siot[1];
data[offset++] = mfg_data->siot[2];
data[offset++] = mfg_data->siot[3];
data[offset++] = mfg_data->siot[4];
data[offset++] = mfg_data->siot[5];
/* flag */
data[offset++] = mfg_data->flag;
/* txpower */
data[offset++] = (uint8_t)mfg_data->txpower;
/* gwmac */
data[offset++] = mfg_data->gwmac[0];
data[offset++] = mfg_data->gwmac[1];
data[offset++] = mfg_data->gwmac[2];
data[offset++] = mfg_data->gwmac[3];
data[offset++] = mfg_data->gwmac[4];
data[offset++] = mfg_data->gwmac[5];
/* manucode */
{
mfg_data->manucode.type = BLEPROTO_ADV_TLV_TYPE_MANUCODE;
mfg_data->manucode.length = BLEPROTO_ADV_TLV_LENGTH_MANUCODE;
data[offset++] = mfg_data->manucode.type;
data[offset++] = mfg_data->manucode.length;
memcpy(&data[offset],
mfg_data->manucode.value,
BLEPROTO_ADV_TLV_LENGTH_MANUCODE);
offset += BLEPROTO_ADV_TLV_LENGTH_MANUCODE;
}
/* prodcode */
{
mfg_data->prodcode.type = BLEPROTO_ADV_TLV_TYPE_PRODCODE;
mfg_data->prodcode.length = BLEPROTO_ADV_TLV_LENGTH_PRODCODE;
data[offset++] = mfg_data->prodcode.type;
data[offset++] = mfg_data->prodcode.length;
memcpy(&data[offset],
mfg_data->prodcode.value,
BLEPROTO_ADV_TLV_LENGTH_PRODCODE);
offset += BLEPROTO_ADV_TLV_LENGTH_PRODCODE;
}
}
return (offset);
}
int bleproto_advdata_deserialize(const uint8_t * data,
uint8_t len,
bleproto_adv_t *adv)
{
int rc;
uint8_t offset = 0;
/* check parameters */
if (!data || !adv) {
BLEPROTO_T_E("Invalid parameters");
return (-1);
}
/* check len */
if (len != BLEPROTO_ADV_MAX_SZ) {
BLEPROTO_T_E("Invalid len");
return (-1);
}
do {
/* clear */
memset(adv, 0, sizeof(*adv));
/* adv1 */
adv->adv1.length = data[offset++];
adv->adv1.ad_type = data[offset++];
adv->adv1.ad_data = data[offset++];
if (adv->adv1.length != 0x02 ||
adv->adv1.ad_type != BLEPROTO_ADV_TYPE_FLAGS ||
adv->adv1.ad_data != 0x06) {
BLEPROTO_T_E("Invalid adv1 data");
rc = -1;
break;
}
adv->adv2.length = data[offset++];
adv->adv2.ad_type = data[offset++];
if (adv->adv2.length != BLEPROTO_ADV_MAX_SZ - 3 - 1) {
BLEPROTO_T_E("Invalid adv2 len");
rc = -1;
break;
}
/* adv2 */
if (adv->adv2.ad_type == BLEPROTO_ADV_TYPE_SVC_DATA_UUID16) {
/* uuid, little endian */
adv->adv2.ad_data.service_data.uuid =
proto_bytes_get_le16(&data[offset]);
offset += 2;
/////////////////////////////////////////
// spec_data
/////////////////////////////////////////
bleproto_adv_specdata_t *spec_data =
&adv->adv2.ad_data.service_data.spec_data;
/* version */
spec_data->version = data[offset++];
/* business */
spec_data->business = data[offset++];
/* rfu */
spec_data->rfu[0] = data[offset++];
spec_data->rfu[1] = data[offset++];
/* txpower */
spec_data->txpower = (int8_t)data[offset++];
/* manucode */
{
spec_data->manucode.type = data[offset++];
if (spec_data->manucode.type !=
BLEPROTO_ADV_TLV_TYPE_MANUCODE) {
BLEPROTO_T_E("Invalid adv2 service_data.manucode.type");
rc = -1;
break;
}
spec_data->manucode.length = data[offset++];
if (spec_data->manucode.length !=
BLEPROTO_ADV_TLV_LENGTH_MANUCODE) {
BLEPROTO_T_E("Invalid adv2 service_data.manucode.length");
rc = -1;
break;
}
memcpy(spec_data->manucode.value,
&data[offset],
spec_data->manucode.length);
offset += spec_data->manucode.length;
}
/* prodcode */
{
spec_data->prodcode.type = data[offset++];
if (spec_data->prodcode.type !=
BLEPROTO_ADV_TLV_TYPE_PRODCODE) {
BLEPROTO_T_E("Invalid adv2 service_data.prodcode.type");
rc = -1;
break;
}
spec_data->prodcode.length = data[offset++];
if (spec_data->prodcode.length !=
BLEPROTO_ADV_TLV_LENGTH_PRODCODE) {
BLEPROTO_T_E("Invalid adv2 service_data.prodcode.length");
rc = -1;
break;
}
memcpy(spec_data->prodcode.value,
&data[offset],
spec_data->prodcode.length);
offset += spec_data->prodcode.length;
}
/* separator */
{
spec_data->separator = data[offset++];
if (spec_data->separator != 0xff) {
BLEPROTO_T_E("Invalid adv2 service_data.separator");
rc = -1;
break;
}
}
/* selfdata */
{
memcpy(spec_data->selfdata,
&data[offset],
sizeof(spec_data->selfdata));
offset += (uint8_t)sizeof(spec_data->selfdata);
}
} else if (adv->adv2.ad_type == BLEPROTO_ADV_TYPE_MFG_DATA) {
bleproto_advdata_mfg_t *mfg_data = &adv->adv2.ad_data.mfg_data;
/* fix "SIOT-1" */
memcpy(mfg_data->siot, &data[offset], 6);
// if (mfg_data->siot[0] != 'S' || mfg_data->siot[1] != 'I' ||
// mfg_data->siot[2] != 'O' || mfg_data->siot[3] != 'T' ||
// mfg_data->siot[4] != '-') {
// BLEPROTO_T_E("Invalid adv2 mfg_data.siot");
// rc = -1;
// break;
// }
offset += 6;
/* flag */
mfg_data->flag = data[offset++];
/* txpower */
mfg_data->txpower = (int8_t)data[offset++];
/* gwmac */
memcpy(mfg_data->gwmac, &data[offset], 6);
offset += 6;
/* manucode */
{
mfg_data->manucode.type = data[offset++];
if (mfg_data->manucode.type !=
BLEPROTO_ADV_TLV_TYPE_MANUCODE) {
BLEPROTO_T_E("Invalid adv2 mfg_data.manucode.type");
rc = -1;
break;
}
mfg_data->manucode.length = data[offset++];
if (mfg_data->manucode.length !=
BLEPROTO_ADV_TLV_LENGTH_MANUCODE) {
BLEPROTO_T_E("Invalid adv2 mfg_data.manucode.length");
rc = -1;
break;
}
memcpy(mfg_data->manucode.value,
&data[offset],
mfg_data->manucode.length);
offset += mfg_data->manucode.length;
}
/* prodcode */
{
mfg_data->prodcode.type = data[offset++];
if (mfg_data->prodcode.type !=
BLEPROTO_ADV_TLV_TYPE_PRODCODE) {
BLEPROTO_T_E("Invalid adv2 mfg_data.prodcode.type");
rc = -1;
break;
}
mfg_data->prodcode.length = data[offset++];
if (mfg_data->prodcode.length !=
BLEPROTO_ADV_TLV_LENGTH_PRODCODE) {
BLEPROTO_T_E("Invalid adv2 mfg_data.prodcode.length");
rc = -1;
break;
}
memcpy(mfg_data->prodcode.value,
&data[offset],
mfg_data->prodcode.length);
offset += mfg_data->prodcode.length;
}
} else {
BLEPROTO_T_E("Invalid adv2 adv_type");
rc = -1;
break;
}
/* check offset */
if (offset != 31) {
BLEPROTO_T_E("Invalid offset");
rc = -1;
break;
}
rc = offset;
} while (0);
return (rc);
}
int bleproto_appdata_serialize_len(bleproto_appdata_t *appdata,
uint8_t packetlen,
uint16_t * outlen)
{
/* check param */
if (!appdata || packetlen <= BLEPROTO_APPDATA_HEADR_LEN) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
/* data total len */
uint16_t datalen = appdata->header.datalen;
/* each frame max payload length */
uint8_t frame_max_payload = packetlen - BLEPROTO_APPDATA_HEADR_LEN;
/* calculate total frames needed */
uint16_t totalframe;
if (datalen == 0) {
/* even with no data, we need at least one frame for the header */
totalframe = 1;
} else {
/* calculate frames needed for the data */
totalframe = (datalen + frame_max_payload - 1) / frame_max_payload;
}
if (totalframe > 255) {
BLEPROTO_T_E("Invalid appdata.datalen too long >(%u)",
(uint16_t)frame_max_payload * 255);
return -1;
}
/* calculate total buffer size needed */
if (totalframe <= 1) {
/* at least one frame is needed */
if (outlen) {
*outlen = datalen + BLEPROTO_APPDATA_HEADR_LEN;
}
} else {
/* calculate size of full frames */
uint16_t full_frames_size = (uint16_t)(totalframe - 1) * packetlen;
// clang-format off
/* calculate size of last frame */
uint16_t last_frame_size =
/* header */ BLEPROTO_APPDATA_HEADR_LEN +
/* payload */ datalen - (uint16_t)((totalframe - 1) * frame_max_payload);
// clang-format on
/* total size is sum of full frames and last frame */
if (outlen) {
*outlen = full_frames_size + last_frame_size;
}
}
return 0;
}
int bleproto_appdata_serialize(bleproto_appdata_t *appdata,
uint8_t packetlen,
uint8_t * buf,
uint16_t size)
{
int rc, offset = 0;
uint16_t data_offset = 0;
/* check param */
if (!appdata || packetlen <= BLEPROTO_APPDATA_HEADR_LEN) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
/* totoal len */
uint16_t total_len;
rc = bleproto_appdata_serialize_len(appdata, packetlen, &total_len);
if (rc < 0) {
return -1;
}
if (size < total_len) {
BLEPROTO_T_E("Invalid datalen:%u, buf too short(%u<%u)",
appdata->header.datalen,
size,
total_len);
return -1;
}
/* data total len */
uint16_t datalen = appdata->header.datalen;
/* each frame max payload length */
uint8_t frame_max_payload = packetlen - BLEPROTO_APPDATA_HEADR_LEN;
/* calculate total frames needed */
uint16_t totalframe;
if (datalen == 0) {
/* even with no data, we need at least one frame for the header */
totalframe = 1;
} else {
/* calculate frames needed for the data */
totalframe = (datalen + frame_max_payload - 1) / frame_max_payload;
}
if (totalframe > 255) {
BLEPROTO_T_E("Invalid appdata.datalen too long");
return -1;
}
for (uint8_t i = 0; i < (uint8_t)totalframe; i++) {
/* pthis_frame_len */
uint8_t pthis_frame_len = 0;
if (totalframe == 1) {
/* only one frame */
pthis_frame_len = (uint8_t)datalen;
} else if (i + 1 < totalframe) {
/* full size frames */
pthis_frame_len = frame_max_payload;
} else {
/* last frame */
pthis_frame_len = (uint8_t)(datalen - data_offset);
}
/* header */
bleproto_appdata_header_t hdr = appdata->header;
{
hdr.totalframe = totalframe;
if (totalframe == 1) {
hdr.frameseq = 0;
} else {
hdr.frameseq = i + 1;
}
}
/* serialize_header */
{
/* buf[0]: version[2:0] | datafmt[3:3] | msgtype[7:4] */
buf[offset + 0] = UTILS_BITFIELD_SET(hdr.version, 2, 0) |
UTILS_BITFIELD_SET(hdr.datafmt, 3, 3) |
UTILS_BITFIELD_SET(hdr.msgtype, 7, 4);
/* buf[1]: msgid[3:0] | encrypt[4:4] | reserve[7:5] */
buf[offset + 1] = UTILS_BITFIELD_SET(hdr.msgid, 3, 0) |
UTILS_BITFIELD_SET(hdr.encrypt, 4, 4) |
UTILS_BITFIELD_SET(hdr.reserve, 7, 5);
buf[offset + 2] = hdr.totalframe;
buf[offset + 3] = hdr.frameseq;
buf[offset + 4] = pthis_frame_len;
buf[offset + 5] = hdr.serviceid;
/* datalen in little endian */
proto_bytes_put_le16(&buf[offset + 6], hdr.datalen);
}
offset += BLEPROTO_APPDATA_HEADR_LEN;
/* payload */
if (pthis_frame_len != 0) {
memcpy(
&buf[offset], &appdata->data[data_offset], pthis_frame_len);
/* offset */
offset += pthis_frame_len;
/* data_offset */
data_offset += pthis_frame_len;
}
}
if (offset != total_len) {
BLEPROTO_T_E("Error calc appdata total_len");
return -1;
}
return (offset);
}
int bleproto_appdata_wrap_raw(uint8_t *txbuf,
uint16_t txbuf_size,
uint8_t packetlen,
const bleproto_appdata_header_t *header,
const uint8_t *payload,
uint16_t payload_len)
{
uint8_t frame_max;
uint16_t totalframe;
uint16_t need;
uint16_t offset = 0;
uint16_t data_offset = 0;
uint16_t i;
if (!txbuf || !header || packetlen <= BLEPROTO_APPDATA_HEADR_LEN) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
if (payload_len > 0 && !payload) {
BLEPROTO_T_E("Invalid payload");
return -1;
}
/* 与 serialize 相同:一帧总长 packetlen,其中 8B 头,其余为 payload */
frame_max = (uint8_t)(packetlen - BLEPROTO_APPDATA_HEADR_LEN);
if (payload_len == 0) {
totalframe = 1;
} else {
totalframe = (uint16_t)((payload_len + frame_max - 1u) / frame_max);
}
if (totalframe > 255u) {
BLEPROTO_T_E("payload too long, frames %u>255", (unsigned)totalframe);
return -1;
}
need = (uint16_t)((uint16_t)totalframe * BLEPROTO_APPDATA_HEADR_LEN + payload_len);
if (txbuf_size < need) {
BLEPROTO_T_E("txbuf too short %u<%u", (unsigned)txbuf_size, (unsigned)need);
return -1;
}
for (i = 0; i < totalframe; i++) {
uint8_t this_len;
uint8_t frameseq;
if (totalframe == 1u) {
this_len = (uint8_t)payload_len;
frameseq = 0; /* 单帧序号为 0 */
} else if ((uint16_t)(i + 1u) < totalframe) {
this_len = frame_max;
frameseq = (uint8_t)(i + 1u); /* 分包从 1 起 */
} else {
this_len = (uint8_t)(payload_len - data_offset);
frameseq = (uint8_t)(i + 1u);
}
/* buf[0]: version[2:0] | datafmt[3:3] | msgtype[7:4] */
txbuf[offset + 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[offset + 1] = UTILS_BITFIELD_SET(header->msgid, 3, 0) |
UTILS_BITFIELD_SET(header->encrypt, 4, 4) |
UTILS_BITFIELD_SET(header->reserve, 7, 5);
txbuf[offset + 2] = (uint8_t)totalframe;
txbuf[offset + 3] = frameseq;
txbuf[offset + 4] = this_len;
txbuf[offset + 5] = header->serviceid;
proto_bytes_put_le16(&txbuf[offset + 6], payload_len);
offset = (uint16_t)(offset + BLEPROTO_APPDATA_HEADR_LEN);
if (this_len != 0) {
memcpy(&txbuf[offset], &payload[data_offset], this_len);
offset = (uint16_t)(offset + this_len);
data_offset = (uint16_t)(data_offset + this_len);
}
}
if (totalframe > 1u) {
BLEPROTO_T_E("wrap_raw split %uB -> %u frames, out %uB",
(unsigned)payload_len, (unsigned)totalframe, (unsigned)offset);
}
return (int)offset;
}
int bleproto_appdata_deserialize(uint8_t * buf,
uint16_t len,
bleproto_appdata_t *appdata)
{
/* check parameters */
if (!buf || !appdata) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
/* 检查是否至少有一个完整的包头 */
if (len < BLEPROTO_APPDATA_HEADR_LEN) {
// 数据不够,需要更多数据
return 0;
}
int offset = 0;
uint8_t msgid;
uint8_t totalframe;
uint8_t frameseq;
uint16_t datalen;
uint8_t frame_payload_len;
uint8_t max_payload = 0;
uint8_t recv_frames = 0;
/* 第一轮: 扫描所有数据,验证分包的完整性和一致性 */
{
int scan_offset = 0;
bool first_frame = true;
while (scan_offset < len) {
/* 解析header中的关键字段 */
msgid = UTILS_BITFIELD_GET(buf[scan_offset + 1], 3, 0);
totalframe = buf[scan_offset + 2];
frameseq = buf[scan_offset + 3];
frame_payload_len = buf[scan_offset + 4];
datalen = proto_bytes_get_le16(&buf[scan_offset + 6]);
BLEPROTO_T_S("[%u/%u]=0x%02X(%u),msgid:%u,datalen:0x%02X(%u)",
frameseq,
totalframe,
frame_payload_len,
frame_payload_len,
msgid,
datalen,
datalen);
/* 基本参数检查 */
if (totalframe == 0) {
BLEPROTO_T_E("Invalid totalframe");
return -1;
}
if (frameseq > totalframe) {
BLEPROTO_T_E("Invalid frameseq");
return -1;
}
if (datalen > BLEPROTO_APPDATA_DATA_MAX_SZ) {
BLEPROTO_T_E("Invalid datalen");
return -1;
}
/* 分包一致性检查 */
if (first_frame) {
first_frame = false;
// 使用第一帧的payload长度作为最大payload
max_payload = frame_payload_len;
} else {
/* 检查msgid一致性 */
if (msgid != UTILS_BITFIELD_GET(buf[1], 3, 0)) {
BLEPROTO_T_E("Inconsistent msgid");
return -1;
}
/* 检查totalframe一致性 */
if (totalframe != buf[2]) {
BLEPROTO_T_E("Inconsistent totalframe");
return -1;
}
/* 检查frameseq连续性 */
uint8_t last_frameseq =
buf[scan_offset -
(BLEPROTO_APPDATA_HEADR_LEN + max_payload) + 3];
if (frameseq != (last_frameseq + 1)) {
BLEPROTO_T_E("Non-sequential frameseq:%u!=%u",
frameseq,
(last_frameseq + 1));
return -1;
}
/* 检查非最后一帧的payload长度是否与第一帧相同 */
if (frameseq < (totalframe - 1) &&
frame_payload_len != max_payload) {
BLEPROTO_T_E("Inconsistent frame payload length");
return -1;
}
}
/* 检查payload长度 */
if ((len - scan_offset) <
(BLEPROTO_APPDATA_HEADR_LEN + frame_payload_len)) {
return 0; // 需要更多数据
}
/* 验证frame_payload_len */
if (totalframe == 1) {
if (frame_payload_len != datalen) {
BLEPROTO_T_E(
"Invalid frame_payload_len for single frame");
return -1;
}
} else {
if (frameseq < totalframe) {
/* 非最后一帧必须是满包 */
if (frame_payload_len != max_payload) {
BLEPROTO_T_E(
"Invalid frame_payload_len for non-last frame");
return -1;
}
} else {
/* 最后一帧的长度计算 */
uint16_t last_frame_payload = datalen % max_payload;
if (last_frame_payload == 0) {
last_frame_payload = max_payload;
}
if (frame_payload_len != last_frame_payload) {
BLEPROTO_T_E(
"Invalid frame_payload_len for last frame(%u!=%u)",
frame_payload_len,
last_frame_payload);
return -1;
}
}
}
/* recv_frames */
recv_frames++;
scan_offset += BLEPROTO_APPDATA_HEADR_LEN + frame_payload_len;
}
/* 检查是否收到了完整的包 */
if (recv_frames != totalframe) {
// 还没收到所有分包
return 0;
}
}
/* 第二轮: 解析数据并填充到appdata结构中 */
{
/* 解析第一帧header */
bleproto_appdata_header_t *hdr = &appdata->header;
/* buf[0]: version[2:0] | datafmt[3:3] | msgtype[7:4] */
hdr->version = UTILS_BITFIELD_GET(buf[0], 2, 0);
hdr->datafmt = UTILS_BITFIELD_GET(buf[0], 3, 3);
hdr->msgtype = UTILS_BITFIELD_GET(buf[0], 7, 4);
/* buf[1]: msgid[3:0] | encrypt[4:4] | reserve[7:5] */
hdr->msgid = UTILS_BITFIELD_GET(buf[1], 3, 0);
hdr->encrypt = UTILS_BITFIELD_GET(buf[1], 4, 4);
hdr->reserve = UTILS_BITFIELD_GET(buf[1], 7, 5);
hdr->totalframe = buf[2];
hdr->frameseq = buf[3];
hdr->framelen = buf[4];
hdr->serviceid = buf[5];
hdr->datalen = proto_bytes_get_le16(&buf[6]);
/* 复制所有payload数据 */
uint16_t data_offset = 0;
uint8_t frames_processed = 0;
/* clear offset */
offset = 0;
while (frames_processed < hdr->totalframe) {
/* this frame payload length */
frame_payload_len = buf[offset + 4];
if (frame_payload_len > 0) {
uint8_t curr_frameseq = buf[offset + 3];
if (curr_frameseq == 0) {
data_offset = 0;
} else {
data_offset = (curr_frameseq - 1) * max_payload;
}
/* copy payload data */
memcpy(&appdata->data[data_offset],
&buf[offset + BLEPROTO_APPDATA_HEADR_LEN],
frame_payload_len);
}
offset += BLEPROTO_APPDATA_HEADR_LEN + frame_payload_len;
frames_processed++;
}
}
/* 返回处理的字节数 */
return offset;
}
int bleproto_encjson_ycmd(const bleproto_ycmd_t *ycmd,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
uint16_t i;
/* check param */
if (!ycmd || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
if (ycmd->arg_int32_count > YCMD_INT32_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_int32_count");
return -1;
}
if (ycmd->arg_string_count > YCMD_STRING_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_string_count");
return -1;
}
for (i = 0; i < ycmd->arg_string_count; i++) {
if (strlen(ycmd->arg_string[i]) == 0) {
BLEPROTO_T_E("Invalid ycmd.arg_string[%u]", i);
return -1;
}
}
if (ycmd->arg_bytes_count > YCMD_BYTES_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_bytes_count");
return -1;
}
char *str = (char *)data;
// {"cmd_id":xxxx,"arg_int32":[],"arg_string":[],"arg_bytes":"xxxx","t":"xxxxxxxx" }
// {
offset = snprintf(str, size, "%s", "{");
// cmd_id
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%" PRId32 ",",
"cmd_id",
(int)ycmd->cmd_id);
}
// arg_int32
if (ycmd->arg_int32_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":[", "arg_int32");
for (i = 0; i < ycmd->arg_int32_count; i++) {
offset += snprintf(&str[offset],
size - offset,
"%" PRId32 "",
ycmd->arg_int32[i]);
if (i != ycmd->arg_int32_count - 1) {
offset += snprintf(&str[offset], size - offset, "%s", ",");
}
}
offset += snprintf(&str[offset], size - offset, "%s", "],");
}
// arg_string
if (ycmd->arg_string_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":[", "arg_string");
for (i = 0; i < ycmd->arg_string_count; i++) {
offset += snprintf(
&str[offset], size - offset, "\"%s\"", ycmd->arg_string[i]);
if (i != ycmd->arg_string_count - 1) {
offset += snprintf(&str[offset], size - offset, "%s", ",");
}
}
offset += snprintf(&str[offset], size - offset, "%s", "],");
}
// arg_bytes
if (ycmd->arg_bytes_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":\"", "arg_bytes");
for (i = 0; i < ycmd->arg_bytes_count; i++) {
offset += snprintf(
&str[offset], size - offset, "%02X", ycmd->arg_bytes[i]);
}
offset += snprintf(&str[offset], size - offset, "%s", "\",");
}
// t
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":\"%" PRIu64 "\"",
"t",
ycmd->t);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("ycmd:%.*s", (int)offset, str);
return (offset);
}
int bleproto_decjson_ycmd(const uint8_t * data,
uint16_t len,
bleproto_ycmd_t *ycmd)
{
int rc, i;
/* check param */
if (!data || len == 0 || !ycmd) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("ycmd:%.*s", (int)len, str);
/* clear */
memset(ycmd, 0, sizeof(*ycmd));
// {"cmd_id":xxxx,"arg_int32":[],"arg_string":[],"arg_bytes":"xxxx","t":"xxxxxxxx" }
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
double v;
// cmd_id
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.cmd_id",
/* v */ &v);
if (rc > 0) {
ycmd->cmd_id = (int)v;
} else {
BLEPROTO_T_E("Error parse cmd_id");
return -1;
}
// arg_int32
for (i = 0; i < YCMD_INT32_MAX_COUNT; i++) {
const char *ptr = NULL;
int n;
char key[sizeof("$.arg_int32[65535]") + 1] = { 0 };
snprintf(key, sizeof(key), "$.arg_int32[%d]", i);
if (mjson_find(str, (int)len, key, &ptr, &n) == MJSON_TOK_NUMBER) {
char vstr[32] = { 0 };
memcpy(vstr, ptr, UTILS_MIN(n, 31));
ycmd->arg_int32[ycmd->arg_int32_count] =
(int32_t)strtol(vstr, NULL, 10);
ycmd->arg_int32_count++;
}
}
// arg_string
for (i = 0; i < YCMD_STRING_MAX_COUNT; i++) {
const char *ptr = NULL;
int n;
char key[sizeof("$.arg_string[65535]") + 1] = { 0 };
snprintf(key, sizeof(key), "$.arg_string[%d]", i);
if (mjson_find(str, (int)len, key, &ptr, &n) == MJSON_TOK_STRING) {
if (n >= 2 && ptr[0] == '"' && ptr[n - 1] == '"') {
ptr++; // 跳过首引号
n -= 2; // 去掉首尾引号的长度
} else {
BLEPROTO_T_E("Error parse arg_string");
return -1;
}
memcpy(ycmd->arg_string[ycmd->arg_string_count],
ptr,
UTILS_MIN(n, YCMD_STRING_MAX_SIZE));
ycmd->arg_string_count++;
}
}
// arg_bytes
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.arg_bytes",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
// strhex to byte
rc = proto_strhex_to_byte(
value_str, ycmd->arg_bytes, sizeof(ycmd->arg_bytes));
if (rc >= 0) {
ycmd->arg_bytes_count = (uint16_t)rc;
}
}
// t
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.t",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
ycmd->t = (uint64_t)strtoull(value_str, NULL, 10);
} else {
BLEPROTO_T_E("Error parse t");
return -1;
}
return (0);
}
int bleproto_encjson_deviceinfo_req(const bleproto_deviceinfo_req_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
//{"t":"xxxxxxxx",gmtoff:%d}
// {
offset = snprintf(str, size, "%s", "{");
// t
{
offset += snprintf(
&str[offset], size - offset, "\"t\":\"%" PRIu64 "\",", p->t);
}
// gmtoff
{
offset +=
snprintf(&str[offset], size - offset, "\"gmtoff\":%d", p->gmtoff);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_deviceinfo_rsp(const bleproto_deviceinfo_rsp_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
/* check params */
if (strlen(p->hwv) == 0) {
BLEPROTO_T_E("Invalid deviceinfo.rsp.hwv");
return -1;
}
if (strlen(p->swv) == 0) {
BLEPROTO_T_E("Invalid deviceinfo.rsp.swv");
return -1;
}
char *str = (char *)data;
// {"hwv":"%s","swv":"%s","prototype":%u,"hbcycle":%u,"longcon":%u}
// {
offset = snprintf(str, size, "%s", "{");
// hwv
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":\"%s\",", "hwv", p->hwv);
}
// swv
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":\"%s\",", "swv", p->swv);
}
// prototype
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%u,",
"prototype",
p->prototype);
}
// hbcycle
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":%u,", "hbcycle", p->hbcycle);
}
// longcon
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":%u", "longcon", p->longcon);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_authsetup_req(const bleproto_authsetup_req_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
/* check params */
if (strlen(p->devid) == 0) {
BLEPROTO_T_E("Invalid authsetup.req.devid");
return -1;
}
if (strlen(p->authcode) == 0) {
BLEPROTO_T_E("Invalid authsetup.req.authcode");
return -1;
}
char *str = (char *)data;
// {"gwmac":"xxxx","devid":"xxxx","authcode":"xxxx"}
// {
offset = snprintf(str, size, "%s", "{");
// gwmac
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":\"%02X%02X%02X%02X%02X%02X\",",
"gwmac",
p->gwmac[0],
p->gwmac[1],
p->gwmac[2],
p->gwmac[3],
p->gwmac[4],
p->gwmac[5]);
}
// devid
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":\"%s\",", "devid", p->devid);
}
// authcode
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":\"%s\"",
"authcode",
p->authcode);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_authsetup_rsp(const bleproto_authsetup_rsp_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
// {"errcode":xxx}
// {
offset = snprintf(str, size, "%s", "{");
// errcode
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%d",
"errcode",
(int)p->errcode);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_authdelete_req(const bleproto_authdelete_req_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
/* check params */
if (strlen(p->authcode) == 0) {
BLEPROTO_T_E("Invalid authdelete.req.authcode");
return -1;
}
char *str = (char *)data;
// { "authcode": "xxxx"}
// {
offset = snprintf(str, size, "%s", "{");
// authcode
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":\"%s\"",
"authcode",
p->authcode);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_authdelete_rsp(const bleproto_authdelete_rsp_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
// {"gwmac": "xxxx","errcode":xxx}
// {
offset = snprintf(str, size, "%s", "{");
// gwmac
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":\"%02X%02X%02X%02X%02X%02X\",",
"gwmac",
p->gwmac[0],
p->gwmac[1],
p->gwmac[2],
p->gwmac[3],
p->gwmac[4],
p->gwmac[5]);
}
// errcode
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%d",
"errcode",
(int)p->errcode);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_runcmd_req(const bleproto_runcmd_req_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
uint16_t i;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
if (p->ycmd.arg_int32_count > YCMD_INT32_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_int32_count");
return -1;
}
if (p->ycmd.arg_string_count > YCMD_STRING_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_string_count");
return -1;
}
for (i = 0; i < p->ycmd.arg_string_count; i++) {
if (strlen(p->ycmd.arg_string[i]) == 0) {
BLEPROTO_T_E("Invalid runcmd.req.arg_string[%u]", i);
return -1;
}
}
if (p->ycmd.arg_bytes_count > YCMD_BYTES_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_bytes_count");
return -1;
}
char *str = (char *)data;
// {"cmd_id":xxxx,"arg_int32":[],"arg_string":[],"arg_bytes":"xxxx","t":"xxxxxxxx" }
// {
offset = snprintf(str, size, "%s", "{");
// cmd_id
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%" PRId32 ",",
"cmd_id",
(int)p->ycmd.cmd_id);
}
// arg_int32
if (p->ycmd.arg_int32_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":[", "arg_int32");
for (i = 0; i < p->ycmd.arg_int32_count; i++) {
offset += snprintf(&str[offset],
size - offset,
"%" PRId32 "",
p->ycmd.arg_int32[i]);
if (i != p->ycmd.arg_int32_count - 1) {
offset += snprintf(&str[offset], size - offset, "%s", ",");
}
}
offset += snprintf(&str[offset], size - offset, "%s", "],");
}
// arg_string
if (p->ycmd.arg_string_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":[", "arg_string");
for (i = 0; i < p->ycmd.arg_string_count; i++) {
offset += snprintf(
&str[offset], size - offset, "\"%s\"", p->ycmd.arg_string[i]);
if (i != p->ycmd.arg_string_count - 1) {
offset += snprintf(&str[offset], size - offset, "%s", ",");
}
}
offset += snprintf(&str[offset], size - offset, "%s", "],");
}
// arg_bytes
if (p->ycmd.arg_bytes_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":\"", "arg_bytes");
for (i = 0; i < p->ycmd.arg_bytes_count; i++) {
offset += snprintf(
&str[offset], size - offset, "%02X", p->ycmd.arg_bytes[i]);
}
offset += snprintf(&str[offset], size - offset, "%s", "\",");
}
// t
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":\"%" PRIu64 "\"",
"t",
p->ycmd.t);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_runcmd_rsp(const bleproto_runcmd_rsp_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
uint16_t i;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
if (p->ycmd.arg_int32_count > YCMD_INT32_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_int32_count");
return -1;
}
if (p->ycmd.arg_string_count > YCMD_STRING_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_string_count");
return -1;
}
for (i = 0; i < p->ycmd.arg_string_count; i++) {
if (strlen(p->ycmd.arg_string[i]) == 0) {
BLEPROTO_T_E("Invalid runcmd.rsp.arg_string[%u]", i);
return -1;
}
}
if (p->ycmd.arg_bytes_count > YCMD_BYTES_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_bytes_count");
return -1;
}
char *str = (char *)data;
// {"cmd_id":xxxx,"arg_int32":[],"arg_string":[],"arg_bytes":"xxxx","t":"xxxxxxxx" }
// {
offset = snprintf(str, size, "%s", "{");
// cmd_id
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%" PRId32 ",",
"cmd_id",
(int)p->ycmd.cmd_id);
}
// arg_int32
if (p->ycmd.arg_int32_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":[", "arg_int32");
for (i = 0; i < p->ycmd.arg_int32_count; i++) {
offset += snprintf(&str[offset],
size - offset,
"%" PRId32 "",
p->ycmd.arg_int32[i]);
if (i != p->ycmd.arg_int32_count - 1) {
offset += snprintf(&str[offset], size - offset, "%s", ",");
}
}
offset += snprintf(&str[offset], size - offset, "%s", "],");
}
// arg_string
if (p->ycmd.arg_string_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":[", "arg_string");
for (i = 0; i < p->ycmd.arg_string_count; i++) {
offset += snprintf(
&str[offset], size - offset, "\"%s\"", p->ycmd.arg_string[i]);
if (i != p->ycmd.arg_string_count - 1) {
offset += snprintf(&str[offset], size - offset, "%s", ",");
}
}
offset += snprintf(&str[offset], size - offset, "%s", "],");
}
// arg_bytes
if (p->ycmd.arg_bytes_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":\"", "arg_bytes");
for (i = 0; i < p->ycmd.arg_bytes_count; i++) {
offset += snprintf(
&str[offset], size - offset, "%02X", p->ycmd.arg_bytes[i]);
}
offset += snprintf(&str[offset], size - offset, "%s", "\",");
}
// t
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":\"%" PRIu64 "\"",
"t",
p->ycmd.t);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_reportcmd_req(const bleproto_reportcmd_req_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
uint16_t i;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
if (p->ycmd.arg_int32_count > YCMD_INT32_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_int32_count");
return -1;
}
if (p->ycmd.arg_string_count > YCMD_STRING_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_string_count");
return -1;
}
for (i = 0; i < p->ycmd.arg_string_count; i++) {
if (strlen(p->ycmd.arg_string[i]) == 0) {
BLEPROTO_T_E("Invalid reportcmd.req.arg_string[%u]", i);
return -1;
}
}
if (p->ycmd.arg_bytes_count > YCMD_BYTES_MAX_COUNT) {
BLEPROTO_T_E("Invalid ycmd.arg_bytes_count");
return -1;
}
char *str = (char *)data;
// {"cmd_id":xxxx,"arg_int32":[],"arg_string":[],"arg_bytes":"xxxx","t":"xxxxxxxx"}
// {
offset = snprintf(str, size, "%s", "{");
// cmd_id
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%" PRId32 ",",
"cmd_id",
(int)p->ycmd.cmd_id);
}
// arg_int32
if (p->ycmd.arg_int32_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":[", "arg_int32");
for (i = 0; i < p->ycmd.arg_int32_count; i++) {
offset += snprintf(&str[offset],
size - offset,
"%" PRId32 "",
p->ycmd.arg_int32[i]);
if (i != p->ycmd.arg_int32_count - 1) {
offset += snprintf(&str[offset], size - offset, "%s", ",");
}
}
offset += snprintf(&str[offset], size - offset, "%s", "],");
}
// arg_string
if (p->ycmd.arg_string_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":[", "arg_string");
for (i = 0; i < p->ycmd.arg_string_count; i++) {
offset += snprintf(
&str[offset], size - offset, "\"%s\"", p->ycmd.arg_string[i]);
if (i != p->ycmd.arg_string_count - 1) {
offset += snprintf(&str[offset], size - offset, "%s", ",");
}
}
offset += snprintf(&str[offset], size - offset, "%s", "],");
}
// arg_bytes
if (p->ycmd.arg_bytes_count > 0) {
offset +=
snprintf(&str[offset], size - offset, "\"%s\":\"", "arg_bytes");
for (i = 0; i < p->ycmd.arg_bytes_count; i++) {
offset += snprintf(
&str[offset], size - offset, "%02X", p->ycmd.arg_bytes[i]);
}
offset += snprintf(&str[offset], size - offset, "%s", "\",");
}
// t
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":\"%" PRIu64 "\"",
"t",
p->ycmd.t);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_reportcmd_rsp(const bleproto_reportcmd_rsp_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
// {"errcode":xxx}
// {
offset = snprintf(str, size, "%s", "{");
// errcode
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%d",
"errcode",
(int)p->errcode);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_doaction_req(const bleproto_doaction_req_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
// {"action":%d}
// {
offset = snprintf(str, size, "%s", "{");
// action
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":%d", "action", p->action);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_doaction_rsp(const bleproto_doaction_rsp_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
// {"errcode":xxx}
// {
offset = snprintf(str, size, "%s", "{");
// errcode
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%d",
"errcode",
(int)p->errcode);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_otanotify_req(const bleproto_otanotify_req_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
// {"id": %d, "ver":"xxxx", "size":%d, "md5":"xxxxxxx"}
// {
offset = snprintf(str, size, "%s", "{");
// id
{
offset +=
snprintf(&str[offset], size - offset, "\"%s\":%d,", "id", p->id);
}
// ver
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":\"%s\",", "ver", p->version);
}
// size
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":%u,", "size", p->size);
}
// md5
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":\"%s\",", "md5", p->md5);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_otanotify_rsp(const bleproto_otanotify_rsp_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
// {"errcode":xxx}
// {
offset = snprintf(str, size, "%s", "{");
// errcode
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%d",
"errcode",
(int)p->errcode);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encjson_otadata_req(const bleproto_otadata_req_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
char *str = (char *)data;
// {"id": %d, "offset":%d, "maxsize":%d}
// {
offset = snprintf(str, size, "%s", "{");
// id
{
offset += snprintf(
&str[offset], size - offset, "\"%s\":%d, ", "id", (int)p->id);
}
// offset
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%d, ",
"offset",
(int)p->offset);
}
// maxsize
{
offset += snprintf(&str[offset],
size - offset,
"\"%s\":%d",
"maxsize",
(int)p->maxsize);
}
// }
offset += snprintf((&str[offset]), size - offset, "%s", "}");
/* dump output data */
BLEPROTO_T_D("data:%.*s", (int)offset, str);
return (offset);
}
int bleproto_encbin_otadata_rsp(const bleproto_otadata_rsp_t *p,
uint8_t data[BLEPROTO_APPDATA_DATA_MAX_SZ])
{
int offset = 0, size = BLEPROTO_APPDATA_DATA_MAX_SZ;
/* check param */
if (!p || !data) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
/* check buffer size */
if ((size_t)size < (sizeof(p->errcode) + sizeof(p->id) +
sizeof(p->offset) + sizeof(p->len) + p->len)) {
BLEPROTO_T_E("Buffer too small");
return -1;
}
/* serialize errcode (little-endian) */
data[offset++] = (uint8_t)(p->errcode & 0xFF);
data[offset++] = (uint8_t)((p->errcode >> 8) & 0xFF);
data[offset++] = (uint8_t)((p->errcode >> 16) & 0xFF);
data[offset++] = (uint8_t)((p->errcode >> 24) & 0xFF);
/* serialize id (little-endian) */
data[offset++] = (uint8_t)(p->id & 0xFF);
data[offset++] = (uint8_t)((p->id >> 8) & 0xFF);
data[offset++] = (uint8_t)((p->id >> 16) & 0xFF);
data[offset++] = (uint8_t)((p->id >> 24) & 0xFF);
/* serialize offset (little-endian) */
data[offset++] = (uint8_t)(p->offset & 0xFF);
data[offset++] = (uint8_t)((p->offset >> 8) & 0xFF);
data[offset++] = (uint8_t)((p->offset >> 16) & 0xFF);
data[offset++] = (uint8_t)((p->offset >> 24) & 0xFF);
/* serialize len (little-endian) */
data[offset++] = (uint8_t)(p->len & 0xFF);
data[offset++] = (uint8_t)((p->len >> 8) & 0xFF);
data[offset++] = (uint8_t)((p->len >> 16) & 0xFF);
data[offset++] = (uint8_t)((p->len >> 24) & 0xFF);
/* 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;
}
return offset;
}
int bleproto_decjson_deviceinfo_req(const uint8_t * data,
uint16_t len,
bleproto_deviceinfo_req_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
//{"t":"xxxxxxxx",gmtoff:%d}
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
double v;
// t
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.t",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
p->t = (uint64_t)strtoull(value_str, NULL, 10);
} else {
BLEPROTO_T_E("Error parse t");
return -1;
}
// gmtoff
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.gmtoff",
/* result */ &v);
if (rc > 0) {
p->gmtoff = (int)v;
} else {
BLEPROTO_T_E("Error parse gmtoff");
return -1;
}
return (0);
}
int bleproto_decjson_deviceinfo_rsp(const uint8_t * data,
uint16_t len,
bleproto_deviceinfo_rsp_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"hwv":"%s","swv":"%s","prototype":%u, "hbcycle":%u,"longcon":%u}
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
double v;
// hwv
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.hwv",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
snprintf(p->hwv, sizeof(p->hwv), "%s", value_str);
} else {
BLEPROTO_T_E("Error parse hwv");
return -1;
}
// swv
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.swv",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
snprintf(p->swv, sizeof(p->swv), "%s", value_str);
} else {
BLEPROTO_T_E("Error parse swv");
return -1;
}
// prototype
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.prototype",
/* result */ &v);
if (rc > 0) {
p->prototype = (uint8_t)v;
} else {
BLEPROTO_T_E("Error parse prototype");
return -1;
}
// hbcycle
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.hbcycle",
/* result */ &v);
if (rc > 0) {
p->hbcycle = (uint32_t)v;
} else {
BLEPROTO_T_E("Error parse hbcycle");
return -1;
}
// longcon
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.longcon",
/* result */ &v);
if (rc > 0) {
p->longcon = (uint8_t)v;
} else {
BLEPROTO_T_E("Error parse longcon");
return -1;
}
return (0);
}
int bleproto_decjson_authsetup_req(const uint8_t * data,
uint16_t len,
bleproto_authsetup_req_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"gwmac":"xxxx","devid":"xxxx","authcode":"xxxx"}
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
// gwmac
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.gwmac",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
int nr = proto_strhex_to_byte(value_str, p->gwmac, sizeof(p->gwmac));
if (nr != (int)sizeof(p->gwmac)) {
BLEPROTO_T_E("Error parse gwmac");
return -1;
}
} else {
BLEPROTO_T_E("Error parse gwmac");
return -1;
}
// devid
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.devid",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
snprintf(p->devid, sizeof(p->devid), "%s", value_str);
} else {
BLEPROTO_T_E("Error parse devid");
return -1;
}
// authcode
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.authcode",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
snprintf(p->authcode, sizeof(p->authcode), "%s", value_str);
} else {
BLEPROTO_T_E("Error parse authcode");
return -1;
}
return (0);
}
int bleproto_decjson_authsetup_rsp(const uint8_t * data,
uint16_t len,
bleproto_authsetup_rsp_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"errcode":xxx}
double v;
// errcode
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.errcode",
/* result */ &v);
if (rc > 0) {
p->errcode = (int32_t)v;
} else {
BLEPROTO_T_E("Error parse errcode");
return -1;
}
return (0);
}
int bleproto_decjson_authdelete_req(const uint8_t * data,
uint16_t len,
bleproto_authdelete_req_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"authcode": "xxxx"}
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
// authcode
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.authcode",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
snprintf(p->authcode, sizeof(p->authcode), "%s", value_str);
} else {
BLEPROTO_T_E("Error parse authcode");
return -1;
}
return (0);
}
int bleproto_decjson_authdelete_rsp(const uint8_t * data,
uint16_t len,
bleproto_authdelete_rsp_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"gwmac":"xxxx","errcode":xxx}
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
double v;
// gwmac
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.gwmac",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
int nr = proto_strhex_to_byte(value_str, p->gwmac, sizeof(p->gwmac));
if (nr != (int)sizeof(p->gwmac)) {
BLEPROTO_T_E("Error parse gwmac");
return -1;
}
} else {
BLEPROTO_T_E("Error parse gwmac");
return -1;
}
// errcode
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.errcode",
/* result */ &v);
if (rc > 0) {
p->errcode = (int32_t)v;
} else {
BLEPROTO_T_E("Error parse errcode");
return -1;
}
return (0);
}
int bleproto_decjson_runcmd_req(const uint8_t * data,
uint16_t len,
bleproto_runcmd_req_t *p)
{
int rc, i;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"cmd_id":xxxx,"arg_int32":[],"arg_string":[],"arg_bytes":"xxxx","t":"xxxxxxxx" }
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
double v;
// cmd_id
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.cmd_id",
/* v */ &v);
if (rc > 0) {
p->ycmd.cmd_id = (int)v;
} else {
BLEPROTO_T_E("Error parse cmd_id");
return -1;
}
// arg_int32
for (i = 0; i < YCMD_INT32_MAX_COUNT; i++) {
const char *ptr = NULL;
int n;
char key[sizeof("$.arg_int32[65535]") + 1] = { 0 };
snprintf(key, sizeof(key), "$.arg_int32[%d]", i);
if (mjson_find(str, (int)len, key, &ptr, &n) == MJSON_TOK_NUMBER) {
char vstr[32] = { 0 };
memcpy(vstr, ptr, UTILS_MIN(n, 31));
p->ycmd.arg_int32[p->ycmd.arg_int32_count] =
(int32_t)strtol(vstr, NULL, 10);
p->ycmd.arg_int32_count++;
}
}
// arg_string
for (i = 0; i < YCMD_STRING_MAX_COUNT; i++) {
const char *ptr = NULL;
int n;
char key[sizeof("$.arg_string[65535]") + 1] = { 0 };
snprintf(key, sizeof(key), "$.arg_string[%d]", i);
if (mjson_find(str, (int)len, key, &ptr, &n) == MJSON_TOK_STRING) {
if (n >= 2 && ptr[0] == '"' && ptr[n - 1] == '"') {
ptr++; // 跳过首引号
n -= 2; // 去掉首尾引号的长度
} else {
BLEPROTO_T_E("Error parse arg_string");
return -1;
}
memcpy(p->ycmd.arg_string[p->ycmd.arg_string_count],
ptr,
UTILS_MIN(n, YCMD_STRING_MAX_SIZE));
p->ycmd.arg_string_count++;
}
}
// arg_bytes
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.arg_bytes",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
// strhex to byte
rc = proto_strhex_to_byte(
value_str, p->ycmd.arg_bytes, sizeof(p->ycmd.arg_bytes));
if (rc >= 0) {
p->ycmd.arg_bytes_count = (uint16_t)rc;
}
}
// t
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.t",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
p->ycmd.t = (uint64_t)strtoull(value_str, NULL, 10);
} else {
BLEPROTO_T_E("Error parse t");
return -1;
}
return (0);
}
int bleproto_decjson_runcmd_rsp(const uint8_t * data,
uint16_t len,
bleproto_runcmd_rsp_t *p)
{
int rc, i;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"cmd_id":xxxx,"arg_int32":[],"arg_string":[],"arg_bytes":"xxxx","t":"xxxxxxxx" }
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
double v;
// cmd_id
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.cmd_id",
/* v */ &v);
if (rc > 0) {
p->ycmd.cmd_id = (int)v;
} else {
BLEPROTO_T_E("Error parse cmd_id");
return -1;
}
// arg_int32
for (i = 0; i < YCMD_INT32_MAX_COUNT; i++) {
const char *ptr = NULL;
int n;
char key[sizeof("$.arg_int32[65535]") + 1] = { 0 };
snprintf(key, sizeof(key), "$.arg_int32[%d]", i);
if (mjson_find(str, (int)len, key, &ptr, &n) == MJSON_TOK_NUMBER) {
char vstr[32] = { 0 };
memcpy(vstr, ptr, UTILS_MIN(n, 31));
p->ycmd.arg_int32[p->ycmd.arg_int32_count] =
(int32_t)strtol(vstr, NULL, 10);
p->ycmd.arg_int32_count++;
}
}
// arg_string
for (i = 0; i < YCMD_STRING_MAX_COUNT; i++) {
const char *ptr = NULL;
int n;
char key[sizeof("$.arg_string[65535]") + 1] = { 0 };
snprintf(key, sizeof(key), "$.arg_string[%d]", i);
if (mjson_find(str, (int)len, key, &ptr, &n) == MJSON_TOK_STRING) {
if (n >= 2 && ptr[0] == '"' && ptr[n - 1] == '"') {
ptr++; // 跳过首引号
n -= 2; // 去掉首尾引号的长度
} else {
BLEPROTO_T_E("Error parse arg_string");
return -1;
}
memcpy(p->ycmd.arg_string[p->ycmd.arg_string_count],
ptr,
UTILS_MIN(n, YCMD_STRING_MAX_SIZE));
p->ycmd.arg_string_count++;
}
}
// arg_bytes
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.arg_bytes",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
// strhex to byte
rc = proto_strhex_to_byte(
value_str, p->ycmd.arg_bytes, sizeof(p->ycmd.arg_bytes));
if (rc >= 0) {
p->ycmd.arg_bytes_count = (uint16_t)rc;
}
}
// t
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.t",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
p->ycmd.t = (uint64_t)strtoull(value_str, NULL, 10);
} else {
BLEPROTO_T_E("Error parse t");
return -1;
}
return (0);
}
int bleproto_decjson_reportcmd_req(const uint8_t * data,
uint16_t len,
bleproto_reportcmd_req_t *p)
{
int rc, i;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"cmd_id":xxxx,"arg_int32":[],"arg_string":[],"arg_bytes":"xxxx","t":"xxxxxxxx" }
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
double v;
// cmd_id
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.cmd_id",
/* v */ &v);
if (rc > 0) {
p->ycmd.cmd_id = (int)v;
} else {
BLEPROTO_T_E("Error parse cmd_id");
return -1;
}
// arg_int32
for (i = 0; i < YCMD_INT32_MAX_COUNT; i++) {
const char *ptr = NULL;
int n;
char key[sizeof("$.arg_int32[65535]") + 1] = { 0 };
snprintf(key, sizeof(key), "$.arg_int32[%d]", i);
if (mjson_find(str, (int)len, key, &ptr, &n) == MJSON_TOK_NUMBER) {
char vstr[32] = { 0 };
memcpy(vstr, ptr, UTILS_MIN(n, 31));
p->ycmd.arg_int32[p->ycmd.arg_int32_count] =
(int32_t)strtol(vstr, NULL, 10);
p->ycmd.arg_int32_count++;
}
}
// arg_string
for (i = 0; i < YCMD_STRING_MAX_COUNT; i++) {
const char *ptr = NULL;
int n;
char key[sizeof("$.arg_string[65535]") + 1] = { 0 };
snprintf(key, sizeof(key), "$.arg_string[%d]", i);
if (mjson_find(str, (int)len, key, &ptr, &n) == MJSON_TOK_STRING) {
if (n >= 2 && ptr[0] == '"' && ptr[n - 1] == '"') {
ptr++; // 跳过首引号
n -= 2; // 去掉首尾引号的长度
} else {
BLEPROTO_T_E("Error parse arg_string");
return -1;
}
memcpy(p->ycmd.arg_string[p->ycmd.arg_string_count],
ptr,
UTILS_MIN(n, YCMD_STRING_MAX_SIZE));
p->ycmd.arg_string_count++;
}
}
// arg_bytes
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.arg_bytes",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
// strhex to byte
rc = proto_strhex_to_byte(
value_str, p->ycmd.arg_bytes, sizeof(p->ycmd.arg_bytes));
if (rc >= 0) {
p->ycmd.arg_bytes_count = (uint16_t)rc;
}
}
// t
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.t",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
p->ycmd.t = (uint64_t)strtoull(value_str, NULL, 10);
} else {
BLEPROTO_T_E("Error parse t");
return -1;
}
return (0);
}
int bleproto_decjson_reportcmd_rsp(const uint8_t * data,
uint16_t len,
bleproto_reportcmd_rsp_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"errcode":xxx}
double v;
// errcode
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.errcode",
/* result */ &v);
if (rc > 0) {
p->errcode = (int32_t)v;
} else {
BLEPROTO_T_E("Error parse errcode");
return -1;
}
return (0);
}
int bleproto_decjson_doaction_req(const uint8_t * data,
uint16_t len,
bleproto_doaction_req_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"action":%d}
double v;
// action
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.action",
/* v */ &v);
if (rc > 0) {
p->action = (int)v;
} else {
BLEPROTO_T_E("Error parse action");
return -1;
}
return (0);
}
int bleproto_decjson_doaction_rsp(const uint8_t * data,
uint16_t len,
bleproto_doaction_rsp_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"errcode":xxx}
double v;
// errcode
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.errcode",
/* result */ &v);
if (rc > 0) {
p->errcode = (int32_t)v;
} else {
BLEPROTO_T_E("Error parse errcode");
return -1;
}
return (0);
}
int bleproto_decjson_otanotify_req(const uint8_t * data,
uint16_t len,
bleproto_otanotify_req_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"id": %d, "ver":"xxxx", "size":%d, "md5":"xxxxxxx"}
char value_str[BLEPROTO_APPDATA_DATA_MAX_SZ] = { 0 };
double v;
// id
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.id",
/* result */ &v);
if (rc > 0) {
p->id = (int)v;
} else {
BLEPROTO_T_E("Error parse errcode");
return -1;
}
// ver
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.ver",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
snprintf(p->version, sizeof(p->version), "%s", value_str);
} else {
BLEPROTO_T_E("Error parse version");
return -1;
}
// size
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.size",
/* result */ &v);
if (rc > 0) {
p->size = (uint32_t)v;
} else {
BLEPROTO_T_E("Error parse errcode");
return -1;
}
// md5
rc = mjson_get_string(
/* s */ str,
/* len */ (int)len,
/* path */ "$.md5",
/* to */ value_str,
/* n */ (int)sizeof(value_str));
if (rc > 0) {
snprintf(p->md5, sizeof(p->md5), "%s", value_str);
} else {
BLEPROTO_T_E("Error parse md5");
return -1;
}
return (0);
}
int bleproto_decjson_otanotify_rsp(const uint8_t * data,
uint16_t len,
bleproto_otanotify_rsp_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"errcode":xxx}
double v;
// errcode
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.errcode",
/* result */ &v);
if (rc > 0) {
p->errcode = (int32_t)v;
} else {
BLEPROTO_T_E("Error parse errcode");
return -1;
}
return (0);
}
int bleproto_decjson_otadata_req(const uint8_t * data,
uint16_t len,
bleproto_otadata_req_t *p)
{
int rc;
/* check param */
if (!data || len == 0 || !p) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
const char *str = (const char *)data;
/* dump input data */
BLEPROTO_T_D("data:%.*s", (int)len, str);
/* clear */
memset(p, 0, sizeof(*p));
// {"id": %d, "offset":%d, "maxsize":%d}
double v;
// id
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.id",
/* result */ &v);
if (rc > 0) {
p->id = (int)v;
} else {
BLEPROTO_T_E("Error parse errcode");
return -1;
}
// offset
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.offset",
/* result */ &v);
if (rc > 0) {
p->offset = (int32_t)v;
} else {
BLEPROTO_T_E("Error parse offset");
return -1;
}
// maxsize
rc = mjson_get_number(
/* s */ str,
/* len */ (int)len,
/* path */ "$.maxsize",
/* result */ &v);
if (rc > 0) {
p->maxsize = (uint32_t)v;
} else {
BLEPROTO_T_E("Error parse maxsize");
return -1;
}
return (0);
}
int bleproto_debin_otadata_rsp(const uint8_t * data,
uint16_t len,
bleproto_otadata_rsp_t *rsp)
{
int offset = 0;
/* check param */
if (!data || len == 0 || !rsp) {
BLEPROTO_T_E("Invalid parameters");
return -1;
}
/* check minimum buffer size (errcode + id + offset + len = 16 bytes) */
if (len < 16) {
BLEPROTO_T_E("Buffer too small");
return -1;
}
/* deserialize errcode (little-endian) */
rsp->errcode =
((int32_t)data[offset]) | ((int32_t)data[offset + 1] << 8) |
((int32_t)data[offset + 2] << 16) | ((int32_t)data[offset + 3] << 24);
offset += 4;
/* deserialize id (little-endian) */
rsp->id = ((uint32_t)data[offset]) | ((uint32_t)data[offset + 1] << 8) |
((uint32_t)data[offset + 2] << 16) |
((uint32_t)data[offset + 3] << 24);
offset += 4;
/* deserialize offset (little-endian) */
rsp->offset = ((uint32_t)data[offset]) |
((uint32_t)data[offset + 1] << 8) |
((uint32_t)data[offset + 2] << 16) |
((uint32_t)data[offset + 3] << 24);
offset += 4;
/* deserialize len (little-endian) */
rsp->len = ((uint32_t)data[offset]) | ((uint32_t)data[offset + 1] << 8) |
((uint32_t)data[offset + 2] << 16) |
((uint32_t)data[offset + 3] << 24);
offset += 4;
/* check data length validity */
if (rsp->len > BLEPROTO_APPDATA_OTADATA_SZ) {
BLEPROTO_T_E("Data length too large: %u", rsp->len);
return -1;
}
/* check remaining buffer size */
if (len < (offset + rsp->len)) {
BLEPROTO_T_E("Insufficient data for payload");
return -1;
}
/* 零拷贝:指向输入缓冲,调用方须在下次 decode 前用完 */
if (rsp->len > 0) {
rsp->data = &data[offset];
offset += rsp->len;
} else {
rsp->data = NULL;
}
return offset;
}
/****************************************************************************/
/* */
/* End of file. */
/* */
/****************************************************************************/