Files
kunlun/app/smart_grid/protocol/proto_spg.c

327 lines
9.7 KiB
C
Raw Permalink Normal View History

2024-09-28 14:24:04 +08:00
/****************************************************************************
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.
****************************************************************************/
/* common includes */
#include "iot_errno_api.h"
#include "iot_sg_fr.h"
/* protocol includes */
#include "proto_spg.h"
#include "iot_sg_ext_api.h"
#include "iot_cli_sg_api.h"
static const uint8_t spg_bcast_mac[IOT_MAC_ADDR_LEN] =
{ 0x99,0x99,0x99,0x99,0x99,0x99 };
uint8_t proto_spg_preamble[PROTO_SPG_PREAMBLE_LEN] =
{ 0xFE, 0xFE, 0xFE, 0xFE };
uint32_t proto_spg_get_proto_pkt_len(uint8_t mac_used, uint32_t data_len)
{
uint32_t tmp_len = 0;
/* IOT_SG_EXT_HEADROOM is additional uart data */
tmp_len = data_len + PROTO_SPG_FIX_FIELD_LEN +
sizeof(proto_spg_app_data_t);
if (mac_used) {
tmp_len += (PROTO_SPG_MAC_ADDR_LEN << 1);
}
return tmp_len;
}
uint32_t proto_spg_get_pkt_len(uint8_t mac_used, uint32_t data_len)
{
return max(IOT_SG_EXT_HEADROOM, IOT_SG_CLI_CHANNEL_HEADROOM) +
proto_spg_get_proto_pkt_len(mac_used, data_len);
}
uint32_t proto_spg_get_header_len(uint8_t mac_used)
{
uint32_t tmp_len = 0;
tmp_len = PROTO_SPG_DATA_OFFSET + sizeof(proto_spg_app_data_t);
if (mac_used) {
tmp_len += (PROTO_SPG_MAC_ADDR_LEN << 1);
}
return tmp_len;
}
uint32_t proto_spg_get_rsvd_len(uint8_t mac_used)
{
/* IOT_SG_EXT_HEADROOM is additional uart data */
return max(IOT_SG_EXT_HEADROOM, IOT_SG_CLI_CHANNEL_HEADROOM) +
proto_spg_get_header_len(mac_used);
}
uint8_t proto_spg_get_checksum(uint8_t *data, uint32_t len)
{
uint8_t result = 0;
for (uint32_t i = 0; i < len; ++i) {
result += data[i];
}
return result;
}
void proto_spg_nid_to_buf(uint32_t nid, uint8_t *p_nid)
{
p_nid[0] = (uint8_t)nid;
p_nid[1] = (uint8_t)(nid >> 8);
p_nid[2] = (uint8_t)(nid >> 16);
}
uint16_t proto_spg_fill_frame(uint8_t *frames_filled, uint8_t role, uint8_t afn,
uint8_t fn, uint8_t di2, uint8_t di3, uint8_t seq, uint8_t *app_data,
uint16_t data_len, uint8_t *mac_buf, uint8_t mac_cnt, uint8_t dir)
{
uint8_t *data = NULL;
uint16_t index = 0;
uint8_t *cs_ptr = NULL; //pointer to checksum
proto_spg_hdr_t *pkt_hdr = NULL;
proto_spg_app_data_t *spg_data = NULL;
data = frames_filled;
pkt_hdr = (proto_spg_hdr_t*)data;
pkt_hdr->sof_byte = PROTO_SPG_SOF_BYTE;
pkt_hdr->ctrl_byte.dir = dir;
pkt_hdr->ctrl_byte.prm = role;
pkt_hdr->ctrl_byte.ver = 0;
pkt_hdr->ctrl_byte.rsvd = 0;
index += sizeof(proto_spg_hdr_t);
if (mac_cnt) {
pkt_hdr->ctrl_byte.addr = 1;
/* only src mac and dest mac for up link */
os_mem_cpy(data + index, mac_buf, mac_cnt * PROTO_SPG_MAC_ADDR_LEN);
index += mac_cnt * PROTO_SPG_MAC_ADDR_LEN;
}
spg_data = (proto_spg_app_data_t *)(data + index);
/* set AFN */
spg_data->afn = afn;
/* set seq */
spg_data->seq = seq;
/* set DI */
spg_data->di[0] = fn;
spg_data->di[1] = afn;
spg_data->di[2] = di2;
spg_data->di[3] = di3;
index += sizeof(proto_spg_app_data_t);
/* skip app data as app data is already in iot_pkt */
if (data_len && app_data) {
os_mem_cpy(spg_data->data, app_data, data_len);
index += data_len;
}
cs_ptr = &data[index++]; /* set the checksum byte pointer */
data[index++] = PROTO_SPG_EOF_BYTE;
pkt_hdr->len = index;
*cs_ptr = proto_spg_get_checksum(data + PROTO_SPG_CTRL_OFFSET,
index - PROTO_SPG_PRECODE_LEN - PROTO_SPG_LENGTH_SIZE - \
PROTO_SPG_CHECKSUM_LEN - PROTO_SPG_BACKCODE_LEN);
return index;
}
iot_pkt_t *proto_spg_alloc_frame(uint8_t role, uint8_t afn, uint8_t fn,
uint8_t di2, uint8_t di3, uint8_t seq, uint8_t *app_data, uint16_t len,
uint8_t *mac_buf, uint8_t mac_cnt, uint8_t dir)
{
iot_pkt_t *pkt;
uint16_t pkt_len;
pkt = iot_pkt_alloc(proto_spg_get_pkt_len(mac_cnt, len),
IOT_SMART_GRID_MID);
if (pkt == NULL) {
goto out;
}
pkt_len = proto_spg_fill_frame(iot_pkt_data(pkt), role, afn, fn, di2, di3,
seq, app_data, len, mac_buf, mac_cnt, dir);
iot_pkt_put(pkt, pkt_len);
out:
return pkt;
}
uint8_t *proto_spg_sanity_check(uint8_t *data, uint16_t len,
uint8_t *reason, uint8_t di3)
{
uint16_t len_t = len, i, frame_len, min_data_len = PROTO_SPG_FIX_FIELD_LEN;
uint8_t *data_s = data;
proto_spg_hdr_t *proto_hdr;
proto_spg_app_data_t* app_data;
again:
len = len_t;
for (i = 0x0; i < len; i++) {
if (data_s[i] == PROTO_SPG_SOF_BYTE) {
data_s += i;
len_t -= i;
break;
}
}
if (i == len) {
goto drop;
}
if (len_t <= min_data_len) {
goto drop;
}
frame_len = (uint16_t)data_s[2] << 8 | (uint16_t)data_s[1];
if (frame_len > len_t) {
data_s++;
len_t--;
goto again;
}
if ((data_s[0] != PROTO_SPG_SOF_BYTE)
|| (data_s[frame_len - 1] != PROTO_SPG_EOF_BYTE)) {
data_s++;
len_t--;
goto again;
}
proto_hdr = (proto_spg_hdr_t *)data_s;
if (proto_hdr->ctrl_byte.addr) {
if (len_t < (PROTO_SPG_PKT_OVERHEAD +
(PROTO_SPG_MAC_ADDR_LEN * 2))) {
goto drop;
}
app_data = (proto_spg_app_data_t*)(data_s + sizeof(proto_spg_hdr_t)
+ sizeof(proto_spg_addr_field_t));
} else {
app_data = (proto_spg_app_data_t*)(data_s + sizeof(proto_spg_hdr_t));
}
if (di3 != app_data->di[3]) {
data_s++;
len_t--;
goto again;
}
if (data_s[frame_len - 2] != proto_spg_get_checksum(
data_s + PROTO_SPG_CTRL_OFFSET,
frame_len - PROTO_SPG_FIX_FIELD_LEN + 1)) {
data_s++;
len_t--;
goto again;
}
goto out;
drop:
*reason = PROTO_SPG_ERR_INVALID_DATA;
data_s = NULL;
out:
return data_s;
}
void proto_spg_check_frame_handler(uint8_t* buffer, uint32_t buffer_len,
bool_t* is_frame)
{
uint16_t frame_len = 0;
proto_spg_hdr_t *proto_hdr;
proto_spg_app_data_t* app_data;
do {
if (buffer_len < PROTO_SPG_PKT_OVERHEAD) {
*is_frame = false;
break;
}
frame_len = (uint16_t)buffer[2];
frame_len = (frame_len << 8) | (uint16_t)buffer[1];
if (buffer[0] != PROTO_SPG_SOF_BYTE
|| buffer[buffer_len - 1] != PROTO_SPG_EOF_BYTE) {
*is_frame = false;
break;
}
if (frame_len != buffer_len) {
*is_frame = false;
break;
}
proto_hdr = (proto_spg_hdr_t*)buffer;
if (proto_hdr->ctrl_byte.addr) {
if (buffer_len < (PROTO_SPG_PKT_OVERHEAD +
(PROTO_SPG_MAC_ADDR_LEN * 2))) {
*is_frame = false;
break;
}
app_data = (proto_spg_app_data_t*)(buffer + sizeof(proto_spg_hdr_t)
+ sizeof(proto_spg_addr_field_t));
} else {
app_data = (proto_spg_app_data_t*)(buffer + sizeof(proto_spg_hdr_t));
}
#if PLC_SUPPORT_CCO_ROLE
if (app_data->di[3] != 0xE8) {
*is_frame = false;
break;
}
#elif (IOT_SG_CONTROLLER_ENABLE && (IOT_STA_CONTROL_MODE == 0))
if (app_data->di[3] != 0xE5) {
*is_frame = false;
break;
}
#else
if (app_data->di[3] != 0xEA) {
*is_frame = false;
break;
}
#endif /* PLC_SUPPORT_CCO_ROLE */
if (buffer[buffer_len - 2] != proto_spg_get_checksum(
buffer + PROTO_SPG_CTRL_OFFSET,
buffer_len - PROTO_SPG_FIX_FIELD_LEN + 1)) {
/* checksum failure */
*is_frame = false;
break;
}
*is_frame = true;
} while(0);
}
uint8_t proto_spg_is_bcast(uint8_t* dst)
{
return iot_mac_addr_cmp(dst, spg_bcast_mac);
}
void proto_spg_set_bcast(uint8_t *dst)
{
iot_mac_addr_cpy(dst, (uint8_t*)spg_bcast_mac);
}
static uint32_t proto_spg_get_block_cnt(uint32_t file_size,
uint16_t block_size)
{
return (0 == block_size) ? 0 : ((file_size + block_size - 1) / block_size);
}
uint32_t proto_spg_get_block_size(uint32_t file_size, uint16_t block_cnt)
{
uint32_t cnt = 0;
cnt = proto_spg_get_block_cnt(file_size, PROTO_SPG_UPGRADE_FILE_SEG_SIZE1);
if (block_cnt == (uint16_t)cnt) {
return PROTO_SPG_UPGRADE_FILE_SEG_SIZE1;
}
cnt = proto_spg_get_block_cnt(file_size, PROTO_SPG_UPGRADE_FILE_SEG_SIZE2);
if (block_cnt == (uint16_t)cnt) {
return PROTO_SPG_UPGRADE_FILE_SEG_SIZE2;
}
cnt = proto_spg_get_block_cnt(file_size, PROTO_SPG_UPGRADE_FILE_SEG_SIZE3);
if (block_cnt == (uint16_t)cnt) {
return PROTO_SPG_UPGRADE_FILE_SEG_SIZE3;
}
cnt = proto_spg_get_block_cnt(file_size, PROTO_SPG_UPGRADE_FILE_SEG_SIZE4);
if (block_cnt == (uint16_t)cnt) {
return PROTO_SPG_UPGRADE_FILE_SEG_SIZE4;
}
cnt = proto_spg_get_block_cnt(file_size, PROTO_SPG_UPGRADE_FILE_SEG_SIZE5);
if (block_cnt == (uint16_t)cnt) {
return PROTO_SPG_UPGRADE_FILE_SEG_SIZE5;
}
return 0;
}