429 lines
12 KiB
C
429 lines
12 KiB
C
/****************************************************************************
|
|
|
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
|
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
be copied by any method or incorporated into another program without
|
|
the express written consent of Aerospace C.Power. This Information or any portion
|
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
liability for its use in any way and conveys no license or title under
|
|
any patent or copyright and makes no representation or warranty that this
|
|
Information is free from patent or copyright infringement.
|
|
|
|
****************************************************************************/
|
|
|
|
/* os shim includes */
|
|
#include "os_types_api.h"
|
|
#include "os_mem_api.h"
|
|
|
|
/* common includes */
|
|
#include "iot_utils_api.h"
|
|
#include "iot_errno_api.h"
|
|
|
|
/* smart grid internal includes */
|
|
#include "proto_crc16.h"
|
|
#include "proto_qsxj.h"
|
|
|
|
proto_qsxj_head_t *proto_qsxj_sanity_check(uint8_t* data,
|
|
uint16_t len)
|
|
{
|
|
uint16_t len_t = len, i = 0x0, frame_len, data_len;
|
|
uint8_t *data_s = data;
|
|
uint16_t min_data_len = sizeof(proto_qsxj_head_t) +
|
|
sizeof(proto_qsxj_tailer_t);
|
|
proto_qsxj_head_t* head;
|
|
|
|
again:
|
|
len = len_t;
|
|
for (i = 0x0; i < len; i++) {
|
|
if (data_s[i] == PROTO_QSXJ_START_CHAR) {
|
|
data_s += i;
|
|
len_t -= i;
|
|
break;
|
|
}
|
|
}
|
|
if (i == len) {
|
|
goto drop;
|
|
}
|
|
if (len_t < min_data_len) {
|
|
goto drop;
|
|
}
|
|
head = (proto_qsxj_head_t*)data_s;
|
|
data_len = proto_qsxj_len_get(head);
|
|
if (data_len < PROTO_QSXJ_COMMAND_LEN + PROTO_QSXJ_CRC16_LEN) {
|
|
data_s++;
|
|
len_t--;
|
|
goto again;
|
|
}
|
|
frame_len = data_len + PROTO_QSXJ_START_CHAR_LEN +
|
|
PROTO_QSXJ_LEN_STRUCTURE_LEN;
|
|
if (len_t < frame_len) {
|
|
data_s++;
|
|
len_t--;
|
|
goto again;
|
|
}
|
|
/* frame crc16 check */
|
|
if (proto_fcs16_check(data_s + 1,
|
|
(frame_len - PROTO_QSXJ_START_CHAR_LEN))) {
|
|
data_s++;
|
|
len_t--;
|
|
goto again;
|
|
}
|
|
goto out;
|
|
drop:
|
|
data_s = NULL;
|
|
out:
|
|
return (proto_qsxj_head_t *)data_s;
|
|
}
|
|
|
|
proto_qsxj_head_t *proto_qsxj_frame_find(uint8_t *data,
|
|
uint16_t len)
|
|
{
|
|
uint16_t len_t = len, i, frame_len, data_len;
|
|
uint8_t *data_s = data;
|
|
uint16_t min_data_len = sizeof(proto_qsxj_head_t) +
|
|
sizeof(proto_qsxj_tailer_t);
|
|
proto_qsxj_head_t* head;
|
|
|
|
again:
|
|
len = len_t;
|
|
for (i = 0x0; i < len; i++) {
|
|
if (data_s[i] == PROTO_QSXJ_START_CHAR) {
|
|
data_s += i;
|
|
len_t -= i;
|
|
break;
|
|
}
|
|
}
|
|
if (i == len) {
|
|
goto drop;
|
|
}
|
|
if (len_t < min_data_len) {
|
|
goto drop;
|
|
}
|
|
head = (proto_qsxj_head_t*)data_s;
|
|
data_len = proto_qsxj_len_get(head);
|
|
if (data_len < PROTO_QSXJ_COMMAND_LEN + PROTO_QSXJ_CRC16_LEN) {
|
|
data_s++;
|
|
len_t--;
|
|
goto again;
|
|
}
|
|
frame_len = data_len + PROTO_QSXJ_START_CHAR_LEN +
|
|
PROTO_QSXJ_LEN_STRUCTURE_LEN;
|
|
if (len_t < frame_len) {
|
|
data_s++;
|
|
len_t--;
|
|
goto again;
|
|
}
|
|
|
|
/* frame crc16 check */
|
|
if (proto_fcs16_check(data_s + 1,
|
|
(frame_len - PROTO_QSXJ_START_CHAR_LEN))) {
|
|
data_s++;
|
|
len_t--;
|
|
goto again;
|
|
}
|
|
goto out;
|
|
drop:
|
|
data_s = NULL;
|
|
out:
|
|
return (proto_qsxj_head_t*)data_s;
|
|
}
|
|
|
|
void proto_qsxj_check_frame_handler(uint8_t* buffer, uint32_t buffer_len,
|
|
bool_t* is_frame)
|
|
{
|
|
proto_qsxj_head_t *head;
|
|
uint16_t min_data_len = sizeof(proto_qsxj_head_t) +
|
|
sizeof(proto_qsxj_tailer_t);
|
|
uint16_t frame_len, data_len;
|
|
|
|
do {
|
|
if (buffer_len < min_data_len) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
head = (proto_qsxj_head_t *)buffer;
|
|
if (head->start_char != PROTO_QSXJ_START_CHAR) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
data_len = proto_qsxj_len_get(head);
|
|
if (data_len < PROTO_QSXJ_COMMAND_LEN + PROTO_QSXJ_CRC16_LEN) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
frame_len = data_len + PROTO_QSXJ_START_CHAR_LEN +
|
|
PROTO_QSXJ_LEN_STRUCTURE_LEN;
|
|
if (buffer_len != frame_len) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
if (proto_fcs16_check(buffer + 1,
|
|
(frame_len - PROTO_QSXJ_START_CHAR_LEN))) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
*is_frame = true;
|
|
} while(0);
|
|
}
|
|
|
|
iot_pkt_t *proto_qsxj_build_msg(uint8_t *data, uint16_t data_len,
|
|
uint8_t command, uint8_t ver, uint8_t flag_follow, uint8_t channel)
|
|
{
|
|
uint8_t *cache_ptr;
|
|
uint16_t total_len, len, fcs_len, fcs;
|
|
iot_pkt_t *pkt = NULL;
|
|
proto_qsxj_head_t *head;
|
|
proto_qsxj_tailer_t *tail;
|
|
|
|
total_len = sizeof(*head) + data_len + sizeof(*tail);
|
|
pkt = iot_pkt_alloc(total_len, IOT_SMART_GRID_MID);
|
|
if (!pkt) {
|
|
goto out;
|
|
}
|
|
cache_ptr = iot_pkt_put(pkt, total_len);
|
|
head = (proto_qsxj_head_t *)cache_ptr;
|
|
head->start_char = PROTO_QSXJ_START_CHAR;
|
|
len = sizeof(head->command) + data_len + sizeof(*tail);
|
|
proto_qsxj_len_fill(head, len);
|
|
head->ver = ver;
|
|
head->flag_follow = flag_follow;
|
|
head->channel_num = channel;
|
|
head->command = command;
|
|
if (data && data_len) {
|
|
os_mem_cpy(head->data, data, data_len);
|
|
}
|
|
fcs_len = total_len - sizeof(head->start_char) - sizeof(*tail);
|
|
fcs = proto_fcs16_get_check_sum(cache_ptr +
|
|
PROTO_QSXJ_START_CHAR_LEN, fcs_len);
|
|
tail = (proto_qsxj_tailer_t *)(head->data + data_len);
|
|
tail->crc[1] = (uint8_t)(fcs >> 8);
|
|
tail->crc[0] = (uint8_t)fcs;
|
|
out:
|
|
return pkt;
|
|
}
|
|
|
|
iot_pkt_t *proto_qsxj_build_get_meter_info(uint8_t ver, uint8_t flag_follow)
|
|
{
|
|
return proto_qsxj_build_msg(NULL, 0, PROTO_QSXJ_COMMAND_CONF_REQ, ver,
|
|
flag_follow, PROTO_QSXJ_CHANNEL_NUM0);
|
|
}
|
|
|
|
iot_pkt_t *proto_qsxj_build_heartbeat_msg(uint8_t ver,
|
|
uint8_t state, uint8_t *cco_addr, int8_t snr)
|
|
{
|
|
uint8_t data[PROTO_QSXJ_HEARTBEAT_DATA_LEN_MAX] = {0}, len = 0;
|
|
uint16_t di;
|
|
proto_qsxj_fixed_data_t *fixed_hb;
|
|
proto_qsxj_data_t *hb;
|
|
|
|
if (ver == PROTO_QSXJ_VER_SX_V04) {
|
|
di = PROTO_QSXJ_DI_MODULE_STATE;
|
|
fixed_hb = (proto_qsxj_fixed_data_t*)data;
|
|
proto_qsxj_di_to_byte(di, fixed_hb->di);
|
|
fixed_hb->data[0] = state;
|
|
len += (sizeof(*fixed_hb) + 1);
|
|
if (cco_addr) {
|
|
di = PROTO_QSXJ_DI_CCO_MAC;
|
|
fixed_hb = (proto_qsxj_fixed_data_t*)&data[len];
|
|
proto_qsxj_di_to_byte(di, fixed_hb->di);
|
|
iot_mac_addr_cpy(fixed_hb->data, cco_addr);
|
|
len += (sizeof(*fixed_hb) + IOT_MAC_ADDR_LEN);
|
|
di = PROTO_QSXJ_DI_SNR;
|
|
fixed_hb = (proto_qsxj_fixed_data_t*)&data[len];
|
|
proto_qsxj_di_to_byte(di, fixed_hb->di);
|
|
fixed_hb->data[0] = (uint8_t)snr;
|
|
len += (sizeof(*fixed_hb) + 1);
|
|
}
|
|
} else {
|
|
di = PROTO_QSXJ_DI_MODULE_STATE;
|
|
hb = (proto_qsxj_data_t*)data;
|
|
proto_qsxj_di_to_byte(di, hb->di);
|
|
hb->len = 1;
|
|
hb->data[0] = state;
|
|
len += (sizeof(*hb) + 1);
|
|
if (cco_addr) {
|
|
di = PROTO_QSXJ_DI_CCO_MAC;
|
|
hb = (proto_qsxj_data_t*)&data[len];
|
|
proto_qsxj_di_to_byte(di, hb->di);
|
|
hb->len = IOT_MAC_ADDR_LEN;
|
|
iot_mac_addr_cpy(hb->data, cco_addr);
|
|
len += (sizeof(*hb) + IOT_MAC_ADDR_LEN);
|
|
di = PROTO_QSXJ_DI_SNR;
|
|
hb = (proto_qsxj_data_t*)&data[len];
|
|
proto_qsxj_di_to_byte(di, hb->di);
|
|
hb->len = 1;
|
|
hb->data[0] = (uint8_t)snr;
|
|
len += (sizeof(*hb) + 1);
|
|
}
|
|
}
|
|
return proto_qsxj_build_msg(data, len, PROTO_QSXJ_COMMAND_SET_REQ, ver, 0,
|
|
PROTO_QSXJ_CHANNEL_NUM0);
|
|
}
|
|
|
|
iot_pkt_t *proto_qsxj_build_trans_msg(uint8_t ver,
|
|
uint8_t *data, uint16_t data_len)
|
|
{
|
|
return proto_qsxj_build_msg(data, data_len, PROTO_QSXJ_COMMAND_TRANS_REQ,
|
|
ver, 0, PROTO_QSXJ_CHANNEL_NUM0);
|
|
}
|
|
|
|
iot_pkt_t *proto_qsxj_build_broadcast_msg(uint8_t ver,
|
|
uint8_t *data, uint16_t data_len)
|
|
{
|
|
return proto_qsxj_build_msg(data, data_len, PROTO_QSXJ_COMMAND_BROADCAST,
|
|
ver, 0, PROTO_QSXJ_CHANNEL_NUM0);
|
|
}
|
|
|
|
iot_pkt_t *proto_qsxj_build_upgrade_msg(uint8_t ver,
|
|
uint8_t *data, uint16_t data_len)
|
|
{
|
|
return proto_qsxj_build_msg(data, data_len,
|
|
PROTO_QSXJ_COMMAND_GET_UPDATA_REQ, ver, 0, PROTO_QSXJ_CHANNEL_NUM0);
|
|
}
|
|
|
|
iot_pkt_t *proto_qsxj_build_ack(uint8_t ver, uint8_t command,
|
|
uint8_t flag_nack)
|
|
{
|
|
uint8_t data[PROTO_QSXJ_DI_LEN];
|
|
uint16_t di = PROTO_QSXJ_DI_SUCCESS;
|
|
|
|
if (flag_nack) {
|
|
di = PROTO_QSXJ_DI_FAILED;
|
|
}
|
|
proto_qsxj_di_to_byte(di, data);
|
|
return proto_qsxj_build_msg(data, PROTO_QSXJ_DI_LEN, command,
|
|
ver, 0, PROTO_QSXJ_CHANNEL_NUM0);
|
|
}
|
|
|
|
uint32_t proto_qsxj_di_data_len_get(uint16_t di, uint8_t *data_len,
|
|
uint8_t *fixed)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
|
|
if (!fixed || !data_len) {
|
|
ret = ERR_INVAL;
|
|
goto out;
|
|
}
|
|
*fixed = 1;
|
|
switch (di) {
|
|
case PROTO_QSXJ_DI_SUCCESS:
|
|
case PROTO_QSXJ_DI_FAILED:
|
|
{
|
|
*data_len = 0;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_MODULE_TYPE:
|
|
{
|
|
*data_len = sizeof(proto_qsxj_mode_type_t);
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_VENDOR_TYPE:
|
|
{
|
|
*data_len = sizeof(proto_qsxj_vendor_type_t);
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_MODULE_STATE:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_MODULE_STATE_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_BUFFER_LEN:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_BUFFER_LEN_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_PROTO_VER:
|
|
{
|
|
*data_len = sizeof(proto_qsxj_proto_ver_t);
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_CLOSE_TIME:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_CLOSE_TIME_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_RPT_TIMEOUT:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_RPT_TIMEOUT_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_CCO_MAC:
|
|
{
|
|
*data_len = IOT_MAC_ADDR_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_SNR:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_SNR_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_MI_PSK:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_MI_PSK_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_BLACKLIST_TIME:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_BL_TIME_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_MI_PSK_ID:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_MI_PSK_ID_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_FUTURE_MI_PSK_ID:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_FMI_PSK_ID_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_FUTURE_MI_PSK:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_FMI_PSK_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_FUTURE_MI_PSK_TIME:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_FMI_PSK_TIME_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_PWR_DOWN_RPT_RAND:
|
|
{
|
|
*data_len = PROTO_QSXJ_DI_PWR_DOWN_RPT_RAND_DATA_LEN;
|
|
*fixed = 1;
|
|
break;
|
|
}
|
|
case PROTO_QSXJ_DI_HARDWARE_VER:
|
|
case PROTO_QSXJ_DI_SOFTWARE_VER:
|
|
case PROTO_QSXJ_DI_METER_NUM:
|
|
case PROTO_QSXJ_DI_MODULE_ID:
|
|
{
|
|
*data_len = 0;
|
|
*fixed = 0;
|
|
break;
|
|
}
|
|
default:
|
|
ret = ERR_INVAL;
|
|
break;
|
|
}
|
|
out:
|
|
return ret;
|
|
} |