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