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