1255 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1255 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/****************************************************************************
 | 
						|
 | 
						|
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 shim includes */
 | 
						|
#include "os_types_api.h"
 | 
						|
#include "os_mem_api.h"
 | 
						|
 | 
						|
/* common includes */
 | 
						|
#include "iot_utils_api.h"
 | 
						|
#include "iot_errno_api.h"
 | 
						|
#include "iot_bitmap_api.h"
 | 
						|
 | 
						|
 | 
						|
/* smart grid internal includes */
 | 
						|
#include "proto_645.h"
 | 
						|
#include "proto_645_vendor.h"
 | 
						|
#include "proto_645_topo.h"
 | 
						|
 | 
						|
uint8_t proto_645_bcast_addr[IOT_MAC_ADDR_LEN] =
 | 
						|
    { 0x99, 0x99, 0x99, 0x99, 0x99, 0x99 };
 | 
						|
 | 
						|
uint8_t proto_645_bcast_dec_addr[IOT_MAC_ADDR_LEN] =
 | 
						|
    { 99, 99, 99, 99, 99, 99 };
 | 
						|
 | 
						|
uint8_t proto_645_any_addr[IOT_MAC_ADDR_LEN] =
 | 
						|
    { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
 | 
						|
 | 
						|
uint8_t proto_645_preamble[PROTO_645_PREAMBLE_LEN] =
 | 
						|
    { 0xFE, 0xFE, 0xFE, 0xFE };
 | 
						|
 | 
						|
uint8_t proto_645_calc_cs(proto_645_header_t *hdr)
 | 
						|
{
 | 
						|
    uint8_t ret = 0;
 | 
						|
    uint16_t i, len;
 | 
						|
    uint8_t *data = (uint8_t *)hdr;
 | 
						|
 | 
						|
    len = sizeof(*hdr) + hdr->len;
 | 
						|
    for (i = 0; i < len; i++)
 | 
						|
        ret += data[i];
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
proto_645_header_t *proto_645_format_check(uint8_t *data,
 | 
						|
    uint32_t len, uint32_t dir)
 | 
						|
{
 | 
						|
    uint32_t len_t, d_len, i = 0x0;
 | 
						|
    uint8_t *data_s = NULL;
 | 
						|
    proto_645_header_t *head;
 | 
						|
    proto_645_tailer_t *tail;
 | 
						|
    for (i = 0x0, len_t = len; i < len; i++) {
 | 
						|
        if (data[i] == PROTO_645_START_CHAR) {
 | 
						|
            data_s = data + i;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        len_t--;
 | 
						|
    }
 | 
						|
    if (data_s == NULL
 | 
						|
        || len_t < sizeof(proto_645_header_t)) {
 | 
						|
        goto drop;
 | 
						|
    }
 | 
						|
    head = (proto_645_header_t *)data_s;
 | 
						|
    if (head->start_char_1 != PROTO_645_START_CHAR
 | 
						|
        || head->start_char_2 != PROTO_645_START_CHAR) {
 | 
						|
        goto drop;
 | 
						|
    }
 | 
						|
    d_len = head->len;
 | 
						|
    if (len_t < (sizeof(proto_645_header_t) + d_len + \
 | 
						|
        sizeof(proto_645_tailer_t))) {
 | 
						|
        goto drop;
 | 
						|
    }
 | 
						|
    tail = (proto_645_tailer_t*)(data_s + sizeof(*head) + d_len);
 | 
						|
    if (proto_645_calc_cs(head) != tail->cs) {
 | 
						|
        goto drop;
 | 
						|
    }
 | 
						|
    if (tail->end_char != PROTO_645_END_CHAR)
 | 
						|
        goto drop;
 | 
						|
 | 
						|
    if (head->control.dir != dir) {
 | 
						|
        goto drop;
 | 
						|
    }
 | 
						|
    goto out;
 | 
						|
drop:
 | 
						|
    data_s = NULL;
 | 
						|
out:
 | 
						|
    return (proto_645_header_t *)data_s;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t proto_645_get_read_rsp_len(uint8_t p_id, uint32_t di)
 | 
						|
{
 | 
						|
    uint32_t d_len = 0;
 | 
						|
    uint32_t di_len;
 | 
						|
    uint32_t fixed_len = sizeof(proto_645_header_t) + \
 | 
						|
        sizeof(proto_645_tailer_t);
 | 
						|
    if (p_id == PROTO_645_2007_ID) {
 | 
						|
        di_len = PROTO_645_2007_DI_LEN;
 | 
						|
        switch (di) {
 | 
						|
        case PROTO_645_2007_DI_FOR_WATTH_T:
 | 
						|
            d_len = PROTO_645_2007_DI_FOR_WATTH_T_LEN;
 | 
						|
            break;
 | 
						|
        case PROTO_645_2007_DI_R_ADDR:
 | 
						|
            d_len = PROTO_645_2007_DI_R_ADDR_LEN;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            d_len= (PROTO_645_READ_DATA_MAX_LEN - di_len);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        di_len = PROTO_645_1997_DI_LEN;
 | 
						|
        switch (di) {
 | 
						|
        case PROTO_645_1997_DI_EPT_POS_SUM:
 | 
						|
            d_len = PROTO_645_1997_DI_EPT_POS_SUM_LEN;
 | 
						|
            break;
 | 
						|
        case PROTO_645_1997_DI_R_ADDR:
 | 
						|
            d_len = PROTO_645_1997_DI_R_ADDR_LEN;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            d_len = (PROTO_645_READ_DATA_MAX_LEN - di_len);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return (d_len + di_len + fixed_len);
 | 
						|
}
 | 
						|
 | 
						|
void proto_645_add33_handle(uint8_t *ds, uint32_t size)
 | 
						|
{
 | 
						|
    uint8_t  *ptr = ds;
 | 
						|
    while (size--)
 | 
						|
    {
 | 
						|
        (*ptr++) += 0x33;
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
void proto_645_sub33_handle(uint8_t *ds, uint32_t size)
 | 
						|
{
 | 
						|
    uint8_t  *ptr = ds;
 | 
						|
    while (size--)
 | 
						|
    {
 | 
						|
        (*ptr++) -= 0x33;
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
void proto_645_invert_handle(uint8_t *ds, uint32_t size)
 | 
						|
{
 | 
						|
    uint8_t  *ptr = ds;
 | 
						|
    while (size--)
 | 
						|
    {
 | 
						|
        (*ptr) = ~(*ptr);
 | 
						|
        ptr++;
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
void proto_645_header_init(proto_645_header_t *hdr,
 | 
						|
    uint8_t *addr, uint8_t fn, uint8_t dir, uint8_t ack_v, uint8_t follow_v)
 | 
						|
{
 | 
						|
    IOT_ASSERT(addr);
 | 
						|
    IOT_ASSERT(ack_v <= PROTO_645_ACK_ABNORMAL);
 | 
						|
    IOT_ASSERT(follow_v <= PROTO_645_FOLLOW_AVAILABLE);
 | 
						|
    IOT_ASSERT(dir <= PROTO_645_DIR_SLAVE);
 | 
						|
    hdr->start_char_1 = PROTO_645_START_CHAR;
 | 
						|
    iot_mac_addr_cpy(hdr->addr, addr);
 | 
						|
    hdr->len = 0;
 | 
						|
    hdr->control.fn  = fn;
 | 
						|
    hdr->control.dir = dir;
 | 
						|
    hdr->control.ack = ack_v;
 | 
						|
    hdr->control.follow = follow_v;
 | 
						|
    hdr->start_char_2 = PROTO_645_START_CHAR;
 | 
						|
}
 | 
						|
 | 
						|
void proto_645_tail_init(proto_645_header_t *hdr)
 | 
						|
{
 | 
						|
    uint8_t *data = hdr->data, len = hdr->len;
 | 
						|
    proto_645_tailer_t *tail = (proto_645_tailer_t*)(data + len);
 | 
						|
 | 
						|
    tail->cs = proto_645_calc_cs(hdr);
 | 
						|
    tail->end_char = PROTO_645_END_CHAR;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t proto_645_fill_frame(uint8_t *frames_filled,
 | 
						|
    uint8_t protocol_type, uint8_t *addr, uint8_t dir, uint8_t ack,
 | 
						|
    uint8_t follow, uint8_t fn, uint32_t di, uint8_t payload_len,
 | 
						|
    uint8_t *payload)
 | 
						|
{
 | 
						|
    uint8_t *data;
 | 
						|
    uint32_t length = 0;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
    uint8_t di_len = 0;
 | 
						|
    IOT_ASSERT(frames_filled && addr);
 | 
						|
    data = frames_filled;
 | 
						|
    hdr = (proto_645_header_t *)data;
 | 
						|
    proto_645_header_init(hdr, addr, fn, dir, ack, follow);
 | 
						|
    hdr->len = 0;
 | 
						|
    if (di != PROTO_645_INVALID_DI) {
 | 
						|
        /* fill DI */
 | 
						|
        if (protocol_type == PROTO_645_2007_ID) {
 | 
						|
            proto_645_2007_di_to_byte(di, hdr->data);
 | 
						|
            hdr->len += PROTO_645_2007_DI_LEN;
 | 
						|
            di_len = PROTO_645_2007_DI_LEN;
 | 
						|
        } else {
 | 
						|
            proto_645_1997_di_to_byte((uint16_t)di, hdr->data);
 | 
						|
            hdr->len += PROTO_645_1997_DI_LEN;
 | 
						|
            di_len = PROTO_645_1997_DI_LEN;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (payload && payload_len) {
 | 
						|
        /* fill data */
 | 
						|
        os_mem_cpy(hdr->data + di_len, payload, payload_len);
 | 
						|
        hdr->len += payload_len;
 | 
						|
    }
 | 
						|
    proto_645_add33_handle(hdr->data, hdr->len);
 | 
						|
    /* fill tail */
 | 
						|
    proto_645_tail_init(hdr);
 | 
						|
    length = (sizeof(proto_645_header_t) + hdr->len +
 | 
						|
        sizeof(proto_645_tailer_t));
 | 
						|
    return length;
 | 
						|
}
 | 
						|
 | 
						|
/* create a meter correcting time message for the 645 protocol  */
 | 
						|
iot_pkt_t *proto_645_build_corr_msg(uint8_t *addr, proto_645_corr_time_t *time)
 | 
						|
{
 | 
						|
    uint8_t *data, pm_addr[IOT_MAC_ADDR_LEN];
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
    proto_645_corr_time_t *tm;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
 | 
						|
    pkt = iot_pkt_alloc(PROTO_645_CORRECT_DATA_PKT_LEN + \
 | 
						|
        PROTO_645_PREAMBLE_LEN, IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt)
 | 
						|
        return NULL;
 | 
						|
    iot_pkt_reserve(pkt, PROTO_645_PREAMBLE_LEN);
 | 
						|
    data = iot_pkt_data(pkt);
 | 
						|
    if (!addr) {
 | 
						|
        iot_mac_addr_cpy(pm_addr, proto_645_bcast_addr);
 | 
						|
    } else {
 | 
						|
        iot_mac_addr_cpy(pm_addr, addr);
 | 
						|
    }
 | 
						|
    hdr = (proto_645_header_t*)data;
 | 
						|
    proto_645_header_init(hdr, pm_addr, PROTO_645_2007_FN_CORRECT_TIME,
 | 
						|
        PROTO_645_DIR_MASTER, PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID);
 | 
						|
    hdr->len = sizeof(*tm);
 | 
						|
    tm = (proto_645_corr_time_t*)hdr->data;
 | 
						|
    os_mem_cpy(tm, time, sizeof(*tm));
 | 
						|
    proto_645_add33_handle(hdr->data, hdr->len);
 | 
						|
    proto_645_tail_init(hdr);
 | 
						|
    iot_pkt_put(pkt, PROTO_645_CORRECT_DATA_PKT_LEN);
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
/* create a meter frozen message for dl/t645 - 07 protocol */
 | 
						|
iot_pkt_t *proto_645_2007_build_frozen_msg(uint8_t *addr,
 | 
						|
    proto_645_07_frozen_mdhm_t *time)
 | 
						|
{
 | 
						|
    uint8_t *data;
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
    proto_645_07_frozen_mdhm_t *tm;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
 | 
						|
    pkt = iot_pkt_alloc(PROTO_645_2007_FROZEN_DATA_PKT_LEN +
 | 
						|
        PROTO_645_PREAMBLE_LEN, IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt)
 | 
						|
        return NULL;
 | 
						|
    iot_pkt_reserve(pkt, PROTO_645_PREAMBLE_LEN);
 | 
						|
    data = iot_pkt_data(pkt);
 | 
						|
    hdr = (proto_645_header_t*)data;
 | 
						|
    proto_645_header_init(hdr, addr, PROTO_645_2007_FN_FROZE,
 | 
						|
        PROTO_645_DIR_MASTER, PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID);
 | 
						|
    hdr->len = sizeof(*tm);
 | 
						|
    tm = (proto_645_07_frozen_mdhm_t*)hdr->data;
 | 
						|
    os_mem_cpy(tm, time, sizeof(*time));
 | 
						|
    proto_645_add33_handle(hdr->data, hdr->len);
 | 
						|
    proto_645_tail_init(hdr);
 | 
						|
    iot_pkt_put(pkt, PROTO_645_2007_FROZEN_DATA_PKT_LEN);
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
/* create a meter reading message for the 645 protocol  */
 | 
						|
iot_pkt_t *proto_645_build_mr_msg(uint8_t p_id,
 | 
						|
    uint8_t *addr, uint32_t di)
 | 
						|
{
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
    uint8_t   fn;
 | 
						|
    uint32_t  length;
 | 
						|
    if (p_id != PROTO_645_1997_ID
 | 
						|
        && p_id != PROTO_645_2007_ID)
 | 
						|
        return NULL;
 | 
						|
    pkt = iot_pkt_alloc(max(PROTO_645_1997_READ_DATA_PKT_LEN,
 | 
						|
        PROTO_645_2007_READ_DATA_PKT_LEN) + PROTO_645_PREAMBLE_LEN, \
 | 
						|
        IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt)
 | 
						|
        return NULL;
 | 
						|
    iot_pkt_reserve(pkt, PROTO_645_PREAMBLE_LEN);
 | 
						|
    if (p_id == PROTO_645_1997_ID) {
 | 
						|
        fn = PROTO_645_1997_FN_READ_DATA;
 | 
						|
    } else {
 | 
						|
        fn = PROTO_645_2007_FN_READ_DATA;
 | 
						|
    }
 | 
						|
    length = proto_645_fill_frame(iot_pkt_data(pkt), p_id, addr,
 | 
						|
        PROTO_645_DIR_MASTER, PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID,
 | 
						|
        fn, di, 0, NULL);
 | 
						|
    IOT_ASSERT(length);
 | 
						|
    iot_pkt_put(pkt, length);
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
iot_pkt_t *proto_645_build_mr_msg_with_multi_di(uint8_t p_id,
 | 
						|
    uint8_t *addr, uint32_t *di_buf, uint8_t cnt,
 | 
						|
    uint8_t is_with_preamble)
 | 
						|
{
 | 
						|
    iot_pkt_t *pkt = NULL;
 | 
						|
    uint8_t i, fn, *data;
 | 
						|
    uint32_t size;
 | 
						|
    size = PROTO_645_2007_READ_DATA_PKT_LEN;
 | 
						|
    if (is_with_preamble) {
 | 
						|
        size += PROTO_645_PREAMBLE_LEN;
 | 
						|
    }
 | 
						|
    size *= cnt;
 | 
						|
    pkt = iot_pkt_alloc(size,IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt)
 | 
						|
        return NULL;
 | 
						|
    data = iot_pkt_data(pkt);
 | 
						|
    for (i = 0; i < cnt; i++) {
 | 
						|
        if (is_with_preamble) {
 | 
						|
            os_mem_cpy(data, proto_645_preamble, PROTO_645_PREAMBLE_LEN);
 | 
						|
            iot_pkt_put(pkt, PROTO_645_PREAMBLE_LEN);
 | 
						|
            data += PROTO_645_PREAMBLE_LEN;
 | 
						|
        }
 | 
						|
        if (p_id == PROTO_645_1997_ID) {
 | 
						|
            fn = PROTO_645_1997_FN_READ_DATA;
 | 
						|
        } else {
 | 
						|
            fn = PROTO_645_2007_FN_READ_DATA;
 | 
						|
        }
 | 
						|
        size = proto_645_fill_frame(data, p_id, addr,
 | 
						|
            PROTO_645_DIR_MASTER, PROTO_645_ACK_NORMAL,
 | 
						|
            PROTO_645_FOLLOW_INVALID, fn, di_buf[i], 0, NULL);
 | 
						|
        iot_pkt_put(pkt, size);
 | 
						|
        data += size;
 | 
						|
    }
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
/* creates a nack message for the 645-2007 protocol */
 | 
						|
iot_pkt_t *proto_645_2007_build_nack_msg(uint8_t err_code, uint8_t *addr,
 | 
						|
    uint8_t fn)
 | 
						|
{
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
 | 
						|
    pkt = iot_pkt_alloc(PROTO_645_2007_NACK_PKT_LEN, IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    hdr = (proto_645_header_t *)iot_pkt_data(pkt);
 | 
						|
    proto_645_header_init(hdr, addr, fn, PROTO_645_DIR_SLAVE,
 | 
						|
        PROTO_645_ACK_ABNORMAL, PROTO_645_FOLLOW_INVALID);
 | 
						|
    hdr->len = sizeof(err_code);
 | 
						|
    hdr->data[0] = err_code;
 | 
						|
    proto_645_add33_handle(hdr->data, hdr->len);
 | 
						|
    proto_645_tail_init(hdr);
 | 
						|
    iot_pkt_put(pkt, PROTO_645_2007_NACK_PKT_LEN);
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
/* creates a ack message for the 645-2007 protocol */
 | 
						|
iot_pkt_t *proto_645_2007_build_ack_msg(uint8_t *addr, uint8_t fn)
 | 
						|
{
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
 | 
						|
    pkt = iot_pkt_alloc(PROTO_645_2007_ACK_PKT_LEN, IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    hdr = (proto_645_header_t *)iot_pkt_data(pkt);
 | 
						|
 | 
						|
    iot_pkt_put(pkt, PROTO_645_2007_ACK_PKT_LEN);
 | 
						|
    proto_645_header_init(hdr, addr, fn, PROTO_645_DIR_SLAVE,
 | 
						|
        PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID);
 | 
						|
    hdr->len = 0;
 | 
						|
    proto_645_tail_init(hdr);
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
/* Creates a read address message for the 645-2007 protocol */
 | 
						|
iot_pkt_t *proto_645_2007_build_ra_msg(void)
 | 
						|
{
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
    uint32_t  length;
 | 
						|
    pkt = iot_pkt_alloc(PROTO_645_2007_READ_ADDR_PKT_LEN, IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt)
 | 
						|
        return NULL;
 | 
						|
    iot_pkt_reserve(pkt,PROTO_645_PREAMBLE_LEN);
 | 
						|
    length = proto_645_fill_frame(iot_pkt_data(pkt), PROTO_645_2007_ID,
 | 
						|
        proto_645_any_addr, PROTO_645_DIR_MASTER, PROTO_645_ACK_NORMAL,
 | 
						|
        PROTO_645_FOLLOW_INVALID, PROTO_645_2007_FN_READ_ADDR,
 | 
						|
        PROTO_645_INVALID_DI, 0, NULL);
 | 
						|
    IOT_ASSERT(length);
 | 
						|
    iot_pkt_put(pkt, length);
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_is_bcast(uint8_t* dst)
 | 
						|
{
 | 
						|
    return iot_mac_addr_cmp(dst, proto_645_bcast_addr);
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_pm_addr_valid(uint8_t *addr)
 | 
						|
{
 | 
						|
    uint8_t i;
 | 
						|
    if (!iot_mac_addr_valid(addr))
 | 
						|
        return 0;
 | 
						|
    if (iot_mac_addr_cmp(addr, proto_645_bcast_addr))
 | 
						|
        return 0;
 | 
						|
    for (i = 0; i < IOT_MAC_ADDR_LEN; i++) {
 | 
						|
        if (addr[i] > IOT_MAC_BCD_MAX) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_mac_addr_cmp(const uint8_t* dst, const uint8_t* src)
 | 
						|
{
 | 
						|
    int8_t  i;
 | 
						|
    uint8_t dst_wildcard_cnt = 0;
 | 
						|
    uint8_t src_wildcard_cnt = 0;
 | 
						|
    uint8_t cmp_cnt;
 | 
						|
    for(i = IOT_MAC_ADDR_LEN - 1; i >= 0;) {
 | 
						|
        if (dst[i] == PRORO_645_ANY_ADDR_BYTE) {
 | 
						|
            i--;
 | 
						|
            dst_wildcard_cnt++;
 | 
						|
        } else {
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    for(i = IOT_MAC_ADDR_LEN - 1; i >= 0;) {
 | 
						|
        if (src[i] == PRORO_645_ANY_ADDR_BYTE) {
 | 
						|
            i--;
 | 
						|
            src_wildcard_cnt++;
 | 
						|
        } else {
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if(dst_wildcard_cnt == IOT_MAC_ADDR_LEN ||
 | 
						|
       src_wildcard_cnt == IOT_MAC_ADDR_LEN) {
 | 
						|
       return 1;
 | 
						|
    }
 | 
						|
    cmp_cnt = IOT_MAC_ADDR_LEN - max(dst_wildcard_cnt, src_wildcard_cnt);
 | 
						|
    return os_mem_cmp(dst, src, cmp_cnt) == 0 ? 1 : 0;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_type_identify(proto_645_header_t *hdr)
 | 
						|
{
 | 
						|
    uint8_t proto_id = PROTO_UNKNOWN_ID;
 | 
						|
    switch(hdr->control.fn) {
 | 
						|
    case PROTO_645_2007_FN_READ_DATA:
 | 
						|
    case PROTO_645_2007_FN_READ_DATA_C:
 | 
						|
    case PROTO_645_2007_FN_READ_ADDR:
 | 
						|
    case PROTO_645_2007_FN_WRITE_DATA:
 | 
						|
    case PROTO_645_2007_FN_WRITE_ADDR:
 | 
						|
    case PROTO_645_2007_FN_FROZE:
 | 
						|
    case PROTO_645_2007_FN_CHG_RATE:
 | 
						|
    case PROTO_645_2007_FN_CHG_PASSWORD:
 | 
						|
    case PROTO_645_2007_FN_MAX_REQ_RESET:
 | 
						|
    case PROTO_645_2007_FN_PM_RESET:
 | 
						|
    case PROTO_645_2007_FN_EVENT_RESET:
 | 
						|
    case PROTO_645_2007_FN_COST_CON:
 | 
						|
    case PROTO_645_2007_EXT_FN_BR:
 | 
						|
    case PROTO_645_2007_FN_BAND_SWITCH:
 | 
						|
    case PROTO_645_2007_EXT_FN_QUERY_ID:
 | 
						|
    {
 | 
						|
        proto_id = PROTO_645_2007_ID;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    case PROTO_645_2007_FN_SECURITY_CERTIFICATE:
 | 
						|
    {
 | 
						|
        /* the fn of repeating read data in 97 protocol is same as the fn of
 | 
						|
         * security certificate in 07 protocol, but the repeated read data
 | 
						|
         * message of the 97 protocol is not loaded with data, i.e hdr->len
 | 
						|
         * = 0.
 | 
						|
         */
 | 
						|
        if (hdr->len)
 | 
						|
            proto_id = PROTO_645_2007_ID;
 | 
						|
        else
 | 
						|
            proto_id = PROTO_645_1997_ID;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    case PROTO_645_1997_FN_READ_DATA:
 | 
						|
    case PROTO_645_1997_FN_READ_DATA_C:
 | 
						|
    case PROTO_645_1997_FN_WRITE_DATA:
 | 
						|
    case PROTO_645_1997_FN_WRITE_ADDR:
 | 
						|
    case PROTO_645_1997_FN_CHG_RATE:
 | 
						|
    case PROTO_645_1997_FN_CHG_PASSWORD:
 | 
						|
    case PROTO_645_1997_FN_MAX_REQ_RESET:
 | 
						|
    {
 | 
						|
        proto_id = PROTO_645_1997_ID;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    case PROTO_645_2007_FN_CORRECT_TIME:
 | 
						|
    default:
 | 
						|
    {
 | 
						|
        /* because spec 07 and 97 has the same FN for correct time
 | 
						|
         * and unknown fn, the protocol id is unknown;
 | 
						|
         */
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    }
 | 
						|
    return proto_id;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t proto_645_07_event_validate(uint8_t *data, uint8_t len)
 | 
						|
{
 | 
						|
    uint8_t event_status_len;
 | 
						|
 | 
						|
    if (len < PROTO_645_2007_EVENT_STATUS_LEN) {
 | 
						|
        event_status_len = len;
 | 
						|
    } else {
 | 
						|
        event_status_len = PROTO_645_2007_EVENT_STATUS_LEN;
 | 
						|
    }
 | 
						|
 | 
						|
    return iot_bitmap_cbs(data, event_status_len);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t proto_645_get_di_by_sub33(uint8_t *data, uint8_t len,
 | 
						|
    uint8_t p_id, uint32_t *di)
 | 
						|
{
 | 
						|
    uint8_t di_t[PROTO_645_2007_DI_LEN] = {0};
 | 
						|
    uint32_t ret = ERR_OK;
 | 
						|
 | 
						|
    BUILD_BUG_ON(PROTO_645_2007_DI_LEN > PROTO_645_1997_DI_LEN);
 | 
						|
    if (p_id == PROTO_645_1997_ID) {
 | 
						|
        if (len < PROTO_645_1997_DI_LEN) {
 | 
						|
            ret = ERR_FAIL;
 | 
						|
            goto out;
 | 
						|
        }
 | 
						|
        os_mem_cpy(di_t, data, PROTO_645_1997_DI_LEN);
 | 
						|
        proto_645_sub33_handle(di_t, PROTO_645_1997_DI_LEN);
 | 
						|
        *di = proto_645_1997_byte_to_di(di_t);
 | 
						|
    } else {
 | 
						|
        if (len < PROTO_645_2007_DI_LEN) {
 | 
						|
            ret = ERR_FAIL;
 | 
						|
            goto out;
 | 
						|
        }
 | 
						|
        os_mem_cpy(di_t, data, PROTO_645_2007_DI_LEN);
 | 
						|
        proto_645_sub33_handle(di_t, PROTO_645_2007_DI_LEN);
 | 
						|
        *di = proto_645_2007_byte_to_di(di_t);
 | 
						|
    }
 | 
						|
 out:
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t proto_645_get_di(uint8_t *data, uint32_t len, uint8_t dir,
 | 
						|
    uint32_t *di, uint8_t *fn)
 | 
						|
{
 | 
						|
    uint32_t result = ERR_FAIL;
 | 
						|
    uint8_t proto_type;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
 | 
						|
    if (di == NULL || fn == NULL) {
 | 
						|
        result = ERR_INVAL;
 | 
						|
        goto exit_label;
 | 
						|
    }
 | 
						|
 | 
						|
    hdr = proto_645_format_check(data, len, dir);
 | 
						|
    if (hdr == NULL) {
 | 
						|
        /* invalid header, or invalid di. */
 | 
						|
        result = ERR_INVAL;
 | 
						|
        goto exit_label;
 | 
						|
    }
 | 
						|
 | 
						|
    proto_type = proto_645_type_identify(hdr);
 | 
						|
    if (proto_type == PROTO_UNKNOWN_ID) {
 | 
						|
        result = ERR_INVAL;
 | 
						|
        goto exit_label;
 | 
						|
    }
 | 
						|
 | 
						|
    if (ERR_OK == proto_645_get_di_by_sub33(hdr->data, hdr->len,
 | 
						|
        proto_type, di)) {
 | 
						|
        *fn = hdr->control.fn;
 | 
						|
        result = ERR_OK;
 | 
						|
        goto exit_label;
 | 
						|
    }
 | 
						|
 | 
						|
exit_label:
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t proto_645_check_di_fn_match(uint8_t *data1, uint32_t len1,
 | 
						|
    uint8_t *data2, uint32_t len2)
 | 
						|
{
 | 
						|
    uint32_t di1;
 | 
						|
    uint32_t di2;
 | 
						|
    uint8_t fn1;
 | 
						|
    uint8_t fn2;
 | 
						|
    uint32_t result1;
 | 
						|
    uint32_t result2;
 | 
						|
    uint32_t result = ERR_FAIL;
 | 
						|
    result1 = proto_645_get_di(data1, len1, PROTO_645_DIR_MASTER,
 | 
						|
        &di1, &fn1);
 | 
						|
    if (result1) {
 | 
						|
        goto exit_label;
 | 
						|
    }
 | 
						|
 | 
						|
    result2 = proto_645_get_di(data2, len2, PROTO_645_DIR_SLAVE,
 | 
						|
        &di2, &fn2);
 | 
						|
    if (result2) {
 | 
						|
        goto exit_label;
 | 
						|
    }
 | 
						|
 | 
						|
    if (di1 == di2 && fn1 == fn2) {
 | 
						|
        result = ERR_OK;
 | 
						|
    }
 | 
						|
 | 
						|
exit_label:
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_pkt_check_handle(iot_pkt_t *pkt, uint8_t *dir,
 | 
						|
    uint32_t *di)
 | 
						|
{
 | 
						|
    uint8_t ret = ERR_OK;
 | 
						|
    proto_645_header_t *hdr_645;
 | 
						|
    uint8_t fn;
 | 
						|
 | 
						|
    hdr_645 = proto_645_format_check(iot_pkt_data(pkt), iot_pkt_data_len(pkt),
 | 
						|
        PROTO_645_DIR_MASTER);
 | 
						|
    if (hdr_645 == NULL) {
 | 
						|
        hdr_645 = proto_645_format_check(iot_pkt_data(pkt),
 | 
						|
            iot_pkt_data_len(pkt), PROTO_645_DIR_SLAVE);
 | 
						|
        if (hdr_645 == NULL) {
 | 
						|
            ret = ERR_FAIL;
 | 
						|
        } else {
 | 
						|
            if (dir)
 | 
						|
                *dir = PROTO_645_DIR_SLAVE;
 | 
						|
            if (di)
 | 
						|
                proto_645_get_di(iot_pkt_data(pkt), iot_pkt_data_len(pkt),
 | 
						|
                    PROTO_645_DIR_SLAVE, di, &fn);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        if (dir)
 | 
						|
            *dir = PROTO_645_DIR_MASTER;
 | 
						|
        if (di)
 | 
						|
            proto_645_get_di(iot_pkt_data(pkt), iot_pkt_data_len(pkt),
 | 
						|
                PROTO_645_DIR_MASTER, di, &fn);
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_is_data_read(uint8_t *data, uint16_t len)
 | 
						|
{
 | 
						|
    uint8_t ret = 0;
 | 
						|
    proto_645_header_t *head;
 | 
						|
    head = proto_645_format_check(data, len, PROTO_645_DIR_MASTER);
 | 
						|
    if (!head) {
 | 
						|
        goto out;
 | 
						|
    }
 | 
						|
    if (head->control.fn == PROTO_645_2007_FN_READ_DATA ||
 | 
						|
        head->control.fn == PROTO_645_2007_FN_READ_DATA_C ||
 | 
						|
        head->control.fn == PROTO_645_1997_FN_READ_DATA ||
 | 
						|
        head->control.fn == PROTO_645_1997_FN_READ_DATA_C) {
 | 
						|
        ret = 1;
 | 
						|
    }
 | 
						|
out:
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_is_password_cmd(uint8_t *data, uint16_t len)
 | 
						|
{
 | 
						|
    uint8_t ret = 0;
 | 
						|
    proto_645_header_t *head;
 | 
						|
    head = proto_645_format_check(data, len, PROTO_645_DIR_MASTER);
 | 
						|
    if (!head) {
 | 
						|
        goto out;
 | 
						|
    }
 | 
						|
    if (head->control.fn == PROTO_645_2007_FN_CHG_PASSWORD ||
 | 
						|
        head->control.fn == PROTO_645_2007_FN_SECURITY_CERTIFICATE ||
 | 
						|
        head->control.fn == PROTO_645_2007_FN_COST_CON ||
 | 
						|
        head->control.fn == PROTO_645_1997_FN_CHG_PASSWORD) {
 | 
						|
        ret = 1;
 | 
						|
    }
 | 
						|
out:
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
proto_645_header_t *proto_645_format_check_ext(uint8_t *data,
 | 
						|
    uint32_t len, uint32_t dir)
 | 
						|
{
 | 
						|
    uint32_t len_t = len, d_len, i;
 | 
						|
    uint8_t *data_s = data;
 | 
						|
    proto_645_header_t *head;
 | 
						|
    proto_645_tailer_t *tail;
 | 
						|
again:
 | 
						|
    len = len_t;
 | 
						|
    for (i = 0x0; i < len; i++) {
 | 
						|
        if (data_s[i] == PROTO_645_START_CHAR) {
 | 
						|
            data_s += i;
 | 
						|
            len_t -= i;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (i == len) {
 | 
						|
        goto drop;
 | 
						|
    }
 | 
						|
    if (len_t < sizeof(proto_645_header_t)) {
 | 
						|
        goto drop;
 | 
						|
    }
 | 
						|
    head = (proto_645_header_t *)data_s;
 | 
						|
    if (head->start_char_1 != PROTO_645_START_CHAR
 | 
						|
        || head->start_char_2 != PROTO_645_START_CHAR) {
 | 
						|
        data_s++;
 | 
						|
        len_t--;
 | 
						|
        goto again;
 | 
						|
    }
 | 
						|
    d_len = head->len;
 | 
						|
    if (len_t < (sizeof(proto_645_header_t) + d_len + \
 | 
						|
        sizeof(proto_645_tailer_t))) {
 | 
						|
        data_s++;
 | 
						|
        len_t--;
 | 
						|
        goto again;
 | 
						|
    }
 | 
						|
    tail = (proto_645_tailer_t *)(head->data + d_len);
 | 
						|
    if (tail->end_char != PROTO_645_END_CHAR) {
 | 
						|
        data_s++;
 | 
						|
        len_t--;
 | 
						|
        goto again;
 | 
						|
    }
 | 
						|
    if (proto_645_calc_cs(head) != tail->cs) {
 | 
						|
        data_s++;
 | 
						|
        len_t--;
 | 
						|
        goto again;
 | 
						|
    }
 | 
						|
    if (head->control.dir != dir) {
 | 
						|
        len_t = len_t - sizeof(*head) - sizeof(*tail) - d_len;
 | 
						|
        if (len_t) {
 | 
						|
            data_s = (uint8_t *)(tail + 1);
 | 
						|
            goto again;
 | 
						|
        }
 | 
						|
        goto drop;
 | 
						|
    }
 | 
						|
    goto out;
 | 
						|
drop:
 | 
						|
    data_s = NULL;
 | 
						|
out:
 | 
						|
    return (proto_645_header_t *)data_s;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_unsig_to_bcd(uint32_t v, uint8_t bcd_byte_n,
 | 
						|
    uint8_t *bcd)
 | 
						|
{
 | 
						|
    uint8_t len = 0, i;
 | 
						|
    uint32_t v_max = 0;
 | 
						|
    uint32_t mul, div = 0;
 | 
						|
    for (i = 0, mul = 1; i < bcd_byte_n; i++) {
 | 
						|
        v_max +=  99 * mul;
 | 
						|
        div = mul;
 | 
						|
        mul *= 100;
 | 
						|
    }
 | 
						|
    v = v  > v_max ? v_max : v;
 | 
						|
    while (div) {
 | 
						|
        bcd[len++] = iot_byte_to_bcd((uint8_t)(v / div));
 | 
						|
        v %= div;
 | 
						|
        div /= 100;
 | 
						|
    }
 | 
						|
    IOT_ASSERT(bcd_byte_n == len);
 | 
						|
    iot_data_reverse(bcd, len);
 | 
						|
    return len;
 | 
						|
}
 | 
						|
 | 
						|
int32_t proto_645_bcd_to_integer(uint8_t *bcd, uint8_t bcd_byte_n,
 | 
						|
    uint8_t is_signed)
 | 
						|
{
 | 
						|
    uint8_t i, n = bcd_byte_n << 1, digital;
 | 
						|
    int32_t v = 0;
 | 
						|
    int32_t mul = 1;
 | 
						|
    int32_t sig = 1;
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
        if (i & 0x01) {
 | 
						|
            digital = bcd[i >> 1] >> 4;
 | 
						|
            if ((i >> 1) == (bcd_byte_n - 1) && is_signed) {
 | 
						|
                if (digital & 0x8) {
 | 
						|
                    sig = -1;
 | 
						|
                }
 | 
						|
                digital &= 0x7;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            digital = bcd[i >> 1] & 0xf;
 | 
						|
        }
 | 
						|
        if (digital > 9) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
        v += digital * mul;
 | 
						|
        mul *= 10;
 | 
						|
    }
 | 
						|
    return (v * sig);
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_bcd_data_check(uint8_t *bcd, uint8_t bcd_byte_n, uint8_t is_signed)
 | 
						|
{
 | 
						|
    uint8_t i;
 | 
						|
 | 
						|
    for (i = 0; i < bcd_byte_n; i++) {
 | 
						|
        if ((bcd[i] & 0xF) > 9) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
        if (((bcd[i] >> 4) & 0xF) > 9) {
 | 
						|
            if (i == (bcd_byte_n - 1) && is_signed) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
int32_t proto_645_ascii_to_integer(uint8_t *ascii, uint8_t ascii_byte_n)
 | 
						|
{
 | 
						|
    iot_data_reverse(ascii, ascii_byte_n);
 | 
						|
    return iot_atoi((const char*)ascii);
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_sig_to_bcd(int32_t v, uint8_t bcd_byte_n,
 | 
						|
    uint8_t *bcd)
 | 
						|
{
 | 
						|
    uint8_t len = 0, i;
 | 
						|
    uint32_t v_max = 0, v_abs;
 | 
						|
    uint32_t mul, div = 0;
 | 
						|
    for (i = 0, mul = 1; i < bcd_byte_n; i++) {
 | 
						|
        if (i == bcd_byte_n - 1)
 | 
						|
            v_max += 79 * mul;
 | 
						|
        else
 | 
						|
            v_max += 99 * mul;
 | 
						|
        div = mul;
 | 
						|
        mul *= 100;
 | 
						|
    }
 | 
						|
    v_abs = IOT_ABS(v);
 | 
						|
    v_abs = v_abs  > v_max ? v_max : v_abs;
 | 
						|
    while(div) {
 | 
						|
        bcd[len++] = iot_byte_to_bcd((uint8_t)(v_abs / div));
 | 
						|
        v_abs %= div;
 | 
						|
        div /= 100;
 | 
						|
    }
 | 
						|
    IOT_ASSERT(bcd_byte_n == len);
 | 
						|
    if (v < 0) {
 | 
						|
        bcd[0] |= 0x80;
 | 
						|
    }
 | 
						|
    iot_data_reverse(bcd, len);
 | 
						|
    return len;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_rtctime_to_YYMMDDhhmm(iot_time_tm_t *tm, uint8_t *buf)
 | 
						|
{
 | 
						|
    buf[0] = iot_byte_to_bcd(tm->tm_min);
 | 
						|
    buf[1] = iot_byte_to_bcd(tm->tm_hour);
 | 
						|
    buf[2] = iot_byte_to_bcd(tm->tm_mday);
 | 
						|
    buf[3] = iot_byte_to_bcd(tm->tm_mon);
 | 
						|
    buf[4] = iot_byte_to_bcd((uint8_t)(tm->tm_year - 2000));
 | 
						|
    return PROTO_645_YYMMDDHHMM_LEN;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_rtctime_to_YYMMDDhhmmss(iot_time_tm_t *tm, uint8_t *buf)
 | 
						|
{
 | 
						|
    buf[0] = iot_byte_to_bcd(tm->tm_sec);
 | 
						|
    buf[1] = iot_byte_to_bcd(tm->tm_min);
 | 
						|
    buf[2] = iot_byte_to_bcd(tm->tm_hour);
 | 
						|
    buf[3] = iot_byte_to_bcd(tm->tm_mday);
 | 
						|
    buf[4] = iot_byte_to_bcd(tm->tm_mon);
 | 
						|
    buf[5] = iot_byte_to_bcd((uint8_t)(tm->tm_year - 2000));
 | 
						|
    return PROTO_645_YYMMDDHHMMSS_LEN;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t proto_645_07_get_curve_point_len(uint32_t di)
 | 
						|
{
 | 
						|
    switch(di) {
 | 
						|
    case PROTO_645_2007_DI_CR_V_A:
 | 
						|
    case PROTO_645_2007_DI_CR_V_B:
 | 
						|
    case PROTO_645_2007_DI_CR_V_C:
 | 
						|
        return PROTO_645_V_LEN;
 | 
						|
    case PROTO_645_2007_DI_CR_V_ALL:
 | 
						|
        return PROTO_645_V_LEN * 3;
 | 
						|
    case PROTO_645_2007_DI_CR_I_A:
 | 
						|
    case PROTO_645_2007_DI_CR_I_B:
 | 
						|
    case PROTO_645_2007_DI_CR_I_C:
 | 
						|
    case PROTO_645_2007_EXT_CR_I_A:
 | 
						|
    case PROTO_645_2007_EXT_CR_I_B:
 | 
						|
    case PROTO_645_2007_EXT_CR_I_C:
 | 
						|
        return PROTO_645_07_A_LEN;
 | 
						|
    case PROTO_645_2007_DI_CR_I_ALL:
 | 
						|
    case PROTO_645_2007_EXT_CR_I_ALL:
 | 
						|
        return PROTO_645_07_A_LEN * 3;
 | 
						|
    case PROTO_645_2007_DI_CR_P_T:
 | 
						|
    case PROTO_645_2007_DI_CR_P_A:
 | 
						|
    case PROTO_645_2007_DI_CR_P_B:
 | 
						|
    case PROTO_645_2007_DI_CR_P_C:
 | 
						|
    case PROTO_645_2007_DI_CR_Q_T:
 | 
						|
    case PROTO_645_2007_DI_CR_Q_A:
 | 
						|
    case PROTO_645_2007_DI_CR_Q_B:
 | 
						|
    case PROTO_645_2007_DI_CR_Q_C:
 | 
						|
        return PROTO_645_07_P_LEN;
 | 
						|
    case PROTO_645_2007_DI_CR_P_ALL:
 | 
						|
    case PROTO_645_2007_DI_CR_Q_ALL:
 | 
						|
        return PROTO_645_07_P_LEN * 4;
 | 
						|
    case PROTO_645_2007_DI_CR_PF_T:
 | 
						|
    case PROTO_645_2007_DI_CR_PF_A:
 | 
						|
    case PROTO_645_2007_DI_CR_PF_B:
 | 
						|
    case PROTO_645_2007_DI_CR_PF_C:
 | 
						|
        return PROTO_645_07_PF_LEN;
 | 
						|
    case PROTO_645_2007_DI_CR_PF_ALL:
 | 
						|
        return PROTO_645_07_PF_LEN * 4;
 | 
						|
    case PROTO_645_2007_DI_CR_EP_POS:
 | 
						|
    case PROTO_645_2007_DI_CR_EP_NEG:
 | 
						|
    case PROTO_645_2007_DI_CR_EQ_POS:
 | 
						|
    case PROTO_645_2007_DI_CR_EQ_NEG:
 | 
						|
        return PROTO_645_07_ENERGY_DATA_LEN;
 | 
						|
    case PROTO_645_2007_DI_CR_EPEQ_ALL:
 | 
						|
        return PROTO_645_07_ENERGY_DATA_LEN * 4;
 | 
						|
    case PROTO_645_2007_DI_CR_EQ_QRT1:
 | 
						|
    case PROTO_645_2007_DI_CR_EQ_QRT2:
 | 
						|
    case PROTO_645_2007_DI_CR_EQ_QRT3:
 | 
						|
    case PROTO_645_2007_DI_CR_EQ_QRT4:
 | 
						|
        return PROTO_645_07_ENERGY_DATA_LEN;
 | 
						|
    case PROTO_645_2007_DI_CR_EQ_QRT_ALL:
 | 
						|
        return PROTO_645_07_ENERGY_DATA_LEN * 4;
 | 
						|
    case PROTO_645_2007_EXT_CR_EP_POS_A:
 | 
						|
    case PROTO_645_2007_EXT_CR_EP_NEG_A:
 | 
						|
    case PROTO_645_2007_EXT_CR_EP_POS_B:
 | 
						|
    case PROTO_645_2007_EXT_CR_EP_NEG_B:
 | 
						|
    case PROTO_645_2007_EXT_CR_EP_POS_C:
 | 
						|
    case PROTO_645_2007_EXT_CR_EP_NEG_C:
 | 
						|
        return PROTO_645_07_ENERGY_DATA_LEN;
 | 
						|
    case PROTO_645_2007_EXT_CR_TEMPERATURE:
 | 
						|
        return PROTO_645_07_TEMP_LEN;
 | 
						|
    case PROTO_645_2007_EXT_CR_HUMIDITY:
 | 
						|
        return PROTO_645_EXT_HUM_LEN;
 | 
						|
    case PROTO_645_2007_EXT_CR_EP_DATA_BLOCKS:
 | 
						|
        return sizeof(proto_645_ext_brm_cus_data_blocks_rsp_t);
 | 
						|
    default:
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
iot_pkt_t *proto_645_build_band_switch_rsp(const uint8_t *addr)
 | 
						|
{
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
    iot_pkt_t *pkt = NULL;
 | 
						|
    uint32_t di = PROTO_645_2007_DI_BAND_SWITCH;
 | 
						|
 | 
						|
    pkt = iot_pkt_alloc(PROTO_645_07_BADN_SWITCH_DATA_LEN + sizeof(*hdr) +
 | 
						|
        sizeof(proto_645_tailer_t), IOT_SMART_GRID_MID);
 | 
						|
    if (pkt) {
 | 
						|
        hdr = (proto_645_header_t *)iot_pkt_data(pkt);
 | 
						|
        /* fill in 645 header */
 | 
						|
        proto_645_header_init(hdr, (uint8_t*)addr,
 | 
						|
            PROTO_645_2007_FN_BAND_SWITCH, PROTO_645_DIR_SLAVE,
 | 
						|
            PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID);
 | 
						|
        hdr->len = PROTO_645_07_BADN_SWITCH_DATA_LEN;
 | 
						|
        proto_645_2007_di_to_byte(di, hdr->data);
 | 
						|
        proto_645_add33_handle(hdr->data, hdr->len);
 | 
						|
        proto_645_tail_init(hdr);
 | 
						|
        iot_pkt_put(pkt, PROTO_645_07_BADN_SWITCH_DATA_LEN + sizeof(*hdr) +
 | 
						|
            sizeof(proto_645_tailer_t));
 | 
						|
    }
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
iot_pkt_t *proto_645_2007_build_mr_rsp(uint8_t *addr, uint32_t di,
 | 
						|
    uint8_t *payload, uint8_t len, uint8_t head_reserved_len)
 | 
						|
{
 | 
						|
    uint8_t *data;
 | 
						|
    iot_pkt_t *pkt = NULL;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
 | 
						|
    if (!addr) {
 | 
						|
        return pkt;
 | 
						|
    }
 | 
						|
    /* node addr, little-endian */
 | 
						|
    pkt = iot_pkt_alloc(sizeof(*hdr) + sizeof(proto_645_tailer_t)
 | 
						|
        + PROTO_645_2007_DI_LEN + len + head_reserved_len,
 | 
						|
        IOT_SMART_GRID_MID);
 | 
						|
    if (pkt) {
 | 
						|
        iot_pkt_reserve(pkt, head_reserved_len);
 | 
						|
        data = iot_pkt_data(pkt);
 | 
						|
        hdr = (proto_645_header_t *)data;
 | 
						|
        proto_645_header_init(hdr, addr,
 | 
						|
            PROTO_645_2007_FN_READ_DATA, PROTO_645_DIR_SLAVE,
 | 
						|
            PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID);
 | 
						|
        iot_pkt_put(pkt, sizeof(*hdr));
 | 
						|
        data += sizeof(*hdr);
 | 
						|
        hdr->len = 0;
 | 
						|
        if (di != PROTO_645_INVALID_DI) {
 | 
						|
            proto_645_2007_di_to_byte(di, data);
 | 
						|
            hdr->len += PROTO_645_2007_DI_LEN;
 | 
						|
            data += PROTO_645_2007_DI_LEN;
 | 
						|
        }
 | 
						|
        if (payload && (len > 0)) {
 | 
						|
            os_mem_cpy(data, payload, len);
 | 
						|
            hdr->len += len;
 | 
						|
            data += len;
 | 
						|
        }
 | 
						|
        proto_645_add33_handle(hdr->data, hdr->len);
 | 
						|
        proto_645_tail_init(hdr);
 | 
						|
        iot_pkt_put(pkt, hdr->len + sizeof(proto_645_tailer_t));
 | 
						|
    }
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
iot_pkt_t *proto_645_1997_build_mr_rsp(uint8_t *addr, uint32_t di,
 | 
						|
    uint8_t *payload, uint8_t len, uint8_t head_reserved_len)
 | 
						|
{
 | 
						|
    uint8_t *data;
 | 
						|
    iot_pkt_t *pkt = NULL;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
 | 
						|
    if (!addr) {
 | 
						|
        return pkt;
 | 
						|
    }
 | 
						|
    /* node addr, little-endian */
 | 
						|
    pkt = iot_pkt_alloc(sizeof(*hdr) + sizeof(proto_645_tailer_t)
 | 
						|
        + PROTO_645_1997_DI_LEN + len + head_reserved_len,
 | 
						|
        IOT_SMART_GRID_MID);
 | 
						|
    if (pkt) {
 | 
						|
        iot_pkt_reserve(pkt, head_reserved_len);
 | 
						|
        data = iot_pkt_data(pkt);
 | 
						|
        hdr = (proto_645_header_t *)data;
 | 
						|
        proto_645_header_init(hdr, addr,
 | 
						|
            PROTO_645_1997_FN_READ_DATA, PROTO_645_DIR_SLAVE,
 | 
						|
            PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID);
 | 
						|
        iot_pkt_put(pkt, sizeof(*hdr));
 | 
						|
        data += sizeof(*hdr);
 | 
						|
        hdr->len = 0;
 | 
						|
        if (di != PROTO_645_INVALID_DI) {
 | 
						|
            proto_645_1997_di_to_byte(di, data);
 | 
						|
            hdr->len += PROTO_645_1997_DI_LEN;
 | 
						|
            data += PROTO_645_1997_DI_LEN;
 | 
						|
        }
 | 
						|
        if (payload && (len > 0)) {
 | 
						|
            os_mem_cpy(data, payload, len);
 | 
						|
            hdr->len += len;
 | 
						|
            data += len;
 | 
						|
        }
 | 
						|
        proto_645_add33_handle(hdr->data, hdr->len);
 | 
						|
        proto_645_tail_init(hdr);
 | 
						|
        iot_pkt_put(pkt, hdr->len + sizeof(proto_645_tailer_t));
 | 
						|
    }
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
iot_pkt_t *proto_645_2007_build_w_rsp(uint8_t *addr)
 | 
						|
{
 | 
						|
    uint8_t *data;
 | 
						|
    iot_pkt_t *pkt = NULL;
 | 
						|
    proto_645_header_t *hdr;
 | 
						|
 | 
						|
    if (!addr) {
 | 
						|
        return pkt;
 | 
						|
    }
 | 
						|
    /* node addr, little-endian */
 | 
						|
    pkt = iot_pkt_alloc(sizeof(*hdr) + sizeof(proto_645_tailer_t),
 | 
						|
        IOT_SMART_GRID_MID);
 | 
						|
    if (pkt) {
 | 
						|
        data = iot_pkt_put(pkt, sizeof(*hdr) + sizeof(proto_645_tailer_t));
 | 
						|
        hdr = (proto_645_header_t *)data;
 | 
						|
        proto_645_header_init(hdr, addr, PROTO_645_2007_FN_WRITE_DATA,
 | 
						|
            PROTO_645_DIR_SLAVE, PROTO_645_ACK_NORMAL,
 | 
						|
            PROTO_645_FOLLOW_INVALID);
 | 
						|
        hdr->len = 0;
 | 
						|
        proto_645_tail_init(hdr);
 | 
						|
    }
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
void proto_645_check_frame_handler(uint8_t* buffer, uint32_t buffer_len,
 | 
						|
    bool_t* is_frame)
 | 
						|
{
 | 
						|
    uint8_t d_len;
 | 
						|
    proto_645_header_t *head;
 | 
						|
    proto_645_tailer_t *tail;
 | 
						|
    do {
 | 
						|
        if (buffer_len < sizeof(proto_645_header_t)) {
 | 
						|
            *is_frame = false;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        head = (proto_645_header_t*)buffer;
 | 
						|
        if (head->start_char_1 != PROTO_645_START_CHAR
 | 
						|
            || head->start_char_2 != PROTO_645_START_CHAR) {
 | 
						|
            *is_frame = false;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        d_len = head->len;
 | 
						|
        if (buffer_len != (sizeof(proto_645_header_t) + d_len + \
 | 
						|
            sizeof(proto_645_tailer_t))) {
 | 
						|
            *is_frame = false;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        tail = (proto_645_tailer_t*)(buffer + sizeof(*head) + d_len);
 | 
						|
        if (proto_645_calc_cs(head) != tail->cs) {
 | 
						|
            *is_frame = false;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        if (tail->end_char != PROTO_645_END_CHAR) {
 | 
						|
            *is_frame = false;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        *is_frame = true;
 | 
						|
    } while(0);
 | 
						|
}
 | 
						|
 | 
						|
iot_pkt_t *proto_645_07_build_mr_lr_msg(uint8_t *addr,
 | 
						|
    uint32_t di, uint8_t n, iot_time_tm_t *start_tm)
 | 
						|
{
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
    uint32_t len;
 | 
						|
    uint8_t *data;
 | 
						|
    proto_645_07_curve_dl_t dl = {0};
 | 
						|
    pkt = iot_pkt_alloc(PROTO_645_PREAMBLE_LEN + sizeof(proto_645_header_t) +
 | 
						|
        PROTO_645_2007_DI_LEN + sizeof(proto_645_tailer_t)+ sizeof(dl),
 | 
						|
        IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt)
 | 
						|
        return NULL;
 | 
						|
    data = iot_pkt_reserve(pkt, PROTO_645_PREAMBLE_LEN);
 | 
						|
    dl.n = iot_byte_to_bcd(n);
 | 
						|
    dl.year = iot_byte_to_bcd((uint8_t)(start_tm->tm_year - 2000));
 | 
						|
    dl.mon = iot_byte_to_bcd(start_tm->tm_mon);
 | 
						|
    dl.mday = iot_byte_to_bcd(start_tm->tm_mday);
 | 
						|
    dl.hour = iot_byte_to_bcd(start_tm->tm_hour);
 | 
						|
    dl.min = iot_byte_to_bcd(start_tm->tm_min);
 | 
						|
    len = proto_645_fill_frame(data, PROTO_645_2007_ID, addr,
 | 
						|
        PROTO_645_DIR_MASTER, PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID,
 | 
						|
        PROTO_645_2007_FN_READ_DATA, di, sizeof(dl), (uint8_t *)&dl);
 | 
						|
    iot_pkt_put(pkt, len);
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
iot_pkt_t *proto_645_07_build_mr_lr_msg_with_multi_di(uint8_t *addr,
 | 
						|
    uint32_t *di_buf, uint8_t cnt, iot_time_tm_t *start_tm, uint8_t n,
 | 
						|
    uint8_t is_with_preamble)
 | 
						|
{
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
    uint32_t len;
 | 
						|
    uint8_t *data, i;
 | 
						|
    proto_645_07_curve_dl_t dl = {0};
 | 
						|
    len = sizeof(proto_645_header_t) + \
 | 
						|
        PROTO_645_2007_DI_LEN + sizeof(proto_645_tailer_t)+ sizeof(dl);
 | 
						|
    if (is_with_preamble) {
 | 
						|
        len += PROTO_645_PREAMBLE_LEN;
 | 
						|
    }
 | 
						|
    len *= cnt;
 | 
						|
    pkt = iot_pkt_alloc(len, IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt)
 | 
						|
        return NULL;
 | 
						|
    data = iot_pkt_data(pkt);
 | 
						|
    for (i = 0; i < cnt; i++) {
 | 
						|
        if (is_with_preamble) {
 | 
						|
            os_mem_cpy(data, proto_645_preamble, PROTO_645_PREAMBLE_LEN);
 | 
						|
            iot_pkt_put(pkt, PROTO_645_PREAMBLE_LEN);
 | 
						|
            data += PROTO_645_PREAMBLE_LEN;
 | 
						|
        }
 | 
						|
        dl.n = iot_byte_to_bcd(n);
 | 
						|
        dl.year = iot_byte_to_bcd((uint8_t)(start_tm->tm_year - 2000));
 | 
						|
        dl.mon = iot_byte_to_bcd(start_tm->tm_mon);
 | 
						|
        dl.mday = iot_byte_to_bcd(start_tm->tm_mday);
 | 
						|
        dl.hour = iot_byte_to_bcd(start_tm->tm_hour);
 | 
						|
        dl.min = iot_byte_to_bcd(start_tm->tm_min);
 | 
						|
        len = proto_645_fill_frame(data, PROTO_645_2007_ID, addr,
 | 
						|
            PROTO_645_DIR_MASTER, PROTO_645_ACK_NORMAL,
 | 
						|
            PROTO_645_FOLLOW_INVALID, PROTO_645_2007_FN_READ_DATA, di_buf[i],
 | 
						|
            sizeof(dl), (uint8_t *)&dl);
 | 
						|
        iot_pkt_put(pkt, len);
 | 
						|
        data += len;
 | 
						|
    }
 | 
						|
    return pkt;
 | 
						|
}
 | 
						|
 | 
						|
void proto_645_i_97_to_07(uint8_t *i_97, uint8_t *i_07)
 | 
						|
{
 | 
						|
    BUILD_BUG_ON(PROTO_645_07_A_LEN == 3);
 | 
						|
    BUILD_BUG_ON(PROTO_645_97_A_LEN == 2);
 | 
						|
    i_07[0] = (i_97[0] & 0x0f) << 4;
 | 
						|
    i_07[1] = ((i_97[0] & 0xf0) >> 4) | ((i_97[1] & 0x0f) << 4);
 | 
						|
    i_07[2] = (i_97[1] & 0xf0) >> 4;
 | 
						|
}
 | 
						|
 | 
						|
void proto_645_rp_97_to_07(uint8_t *rp_97, uint8_t *rp_07)
 | 
						|
{
 | 
						|
    BUILD_BUG_ON(PROTO_645_07_P_LEN == 3);
 | 
						|
    BUILD_BUG_ON(PROTO_645_97_RP_LEN == 2);
 | 
						|
    rp_07[0] = 0x0;
 | 
						|
    rp_07[1] = rp_97[0];
 | 
						|
    rp_07[2] = rp_97[1];
 | 
						|
}
 | 
						|
 | 
						|
uint32_t proto_645_corr_msg_check(uint8_t *data, uint32_t len, uint8_t *addr)
 | 
						|
{
 | 
						|
    uint32_t ret = ERR_INVAL;
 | 
						|
    proto_645_header_t *hdr_645;
 | 
						|
 | 
						|
    if (!data || !len || !addr) {
 | 
						|
        goto out;
 | 
						|
    }
 | 
						|
    hdr_645 = proto_645_format_check(data, len, PROTO_645_DIR_MASTER);
 | 
						|
    if (!hdr_645) {
 | 
						|
        goto out;
 | 
						|
    }
 | 
						|
    if (hdr_645->control.fn != PROTO_645_2007_FN_CORRECT_TIME) {
 | 
						|
        goto out;
 | 
						|
    }
 | 
						|
    if (hdr_645->len < sizeof(proto_645_corr_time_t)) {
 | 
						|
        goto out;
 | 
						|
    }
 | 
						|
    iot_mac_addr_cpy(addr, hdr_645->addr);
 | 
						|
    ret = ERR_OK;
 | 
						|
out:
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
iot_pkt_t *proto_645_build_msg(uint8_t *addr, uint8_t *data, uint8_t len,
 | 
						|
    uint32_t di, uint8_t dir, uint8_t ack, uint8_t fn, uint8_t p_id,
 | 
						|
    uint8_t follow)
 | 
						|
{
 | 
						|
    uint16_t pkt_len;
 | 
						|
    uint32_t length;
 | 
						|
    iot_pkt_t *pkt;
 | 
						|
 | 
						|
    if (p_id != PROTO_645_1997_ID && p_id != PROTO_645_2007_ID) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    pkt_len = PROTO_645_PREAMBLE_LEN + sizeof(proto_645_header_t) +
 | 
						|
        PROTO_645_2007_DI_LEN + len + sizeof(proto_645_tailer_t);
 | 
						|
    pkt = iot_pkt_alloc(pkt_len, IOT_SMART_GRID_MID);
 | 
						|
    if (!pkt) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    iot_pkt_reserve(pkt, PROTO_645_PREAMBLE_LEN);
 | 
						|
    length = proto_645_fill_frame(iot_pkt_data(pkt), p_id, addr, dir, ack,
 | 
						|
        follow, fn, di, len, data);
 | 
						|
    IOT_ASSERT(length);
 | 
						|
    iot_pkt_put(pkt, length);
 | 
						|
    return pkt;
 | 
						|
} |