Files
BLE-USB_Dongle/apps/usr_le_code/bleproto_packer.c
T

3000 lines
87 KiB
C

/****************************************************************************/
/* 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_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 data */
if (p->len > 0 && p->len <= BLEPROTO_APPDATA_OTADATA_SZ) {
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;
}
/* deserialize data */
if (rsp->len > 0) {
memcpy(rsp->data, &data[offset], rsp->len);
offset += rsp->len;
}
return offset;
}
/****************************************************************************/
/* */
/* End of file. */
/* */
/****************************************************************************/