3093 lines
90 KiB
C
3093 lines
90 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_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) {
|
||
printf("Invalid parameters");
|
||
return -1;
|
||
}
|
||
if (payload_len > 0 && !payload) {
|
||
printf("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) {
|
||
printf("payload too long, frames %u>255\n", (unsigned)totalframe);
|
||
return -1;
|
||
}
|
||
|
||
need = (uint16_t)((uint16_t)totalframe * BLEPROTO_APPDATA_HEADR_LEN + payload_len);
|
||
if (txbuf_size < need) {
|
||
printf("txbuf too short %u<%u\n", (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) {
|
||
printf("wrap_raw split %uB -> %u frames, out %uB\n",
|
||
(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 data(data 为外部指针,不再内嵌数组) */
|
||
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. */
|
||
/* */
|
||
/****************************************************************************/
|