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 */
							 | 
						||
| 
								 | 
							
								}
							 |