308 lines
9.7 KiB
C
308 lines
9.7 KiB
C
/****************************************************************************
|
|
|
|
Copyright(c) 2024 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 ship includes */
|
|
#include "os_mem_api.h"
|
|
|
|
/* common includes */
|
|
#include "iot_config_api.h"
|
|
#include "iot_errno_api.h"
|
|
#include "iot_ntoh_api.h"
|
|
|
|
/* protocol includes */
|
|
#include "proto_crc16.h"
|
|
#include "proto_hx_dlms.h"
|
|
|
|
/* smart grid internal header files */
|
|
#include "iot_sg_fr.h"
|
|
|
|
proto_hx_dlms_head_t *proto_hx_dlms_check(uint8_t* data,
|
|
uint16_t len)
|
|
{
|
|
uint16_t len_t, i;
|
|
uint16_t total_len;
|
|
uint8_t *data_s = NULL;
|
|
uint16_t min_data_len;
|
|
proto_hx_dlms_head_t *head;
|
|
|
|
for (i = 0x0, len_t = len; i < len; i++) {
|
|
if (data[i] == PROTO_HX_DLMS_START_BYTE) {
|
|
data_s = data + i;
|
|
break;
|
|
}
|
|
len_t--;
|
|
}
|
|
min_data_len = sizeof(proto_hx_dlms_head_t)
|
|
+ sizeof(proto_hx_dlms_tail_t);
|
|
if (len_t <= min_data_len || data_s == NULL) {
|
|
goto drop;
|
|
}
|
|
head = (proto_hx_dlms_head_t*)data_s;
|
|
total_len = head->len_h;
|
|
total_len = (total_len << 8) + head->len_l + PROTO_HX_DLMS_START_END_LEN;
|
|
if (len_t < total_len) {
|
|
goto drop;
|
|
}
|
|
/* start and end byte check */
|
|
if (data_s[0] != PROTO_HX_DLMS_START_BYTE
|
|
|| data_s[total_len - 1] != PROTO_HX_DLMS_END_BYTE) {
|
|
goto drop;
|
|
}
|
|
/* dlms frame fcs check */
|
|
if (proto_fcs16_check(data_s + 1, (total_len - PROTO_HX_DLMS_START_END_LEN))) {
|
|
goto drop;
|
|
}
|
|
goto out;
|
|
drop:
|
|
head = NULL;
|
|
out:
|
|
return head;
|
|
}
|
|
|
|
void proto_hx_dlms_check_frame_handler(uint8_t* buffer,
|
|
uint32_t buffer_len, bool_t* is_frame)
|
|
{
|
|
uint16_t d_len;
|
|
proto_hx_dlms_head_t *head;
|
|
|
|
do {
|
|
if (buffer_len < sizeof(proto_hx_dlms_head_t)) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
head = (proto_hx_dlms_head_t*)buffer;
|
|
if (head->start_char != PROTO_HX_DLMS_START_BYTE) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
d_len = head->len_h;
|
|
d_len = (d_len << 8) + head->len_l + PROTO_HX_DLMS_START_END_LEN;
|
|
if (buffer_len != d_len) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
if (proto_fcs16_check(buffer + 1,
|
|
(d_len - PROTO_HX_DLMS_START_END_LEN))) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
if (buffer[d_len - 1] != PROTO_HX_DLMS_END_BYTE) {
|
|
*is_frame = false;
|
|
break;
|
|
}
|
|
*is_frame = true;
|
|
} while(0);
|
|
}
|
|
|
|
iot_pkt_t *proto_hx_dlms_msg_build(const uint8_t *data, uint16_t len,
|
|
uint8_t frame_type, uint8_t dst_addr, uint8_t src_addr, uint8_t serial_id,
|
|
uint8_t seq)
|
|
{
|
|
uint8_t *data_tmp;
|
|
uint16_t fcs, cache_len;
|
|
uint32_t total_len;
|
|
iot_pkt_t *pkt;
|
|
proto_hx_dlms_head_t *head;
|
|
proto_hx_dlms_tail_t *tail;
|
|
|
|
total_len = sizeof(*head) + len + sizeof(*tail);
|
|
pkt = iot_pkt_alloc(total_len, IOT_SMART_GRID_MID);
|
|
if (!pkt)
|
|
return NULL;
|
|
data_tmp = iot_pkt_put(pkt, total_len);
|
|
head = (proto_hx_dlms_head_t*)data_tmp;
|
|
head->start_char = PROTO_HX_DLMS_START_BYTE;
|
|
head->frame_type = frame_type;
|
|
cache_len = (uint16_t)(total_len - PROTO_HX_DLMS_START_END_LEN);
|
|
head->len_l = (uint8_t)cache_len;
|
|
head->len_h = (uint8_t)(cache_len >> 8);
|
|
head->seq.bit.serial_id = serial_id;
|
|
head->seq.bit.frame_seq = seq;
|
|
head->dst_addr = dst_addr;
|
|
head->src_addr = src_addr;
|
|
os_mem_cpy(head->data, data, len);
|
|
tail = (proto_hx_dlms_tail_t*)(data_tmp + sizeof(*head) + len);
|
|
cache_len = (uint16_t)(total_len - PROTO_HX_DLMS_START_END_LEN
|
|
- PROTO_HX_DLMS_FCS_LEN);
|
|
fcs = proto_fcs16_get_check_sum(data_tmp + 1, cache_len);
|
|
tail->fcs[0] = (uint8_t)fcs;
|
|
tail->fcs[1] = (uint8_t)(fcs >> 8);
|
|
tail->end_char = PROTO_HX_DLMS_END_BYTE;
|
|
return pkt;
|
|
}
|
|
|
|
iot_pkt_t *proto_hx_dlms_change_app_to_meter(
|
|
proto_hx_dlms_app_hdr_t *head, uint16_t len, uint8_t serial_id, uint8_t seq)
|
|
{
|
|
uint8_t dst_addr, src_addr;
|
|
uint16_t len_t;
|
|
iot_pkt_t *pkt = NULL;
|
|
|
|
if (len <= sizeof(*head)) {
|
|
goto out;
|
|
}
|
|
len_t = iot_bytes_to_uint16((uint8_t*)&head->len, 1);
|
|
if (len < (len_t + sizeof(*head))) {
|
|
goto out;
|
|
}
|
|
dst_addr = (uint8_t)iot_bytes_to_uint16((uint8_t*)&head->dst_addr, 1);
|
|
src_addr = (uint8_t)iot_bytes_to_uint16((uint8_t*)&head->src_addr, 1);
|
|
pkt = proto_hx_dlms_msg_build(head->data, len_t,
|
|
PROTO_HX_DLMS_FRAME_TRANS_REQ, dst_addr, src_addr, serial_id, seq);
|
|
out:
|
|
return pkt;
|
|
}
|
|
|
|
iot_pkt_t *proto_hx_dlms_change_meter_to_app(
|
|
proto_hx_dlms_head_t *head)
|
|
{
|
|
uint16_t total_len, apdu_len;
|
|
iot_pkt_t *pkt = NULL;
|
|
proto_hx_dlms_app_hdr_t *app_hdr;
|
|
|
|
apdu_len = head->len_h;
|
|
apdu_len = (apdu_len << 8) + head->len_l + PROTO_HX_DLMS_START_END_LEN;
|
|
apdu_len = apdu_len - sizeof(*head) - sizeof(proto_hx_dlms_tail_t);
|
|
total_len = apdu_len + sizeof(*app_hdr);
|
|
pkt = iot_pkt_alloc(total_len, IOT_SMART_GRID_MID);
|
|
if (!pkt) {
|
|
goto out;
|
|
}
|
|
app_hdr = (proto_hx_dlms_app_hdr_t*)iot_pkt_put(pkt, total_len);
|
|
iot_uint16_to_bytes(1, (uint8_t*)&app_hdr->ver, 1);
|
|
iot_uint16_to_bytes(head->dst_addr, (uint8_t*)&app_hdr->dst_addr, 1);
|
|
iot_uint16_to_bytes(head->src_addr, (uint8_t*)&app_hdr->src_addr, 1);
|
|
iot_uint16_to_bytes(apdu_len, (uint8_t*)&app_hdr->len, 1);
|
|
os_mem_cpy(app_hdr->data, head->data, apdu_len);
|
|
out:
|
|
return pkt;
|
|
}
|
|
|
|
static uint32_t proto_hx_dlms_get_str_len(uint8_t *data, uint8_t *len_width)
|
|
{
|
|
uint8_t size, i;
|
|
uint32_t length = 0;
|
|
*len_width = 1;
|
|
if (data[0] < 0x80) {
|
|
length = data[0] & 0x7F;
|
|
} else {
|
|
size = data[0] & 0x0F;
|
|
if (size > PROTO_HX_DLMS_EVENT_STR_LEN_NUM_MAX) {
|
|
return 0;
|
|
}
|
|
for (i = 0; i < size; i++) {
|
|
length <<= 8;
|
|
length += data[i + 1];
|
|
}
|
|
*len_width += size;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
iot_pkt_t *proto_hx_dlms_change_evt_to_app(uint8_t *data, uint16_t len)
|
|
{
|
|
iot_pkt_t *pkt = NULL;
|
|
proto_hx_dlms_data_t *event_info = NULL;
|
|
proto_hx_dlms_data_fix_t *channel_info = NULL, *push_service_info = NULL,
|
|
*push_client_info = NULL;
|
|
proto_hx_dlms_data_t *destination_info = NULL, *event_data_info = NULL;
|
|
uint32_t event_data_len = 0, pkt_len = 0, length = len;
|
|
uint8_t len_width = 0, *event_data = NULL, push_client = 0;
|
|
proto_hx_dlms_app_hdr_t *app_hdr;
|
|
|
|
IOT_ASSERT(data);
|
|
if (length < sizeof(*event_info)) {
|
|
goto out;
|
|
}
|
|
event_info = (proto_hx_dlms_data_t *)data;
|
|
if (event_info->type != PROTO_HX_DLMS_DATA_TYPE_STRUCTURE ||
|
|
event_info->num != PROTO_HX_DLMS_EVENT_DATA_STRUCT_NUM) {
|
|
goto out;
|
|
}
|
|
length -= sizeof(*event_info);
|
|
if (length < sizeof(*channel_info)) {
|
|
goto out;
|
|
}
|
|
channel_info = (proto_hx_dlms_data_fix_t *)event_info->con;
|
|
if (channel_info->type != PROTO_HX_DLMS_DATA_TYPE_ENUM) {
|
|
goto out;
|
|
}
|
|
length -= (sizeof(*channel_info) + 1);
|
|
if (length < sizeof(*destination_info)) {
|
|
goto out;
|
|
}
|
|
destination_info = (proto_hx_dlms_data_t *)(channel_info->data + 1);
|
|
if (destination_info->type != PROTO_HX_DLMS_DATA_TYPE_OCTET_STR) {
|
|
goto out;
|
|
}
|
|
|
|
length -= (sizeof(*destination_info) + destination_info->num);
|
|
if (length < sizeof(*push_service_info)) {
|
|
goto out;
|
|
}
|
|
push_service_info = (proto_hx_dlms_data_fix_t *)
|
|
(destination_info->con + destination_info->num);
|
|
if (push_service_info->type != PROTO_HX_DLMS_DATA_TYPE_ENUM) {
|
|
goto out;
|
|
}
|
|
|
|
length -= (sizeof(*push_service_info) + 1);
|
|
if (length < sizeof(*push_client_info)) {
|
|
goto out;
|
|
}
|
|
push_client_info = (proto_hx_dlms_data_fix_t *)
|
|
(push_service_info->data + 1);
|
|
if (push_client_info->type != PROTO_HX_DLMS_DATA_TYPE_UINT8) {
|
|
goto out;
|
|
}
|
|
push_client = push_client_info->data[0];
|
|
|
|
length -= (sizeof(*push_client_info) + 1);
|
|
if (length < sizeof(*event_data_info)) {
|
|
goto out;
|
|
}
|
|
event_data_info = (proto_hx_dlms_data_t *)(push_client_info->data + 1);
|
|
if (event_data_info->type != PROTO_HX_DLMS_DATA_TYPE_OCTET_STR) {
|
|
goto out;
|
|
}
|
|
event_data_len = proto_hx_dlms_get_str_len(&event_data_info->num,
|
|
&len_width);
|
|
if (!event_data_len) {
|
|
goto out;
|
|
}
|
|
length -= sizeof(*event_data_info);
|
|
if (length < (event_data_len + len_width - sizeof(event_data_info->num))) {
|
|
goto out;
|
|
|
|
}
|
|
event_data = (uint8_t *)(event_data_info->con + (len_width - 1));
|
|
|
|
pkt_len = event_data_len + sizeof(*app_hdr);
|
|
pkt = iot_pkt_alloc(pkt_len, IOT_SMART_GRID_MID);
|
|
if (!pkt) {
|
|
goto out;
|
|
}
|
|
app_hdr = (proto_hx_dlms_app_hdr_t *)iot_pkt_put(pkt, pkt_len);
|
|
iot_uint16_to_bytes(1, (uint8_t *)&app_hdr->ver, 1);
|
|
iot_uint16_to_bytes(push_client, (uint8_t *)&app_hdr->dst_addr, 1);
|
|
iot_uint16_to_bytes(PROTO_HX_DLMS_LOGICAL_METER_ADDR,
|
|
(uint8_t *)&app_hdr->src_addr, 1);
|
|
iot_uint16_to_bytes((uint16_t)event_data_len, (uint8_t *)&app_hdr->len, 1);
|
|
os_mem_cpy(app_hdr->data, event_data, event_data_len);
|
|
|
|
out:
|
|
return pkt;
|
|
}
|