202 lines
5.8 KiB
C
202 lines
5.8 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 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_dlms.h"
|
|
|
|
/* smart grid internal header files */
|
|
#include "iot_sg_fr.h"
|
|
|
|
uint32_t proto_dlms_hdlc_addr_parse(uint8_t *data,
|
|
proto_dlms_hdlc_addr_t *addr)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
uint8_t *addr_ptr = data;
|
|
uint8_t addr_len = PROTO_DLMS_HDLC_ADD_MAX_LEN;
|
|
uint8_t i;
|
|
os_mem_set(addr, 0x0, sizeof(*addr));
|
|
/* if address include upper address and lower address
|
|
* addr_len is PROTO_DLMS_HDLC_ADD_MAX_LEN * 2.
|
|
*/
|
|
addr_len = addr_len << 1;
|
|
for (i = 0; i < addr_len; i++) {
|
|
if (addr_ptr[i] & 0x01) {
|
|
break;
|
|
}
|
|
}
|
|
addr->len = i + 1;
|
|
addr->type = addr->len;
|
|
switch (addr->type) {
|
|
case PROTO_DLMS_HDLC_ADD_TYPE_1:
|
|
{
|
|
addr->u_addr = (addr_ptr[0] >> 1);
|
|
break;
|
|
}
|
|
case PROTO_DLMS_HDLC_ADD_TYPE_2:
|
|
{
|
|
addr->u_addr = (addr_ptr[0] >> 1);
|
|
addr->l_addr = (addr_ptr[1] >> 1);
|
|
break;
|
|
}
|
|
case PROTO_DLMS_HDLC_ADD_TYPE_4:
|
|
{
|
|
addr->u_addr = (addr_ptr[0] >> 1);
|
|
addr->u_addr <<= 7;
|
|
addr->u_addr |= (addr_ptr[1] >> 1);
|
|
addr->l_addr = (addr_ptr[2] >> 1);
|
|
addr->l_addr <<= 7;
|
|
addr->l_addr |= (addr_ptr[3] >> 1);
|
|
break;
|
|
}
|
|
default:
|
|
goto drop;
|
|
}
|
|
goto out;
|
|
drop:
|
|
ret = ERR_FAIL;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
void proto_dlms_hdlc_type_4_addr_to_bcd_addr(uint8_t *addr,
|
|
proto_dlms_hdlc_addr_t *hdlc_addr)
|
|
{
|
|
uint16_t l_addr = hdlc_addr->l_addr;
|
|
os_mem_set(addr, 0x0, IOT_MAC_ADDR_LEN);
|
|
addr[2] = iot_byte_to_bcd((uint8_t)(l_addr / 10000));
|
|
l_addr %= 10000;
|
|
addr[1] = iot_byte_to_bcd((uint8_t)(l_addr / 100));
|
|
l_addr %= 100;
|
|
addr[0] = iot_byte_to_bcd((uint8_t)l_addr);
|
|
}
|
|
|
|
proto_dlms_hdlc_head_t *proto_dlms_hdlc_parse(uint8_t* data,
|
|
uint16_t len, proto_dlms_hdlc_cache_t *dlms_info)
|
|
{
|
|
uint16_t len_t, head_len, i = 0x0;
|
|
uint16_t rest_len;
|
|
uint8_t *data_s = NULL;
|
|
uint16_t min_data_len;
|
|
proto_dlms_hdlc_cache_t cache = {0};
|
|
union proto_dlms_hdlc_format frame_format = {0};
|
|
proto_dlms_hdlc_head_t* head;
|
|
|
|
for (i = 0x0, len_t = len; i < len; i++) {
|
|
if (data[i] == PROTO_DLMS_HDLC_START_BYTE) {
|
|
data_s = data + i;
|
|
break;
|
|
}
|
|
len_t--;
|
|
}
|
|
min_data_len = sizeof(proto_dlms_hdlc_head_t)
|
|
+ sizeof(proto_dlms_hdlc_tailer_t);
|
|
if (len_t <= min_data_len) {
|
|
goto drop;
|
|
}
|
|
/* start and end byte check */
|
|
if (data_s[0] != PROTO_DLMS_HDLC_START_BYTE
|
|
|| data_s[len_t - 1] != PROTO_DLMS_HDLC_END_BYTE) {
|
|
goto drop;
|
|
}
|
|
/* length check */
|
|
head = (proto_dlms_hdlc_head_t*)data_s;
|
|
frame_format.value = iot_ntohs(head->frame_format.value);
|
|
if ((frame_format.bit.len + PROTO_DLMS_HDLC_START_END_LEN) != len_t) {
|
|
goto drop;
|
|
}
|
|
|
|
/* dlms frame type check */
|
|
if (frame_format.bit.frame_type != PROTO_DLMS_HDLC_FRAME_HDLC) {
|
|
goto drop;
|
|
}
|
|
|
|
/* dlms frame fcs check */
|
|
if (proto_fcs16_check(data_s + 1,
|
|
(len_t - PROTO_DLMS_HDLC_START_END_LEN))) {
|
|
goto drop;
|
|
}
|
|
rest_len = len_t - min_data_len;
|
|
|
|
/* destination address parse */
|
|
if (proto_dlms_hdlc_addr_parse(head->sa_and_ca, &cache.dest_addr)) {
|
|
goto drop;
|
|
}
|
|
if(rest_len < cache.dest_addr.len) {
|
|
goto drop;
|
|
}
|
|
rest_len -= cache.dest_addr.len;
|
|
|
|
/* source address parse */
|
|
if (proto_dlms_hdlc_addr_parse(head->sa_and_ca + cache.dest_addr.len,
|
|
&cache.source_addr)) {
|
|
goto drop;
|
|
}
|
|
if (rest_len < cache.source_addr.len) {
|
|
goto drop;
|
|
}
|
|
rest_len -= cache.source_addr.len;
|
|
|
|
/* get control code */
|
|
if (rest_len < PROTO_DLMS_HDLC_CTRL_LEN) {
|
|
goto drop;
|
|
}
|
|
data_s = data_s + sizeof(proto_dlms_hdlc_head_t)
|
|
+ cache.dest_addr.len + cache.source_addr.len;
|
|
cache.control = *data_s;
|
|
rest_len -= PROTO_DLMS_HDLC_CTRL_LEN;
|
|
|
|
/* check if the data field and hcs exists */
|
|
if (rest_len == 0) {
|
|
/* If the data field and hcs don't exist,
|
|
* the analysis is complete.
|
|
*/
|
|
cache.data_ptr = NULL;
|
|
cache.data_len = 0;
|
|
goto out;
|
|
} else if (rest_len <= PROTO_DLMS_HDLC_CHECKSUM_LEN) {
|
|
goto drop;
|
|
}
|
|
/* dlms frame hcs check */
|
|
data_s = (uint8_t*)head;
|
|
head_len = sizeof(proto_dlms_hdlc_head_t) + cache.dest_addr.len
|
|
+ cache.source_addr.len + PROTO_DLMS_HDLC_CTRL_LEN
|
|
+ PROTO_DLMS_HDLC_CHECKSUM_LEN;
|
|
if (proto_fcs16_check(data_s + 1, head_len - 1)) {
|
|
goto drop;
|
|
}
|
|
rest_len -= PROTO_DLMS_HDLC_CHECKSUM_LEN;
|
|
|
|
/* get data */
|
|
cache.data_ptr = data_s + head_len;
|
|
cache.data_len = rest_len;
|
|
goto out;
|
|
drop:
|
|
head = NULL;
|
|
out:
|
|
if ((dlms_info != NULL) && (head != NULL)) {
|
|
*dlms_info = cache;
|
|
}
|
|
return head; /* checksum success */
|
|
}
|