Files
kunlun/app/smart_grid/protocol/proto_qsxj.c
2024-09-28 14:24:04 +08:00

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;
}