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