/**************************************************************************** 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_dbglog_api.h" #include "iot_errno_api.h" #include "iot_utils_api.h" #include "iot_io_api.h" /* protocol includes */ #include "proto_crc16.h" #include "proto_645.h" #include "proto_69845.h" /* smart grid internal header files */ #include "iot_sg_cco_drv_api.h" #include "iot_sg_fr.h" #define PROTO_69845_DATA_DESC_LIST_MAX 40 #define PROTO_69845_ELEMENT_DATA_RECURSION_CNT_MAX 4 #define PROTO_69845_TANS_BAUD_MAX 11 #define PORTO_645_BAUD_ID_AUTO 255 const uint8_t proto_69845_preamble[PROTO_69845_PREAMBLE_LEN] = { 0xFE, 0xFE, 0xFE, 0xFE }; const server_addr_info_t proto_69845_any_server_addr = { .len = PROTO_69845_SA_LEN, .type = PROTO_69845_SA_TYPE_WILDCARD, .addr = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF}, .logical_addr = 0 }; const uint8_t proto_69845_event_report_data[PROTO_69845_EVENT_DATA_LEN] = { 0x34, 0x48, 0x33, 0x37, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xdd, 0xdd}; const uint8_t proto_69845_rn[PROTO_69845_SECURITY_RN_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const uint32_t proto_69845_tans_baud[PROTO_69845_TANS_BAUD_MAX] = { 300, 600, 1200, 2400, 4800, 7200, 9600, 19200, 38400, 57600, 115200}; const proto_69845_app_data_desc_t proto_69845_data_desc_list[ \ PROTO_69845_DATA_DESC_LIST_MAX] = { { PROTO_69845_APP_DATA_NULL, PROTO_69845_DATA_LEN_TYPE_NORMAL, 0, }, { PROTO_69845_APP_DATA_ARRAY, PROTO_69845_DATA_LEN_TYPE_ELEMENT, 0, }, { PROTO_69845_APP_DATA_STRUCTURE, PROTO_69845_DATA_LEN_TYPE_ELEMENT, 0, }, { PROTO_69845_APP_DATA_BOOL, PROTO_69845_DATA_LEN_TYPE_NORMAL, 1, }, { PROTO_69845_APP_DATA_BIT_STRING, PROTO_69845_DATA_LEN_TYPE_DIV8, 0 }, { PROTO_69845_APP_DATA_DOUBLE_LONG, PROTO_69845_DATA_LEN_TYPE_NORMAL, 4, }, { PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED, PROTO_69845_DATA_LEN_TYPE_NORMAL, 4, }, { PROTO_69845_APP_DATA_OCTET_STRING, PROTO_69845_DATA_LEN_TYPE_MULTI_BTYE, 0, }, { PROTO_69845_APP_DATA_VISIBLE_STRING, PROTO_69845_DATA_LEN_TYPE_MULTI_BTYE, 0, }, { PROTO_69845_APP_DATA_UTF8_SRTING, PROTO_69845_DATA_LEN_TYPE_MULTI_BTYE, 0, }, { PROTO_69845_APP_DATA_INTEGER, PROTO_69845_DATA_LEN_TYPE_NORMAL, 1, }, { PROTO_69845_APP_DATA_LONG, PROTO_69845_DATA_LEN_TYPE_NORMAL, 2, }, { PROTO_69845_APP_DATA_UNSIGNED, PROTO_69845_DATA_LEN_TYPE_NORMAL, 1, }, { PROTO_69845_APP_DATA_LONG_UNSIGNED, PROTO_69845_DATA_LEN_TYPE_NORMAL, 2, }, { PROTO_69845_APP_DATA_LONG64, PROTO_69845_DATA_LEN_TYPE_NORMAL, 8, }, { PROTO_69845_APP_DATA_LONG64_UNSIGNED, PROTO_69845_DATA_LEN_TYPE_NORMAL, 8, }, { PROTO_69845_APP_DATA_ENUM, PROTO_69845_DATA_LEN_TYPE_NORMAL, 1, }, { PROTO_69845_APP_DATA_FLOAT32, PROTO_69845_DATA_LEN_TYPE_NORMAL, 4, }, { PROTO_69845_APP_DATA_FLOAT64, PROTO_69845_DATA_LEN_TYPE_NORMAL, 8, }, { PROTO_69845_APP_DATA_DATE_TIME, PROTO_69845_DATA_LEN_TYPE_NORMAL, 10, }, { PROTO_69845_APP_DATA_DATE, PROTO_69845_DATA_LEN_TYPE_NORMAL, 5, }, { PROTO_69845_APP_DATA_TIME, PROTO_69845_DATA_LEN_TYPE_NORMAL, 3, }, { PROTO_69845_APP_DATA_TIME_S, PROTO_69845_DATA_LEN_TYPE_NORMAL, 7, }, { PROTO_69845_APP_DATA_OI, PROTO_69845_DATA_LEN_TYPE_NORMAL, 2, }, { PROTO_69845_APP_DATA_OAD, PROTO_69845_DATA_LEN_TYPE_NORMAL, 4, }, { PROTO_69845_APP_DATA_ROAD, PROTO_69845_DATA_LEN_TYPE_ROAD, 0, }, { PROTO_69845_APP_DATA_OMD, PROTO_69845_DATA_LEN_TYPE_NORMAL, 4, }, { PROTO_69845_APP_DATA_TI, PROTO_69845_DATA_LEN_TYPE_NORMAL, 3, }, { PROTO_69845_APP_DATA_TSA, PROTO_69845_DATA_LEN_TYPE_TSA, 0, }, { PROTO_69845_APP_DATA_MAC, PROTO_69845_DATA_LEN_TYPE_UNKNOW, 0, }, { PROTO_69845_APP_DATA_RN, PROTO_69845_DATA_LEN_TYPE_MULTI_BTYE, 0, }, { PROTO_69845_APP_DATA_REGION, PROTO_69845_DATA_LEN_TYPE_UNKNOW, 0, }, { PROTO_69845_APP_DATA_SCALER_UNIT, PROTO_69845_DATA_LEN_TYPE_NORMAL, 2, }, { PROTO_69845_APP_DATA_RSD, PROTO_69845_DATA_LEN_TYPE_RSD, 0, }, { PROTO_69845_APP_DATA_CSD, PROTO_69845_DATA_LEN_TYPE_CSD, 0, }, { PROTO_69845_APP_DATA_MS, PROTO_69845_DATA_LEN_TYPE_MS, 0, }, { PROTO_69845_APP_DATA_SID, PROTO_69845_DATA_LEN_TYPE_UNKNOW, 0, }, { PROTO_69845_APP_DATA_SID_MAC, PROTO_69845_DATA_LEN_TYPE_UNKNOW, 0, }, { PROTO_69845_APP_DATA_COMDCB, PROTO_69845_DATA_LEN_TYPE_NORMAL, 5, }, { PROTO_69845_APP_DATA_RCSD, PROTO_69845_DATA_LEN_TYPE_RCSD, 0, }, }; uint8_t proto_698_is_security_cmd(uint8_t *data, uint32_t len) { uint8_t ret = 0; proto_69845_frame_head_info_t *head; proto_69845_app_req_resp_t *resp; apdu_info_t apdu; if (proto_69845_parse(&data, &len, &head, &apdu) != ERR_OK) { goto out; } if (apdu.len < sizeof(*resp)) { goto out; } resp = (proto_69845_app_req_resp_t * )apdu.ptr; if (resp->type == PROTO_69845_C_APP_SECURITY_REQ || resp->type == PROTO_69845_S_APP_SECURITY_RESP) { ret = 1; } out: return ret; } uint8_t proto_698_interactive_cmd_check(uint8_t *data1, uint32_t len1, uint8_t *data2, uint32_t len2) { uint32_t apud_len1, apdu_len2; uint8_t ret = 0, *choice1, *choice2; proto_69845_frame_head_info_t *head1, *head2; proto_69845_app_req_resp_t *resp1, *resp2; proto_69845_app_piid_t *piid1 = NULL, *piid2 = NULL; apdu_info_t apdu1, apdu2; if (!data1 || !len1 || !data2 || !len2) { goto out; } if (proto_69845_parse(&data1, &len1, &head1, &apdu1) != ERR_OK || proto_69845_parse(&data2, &len2, &head2, &apdu2) != ERR_OK) { goto out; } apud_len1 = apdu1.len; apdu_len2 = apdu2.len; if (apud_len1 < sizeof(*resp1) || apdu_len2 < sizeof(*resp2)) { goto out; } apud_len1 -= sizeof(*resp1); apdu_len2 -= sizeof(*resp2); resp1 = (proto_69845_app_req_resp_t * )apdu1.ptr; resp2 = (proto_69845_app_req_resp_t * )apdu2.ptr; if (((resp1->type & 0x80) == (resp2->type & 0x80)) || ((resp1->type & 0x7f) != (resp2->type & 0x7f))) { goto out; } switch (resp1->type & 0x7f) { case PROTO_69845_C_APP_LINK_RESP: case PROTO_69845_C_APP_CONNECT_REQ: case PROTO_69845_C_APP_RELEASE_REQ: { if (apud_len1 < sizeof(*piid1) || apdu_len2 < sizeof(*piid2)) { goto out; } piid1 = (proto_69845_app_piid_t *)resp1->data; piid2 = (proto_69845_app_piid_t *)resp2->data; break; } case PROTO_69845_C_APP_GET_REQ: case PROTO_69845_C_APP_SET_REQ: case PROTO_69845_C_APP_ACTION_REQ: case PROTO_69845_C_APP_REPORT_RESP: case PROTO_69845_C_APP_PROXY_REQ: { if (apud_len1 < sizeof(*choice1) || apdu_len2 < sizeof(*choice2)) { goto out; } apud_len1 -= sizeof(*choice1); apdu_len2 -= sizeof(*choice2); choice1 = resp1->data; choice2 = resp2->data; if (*choice1 != *choice2) { goto out; } if (apud_len1 < sizeof(*piid1) || apdu_len2 < sizeof(*piid2)) { goto out; } piid1 = (proto_69845_app_piid_t *)(choice1 + 1); piid2 = (proto_69845_app_piid_t *)(choice2 + 1); break; } default: break; } if (!piid1 || !piid2) { goto out; } if (piid1->sn != piid2->sn) { goto out; } ret = 1; out: return ret; } uint32_t proto_698_oad_to_645_di(uint32_t oad_698) { uint32_t di_645 = PROTO_645_INVALID_DI; uint16_t oi_698 = oad_698 >> 16; switch (oi_698) { case PROTO_69845_APP_OI_VOLTAGE: { di_645 = PROTO_645_2007_DI_V_ALL; break; } case PROTO_69845_APP_OI_CURRENT: { if (oad_698 == PROTO_69845_APP_OAD_GND_CURRENT) { di_645 = PROTO_645_2007_DI_I_N; } else { di_645 = PROTO_645_2007_DI_I_ALL; } break; } case PROTO_69845_APP_OI_P: { di_645 = PROTO_645_2007_DI_P_ALL; break; } case PROTO_69845_APP_OI_Q: { di_645 = PROTO_645_2007_DI_Q_ALL; break; } case PROTO_69845_APP_OI_PF: { di_645 = PROTO_645_2007_DI_PF_ALL; break; } case PROTO_69845_APP_OI_EPT_COMP: { di_645 = PROTO_645_2007_DI_EPT_COMP_ALL; break; } case PROTO_69845_APP_OI_EPT_POS: { di_645 = PROTO_645_2007_DI_EPT_POS_ALL; break; } case PROTO_69845_APP_OI_EPT_NEG: { di_645 = PROTO_645_2007_DI_EPT_NEG_ALL; break; } case PROTO_69845_APP_OI_EQT_POS: { di_645 = PROTO_645_2007_DI_EQT_POS_ALL; break; } case PROTO_69845_APP_OI_EQT_NEG: { di_645 = PROTO_645_2007_DI_EQT_NEG_ALL; break; } case PROTO_69845_APP_OI_EQT_QRT1: { di_645 = PROTO_645_2007_DI_EQT_QRT1_SUM; break; } case PROTO_69845_APP_OI_EQT_QRT2: { di_645 = PROTO_645_2007_DI_EQT_QRT2_SUM; break; } case PROTO_69845_APP_OI_EQT_QRT3: { di_645 = PROTO_645_2007_DI_EQT_QRT3_SUM; break; } case PROTO_69845_APP_OI_EQT_QRT4: { di_645 = PROTO_645_2007_DI_EQT_QRT4_SUM; break; } case PROTO_69845_APP_OI_EPT_DEMAND: { di_645 = PROTO_645_2007_DI_EPT_DEMAND; break; } case PROTO_69845_APP_OI_EQT_DEMAND: { di_645 = PROTO_645_2007_DI_EQT_DEMAND; break; } case PROTO_69845_APP_OI_EPT_POS_DEMAND: { di_645 = PROTO_645_2007_DI_EPT_POS_DEMAND; break; } case PROTO_69845_APP_OI_EPT_NEG_DEMAND: { di_645 = PROTO_645_2007_DI_EPT_NEG_DEMAND; break; } default: break; } switch (oad_698) { case PROTO_69845_APP_OAD_EPT_POS_A_SIG: { di_645 = PROTO_645_2007_DI_EPT_POS_A; break; } case PROTO_69845_APP_OAD_EPT_POS_B_SIG: { di_645 = PROTO_645_2007_DI_EPT_POS_B; break; } case PROTO_69845_APP_OAD_EPT_POS_C_SIG: { di_645 = PROTO_645_2007_DI_EPT_POS_C; break; } default: break; } return di_645; } uint32_t proto_645_di_to_698_oad(uint32_t di) { uint32_t oad_698 = PROTO_69845_APP_OAD_INVALID; switch (di) { case PROTO_645_2007_DI_V_A: case PROTO_645_2007_DI_V_ALL: { oad_698 = PROTO_69845_APP_OAD_VOLTAGE; break; } case PROTO_645_2007_DI_I_A: case PROTO_645_2007_DI_I_ALL: { oad_698 = PROTO_69845_APP_OAD_CURRENT; break; } case PROTO_645_2007_DI_PF_ALL: { oad_698 = PROTO_69845_APP_OAD_PF; break; } case PROTO_645_2007_DI_EPT_COMP_SUM: case PROTO_645_2007_DI_EPT_COMP_ALL: { oad_698 = PROTO_69845_APP_OAD_EPT_COMP; break; } case PROTO_645_2007_DI_EPT_POS_ALL: case PROTO_645_2007_DI_EPT_POS_SUM: { oad_698 = PROTO_69845_APP_OAD_EPT_POS; break; } case PROTO_645_2007_DI_EPT_NEG_ALL: case PROTO_645_2007_DI_EPT_NEG_SUM: { oad_698 = PROTO_69845_APP_OAD_EPT_NEG; break; } case PROTO_645_2007_DI_EQT_POS_ALL: case PROTO_645_2007_DI_EQT_POS_SUM: { oad_698 = PROTO_69845_APP_OAD_EQT_POS; break; } case PROTO_645_2007_DI_EQT_NEG_ALL: case PROTO_645_2007_DI_EQT_NEG_SUM: { oad_698 = PROTO_69845_APP_OAD_EQT_NEG; break; } case PROTO_645_2007_DI_P_A: case PROTO_645_2007_DI_P_T: case PROTO_645_2007_DI_P_ALL: { oad_698 = PROTO_69845_APP_OAD_P; break; } case PROTO_645_2007_DI_Q_ALL: { oad_698 = PROTO_69845_APP_OAD_Q; break; } case PROTO_645_2007_DI_I_N: { oad_698 = PROTO_69845_APP_OAD_GND_CURRENT; break; } case PROTO_645_2007_DI_EQT_QRT1_SUM: { oad_698 = PROTO_69845_APP_OAD_EQT_QRT1_SUM; break; } case PROTO_645_2007_DI_EQT_QRT2_SUM: { oad_698 = PROTO_69845_APP_OAD_EQT_QRT2_SUM; break; } case PROTO_645_2007_DI_EQT_QRT3_SUM: { oad_698 = PROTO_69845_APP_OAD_EQT_QRT3_SUM; break; } case PROTO_645_2007_DI_EQT_QRT4_SUM: { oad_698 = PROTO_69845_APP_OAD_EQT_QRT4_SUM; break; } case PROTO_645_2007_DI_EPT_DEMAND: { oad_698 = PROTO_69845_APP_OAD_EPT_DEMAND; break; } case PROTO_645_2007_DI_EQT_DEMAND: { oad_698 = PROTO_69845_APP_OAD_EQT_DEMAND; break; } case PROTO_645_2007_DI_EPT_POS_DEMAND: { oad_698 = PROTO_69845_APP_OAD_EPT_POS_DEMAND; break; } case PROTO_645_2007_DI_EPT_NEG_DEMAND: { oad_698 = PROTO_69845_APP_OAD_EPT_NEG_DEMAND; break; } case PROTO_645_2007_DI_TIME: { oad_698 = PROTO_69845_APP_OAD_TIME; break; } case PROTO_645_2007_DI_EPT_POS_A: { oad_698 = PROTO_69845_APP_OAD_EPT_POS_A_SIG; break; } case PROTO_645_2007_DI_EPT_POS_B: { oad_698 = PROTO_69845_APP_OAD_EPT_POS_B_SIG; break; } case PROTO_645_2007_DI_EPT_POS_C: { oad_698 = PROTO_69845_APP_OAD_EPT_POS_C_SIG; break; } case PROTO_645_2007_DI_RT_YMDHMS_LAST1: case PROTO_645_2007_DI_RT_EP_POS_LAST1: case PROTO_645_2007_DI_RT_EP_NEG_LAST1: case PROTO_645_2007_DI_RT_VARIABLE_LAST1: default: break; } return oad_698; } uint32_t proto_69845_is_any_server_addr(uint8_t *server_addr) { uint8_t i; for (i = 0; i < IOT_MAC_ADDR_LEN; i++) { if (server_addr[i] == 0xAA) { return 1; } } return 0; } uint8_t proto_69845_get_addr_info(proto_69845_frame_head_info_t* head, addr_info_t *addr_info) { uint8_t total_len = 0; if (head == NULL) { goto out; } total_len = head->addr.flag.sa_len + 1; if (addr_info) { if (head->addr.flag.flg_ext) { addr_info->ser_info.logical_addr = head->addr.sa_and_ca[0]; addr_info->ser_info.len = total_len - PROTO_69845_EXT_LOGICAL_ADD_LEN; os_mem_cpy(addr_info->ser_info.addr, &head->addr.sa_and_ca[PROTO_69845_EXT_LOGICAL_ADD_LEN], addr_info->ser_info.len); } else { addr_info->ser_info.logical_addr = head->addr.flag.logical_addr; addr_info->ser_info.len = total_len; os_mem_cpy(addr_info->ser_info.addr, head->addr.sa_and_ca, addr_info->ser_info.len); } addr_info->ser_info.type = head->addr.flag.sa_type; addr_info->cli_addr = head->addr.sa_and_ca[total_len]; } total_len += PROTO_69845_CA_LEN; out: return total_len; } uint8_t *proto_69845_get_ser_addr(proto_69845_frame_head_info_t* head) { uint8_t *addr = NULL; if (head) { addr = head->addr.sa_and_ca; if (head->addr.flag.flg_ext) { addr += PROTO_69845_EXT_LOGICAL_ADD_LEN; } } return addr; } static uint8_t proto_69845_server_len_calc( const server_addr_info_t *ser_info) { uint8_t len; len = ser_info->len; if (ser_info->logical_addr >= PROTO_69845_EXT_LOGICAL_ADD_MIN) { len += PROTO_69845_EXT_LOGICAL_ADD_LEN; } return len; } uint32_t proto_69845_head_sanity_check( proto_69845_frame_head_info_t* head, uint8_t* data, uint16_t len) { uint8_t head_len; uint8_t *check_sum_start = data + 1; uint32_t ret; if ((head->addr.flag.sa_len + 1) > PROTO_69845_SA_MAX_LEN) { ret = ERR_FAIL; goto out; } head_len = sizeof(proto_69845_frame_head_info_t) + head->addr.flag.sa_len \ + 1 + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; if (len < head_len) { ret = ERR_FAIL; goto out; } head_len = (head_len - sizeof(head->start_char)); /* 698.45 Head Check Sum */ ret = proto_fcs16_check(check_sum_start, head_len); out: /* Invalid 698.45 protocol head */ return ret; } proto_69845_frame_head_info_t *proto_69845_sanity_check(uint8_t* data, uint16_t len) { uint16_t len_t, i = 0x0; uint8_t *data_s = NULL; uint16_t min_data_len = sizeof(proto_69845_frame_head_info_t); proto_69845_frame_head_info_t* head; for (i = 0x0, len_t = len; i < len; i++) { if (data[i] == PROTO_69845_START_BYTE) { data_s = data + i; break; } len_t--; } if (len_t <= min_data_len) { goto drop; } head = (proto_69845_frame_head_info_t*)data_s; if (len_t < (head->len + PROTO_69845_START_END_LEN)) { goto drop; } if (data_s[0] != PROTO_69845_START_BYTE || data_s[head->len + 1] != PROTO_69845_END_BYTE) { goto drop; } if (proto_69845_head_sanity_check(head, data_s, len_t)) { /* Invalid 698.45 protocol head */ goto drop; } /* 698.45 frame check sum */ if (proto_fcs16_check(data_s + 1, head->len)) { goto drop; } goto out; drop: head = NULL; out: return head; /* checksum success */ } proto_69845_frame_head_info_t *proto_69845_sanity_check_ext(uint8_t* data, uint16_t len) { uint16_t len_t = len, curr_len, i = 0x0; uint8_t *data_s = data; uint16_t min_data_len = sizeof(proto_69845_frame_head_info_t); proto_69845_frame_head_info_t* head; again: curr_len = len_t; for (i = 0x0; i < curr_len; i++) { if (data_s[i] == PROTO_69845_START_BYTE) { data_s += i; len_t -= i; break; } } if (i == curr_len) { goto drop; } if (len_t < min_data_len) { goto drop; } head = (proto_69845_frame_head_info_t*)data_s; if (len_t < (head->len + PROTO_69845_START_END_LEN)) { data_s++; len_t--; goto again; } if (data_s[0] != PROTO_69845_START_BYTE || data_s[head->len + 1] != PROTO_69845_END_BYTE) { data_s++; len_t--; goto again; } if (proto_69845_head_sanity_check(head, data_s, len_t)) { /* Invalid 698.45 protocol head */ data_s++; len_t--; goto again; } /* 698.45 frame check sum */ if (proto_fcs16_check(data_s + 1, head->len)) { data_s++; len_t--; goto again; } goto out; drop: head = NULL; out: return head; } uint32_t proto_69845_head_fill( proto_69845_frame_head_info_t *head, uint16_t head_len, uint16_t total_len, addr_info_t *addr_info, uint8_t fn, uint8_t fragment, uint8_t dir_prm) { uint8_t *data, ser_len; uint16_t cs_len, cs; uint32_t ret = ERR_FAIL; if (!total_len || !addr_info) { goto out; } if (total_len < head_len) { goto out; } ser_len = proto_69845_server_len_calc(&addr_info->ser_info); if ((head_len < (sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN)) || !ser_len) { goto out; } data = (uint8_t*)head; head->start_char = PROTO_69845_START_BYTE; head->len = total_len - PROTO_69845_START_END_LEN; head ->ctrl.fn = fn; head->ctrl.fragment = fragment; head->ctrl.dir_prm = dir_prm; if (addr_info->ser_info.logical_addr < PROTO_69845_EXT_LOGICAL_ADD_MIN) { head->addr.flag.logical_addr = addr_info->ser_info.logical_addr; head->addr.flag.flg_ext = 0; os_mem_cpy(head->addr.sa_and_ca, addr_info->ser_info.addr, addr_info->ser_info.len); head->addr.flag.sa_len = addr_info->ser_info.len; } else { head->addr.flag.logical_addr = 0; head->addr.flag.flg_ext = 1; head->addr.sa_and_ca[0] = addr_info->ser_info.logical_addr; os_mem_cpy(&head->addr.sa_and_ca[PROTO_69845_EXT_LOGICAL_ADD_LEN], addr_info->ser_info.addr, addr_info->ser_info.len); head->addr.flag.sa_len = (addr_info->ser_info.len + PROTO_69845_EXT_LOGICAL_ADD_LEN); } head->addr.flag.sa_len--; head->addr.flag.sa_type = addr_info->ser_info.type; head->addr.sa_and_ca[head->addr.flag.sa_len + 1] = addr_info->cli_addr; cs_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN - PROTO_69845_START_LEN; cs = proto_fcs16_get_check_sum(data + 1, cs_len); data[cs_len + 1] = (cs & 0x00ff); data[cs_len + 2] = ((cs >> 8) & 0x00ff); ret = ERR_OK; out: return ret; } uint32_t proto_69845_tail_fill(proto_69845_frame_head_info_t *head, uint8_t *tail_data, uint16_t len) { uint8_t *ptr = tail_data; uint16_t cs_len, cs; uint32_t ret = ERR_FAIL; proto_69845_tailer_t *tail; if (len < sizeof(*tail)) { goto out; } /* fill 698.45 proto tailer */ tail = (proto_69845_tailer_t*)ptr; cs_len = head->len - PROTO_69845_CHECKSUM_LEN; cs = proto_fcs16_get_check_sum((uint8_t*)&head->len, cs_len); tail->fcs[0] = (cs & 0x00ff); tail->fcs[1] = ((cs >> 8) & 0x00ff); tail->end_char = PROTO_69845_END_BYTE; ret = ERR_OK; out: return ret; } uint32_t proto_69845_tail_fill_without_ts_fl( proto_69845_frame_head_info_t *head, uint8_t *tail_data, uint16_t len) { uint8_t *time_tag, *flw_rpt, *ptr = tail_data; uint16_t total_len; uint32_t ret = ERR_FAIL; if (head->ctrl.dir_prm == PROTO_69845_D_P_SERVER_REPORT || head->ctrl.dir_prm == PROTO_69845_D_P_SERVER_RESPONSE) { total_len = sizeof(proto_69845_tailer_t) + sizeof(*time_tag) + sizeof(*flw_rpt); } else { total_len = sizeof(proto_69845_tailer_t) + sizeof(*time_tag); } if (len < total_len) { goto out; } /* There is no time tag field, so time_tag is 0 */ time_tag = ptr; (*time_tag) = 0; ptr += sizeof(*time_tag); if (head->ctrl.dir_prm == PROTO_69845_D_P_SERVER_REPORT || head->ctrl.dir_prm == PROTO_69845_D_P_SERVER_RESPONSE) { /* There is no follow report data field, so flw_rpt is 0 */ flw_rpt = ptr; (*flw_rpt) = 0; ptr += sizeof(*flw_rpt); } /* fill 698.45 proto tailer */ proto_69845_tail_fill(head, ptr, sizeof(proto_69845_tailer_t)); out: return ret; } void proto_69845_add33_handle(uint8_t *ds, uint32_t size) { uint8_t *ptr = ds; while (size--) { (*ptr++) += 0x33; } return; } void proto_69845_sub33_handle(uint8_t *ds, uint32_t size) { uint8_t *ptr = ds; while (size--) { (*ptr++) -= 0x33; } return; } uint32_t proto_69845_get_apdu(proto_69845_frame_head_info_t *hdr, uint32_t len, apdu_info_t *apdu) { uint8_t *data = (uint8_t*)hdr; uint32_t head_len, total_len, min_len; uint32_t ret = ERR_OK; head_len = sizeof(*hdr) + hdr->addr.flag.sa_len \ + 1 + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; total_len = hdr->len + PROTO_69845_START_END_LEN; min_len = head_len + sizeof(proto_69845_tailer_t); if ((len < head_len) || (len < total_len) || (len < min_len)) { ret = ERR_FAIL; goto out; } if (hdr->ctrl.fragment != PROTO_69845_APDU_WHOLE) { ret = ERR_FAIL; goto out; } apdu->ptr = data + head_len; apdu->len = len - min_len; out: return ret; } uint32_t proto_69845_parse(uint8_t **data, uint32_t *len, proto_69845_frame_head_info_t **hdr, apdu_info_t *apdu_desc) { uint8_t *ds = *data, *sub_data = NULL; uint32_t len1 = *len, temp, offset, sub_len = 0; proto_69845_frame_head_info_t *hdr_temp; proto_69845_apdu_t *apdu; proto_69845_app_sec_req_resp_info_t *sec; proto_69845_app_len_descript_t *len_desc; hdr_temp = proto_69845_sanity_check(ds, (uint16_t)len1); if (hdr_temp == NULL) { goto err; } offset = (uint32_t)((uint8_t *)hdr_temp - ds); len1 -= offset; ds += offset; temp = sizeof(*hdr_temp) + sizeof(proto_69845_addr_t) + hdr_temp->addr.flag.sa_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; len1 -= temp; ds += temp; if (len1 < sizeof(proto_69845_tailer_t)) { goto err; } len1 -= sizeof(proto_69845_tailer_t); if (hdr_temp->ctrl.flag_scramble) { proto_69845_sub33_handle(ds, len1); sub_data = ds; sub_len = len1; } if (apdu_desc) { apdu_desc->ptr = ds; apdu_desc->len = len1; } if (len1 < sizeof(*apdu)) goto err; apdu = (proto_69845_apdu_t *)ds; switch (apdu->type) { case PROTO_69845_C_APP_SECURITY_REQ: case PROTO_69845_S_APP_SECURITY_RESP: { ds += sizeof(*apdu); len1 -= sizeof(*apdu); if (len1 < sizeof (*sec)) { goto err; } sec = (proto_69845_app_sec_req_resp_info_t*)ds; len1 -= sizeof (*sec); ds += sizeof (*sec); len_desc = (proto_69845_app_len_descript_t *)((uint8_t *)sec + 1); if (!len_desc->mub_flag) { ds = sec->data; temp = sec->len; } else if (len_desc->byte_num == 1) { if (len1 < 1) { goto err; } temp = sec->data[0]; ds = sec->data + 1; len1--; } else if (len_desc->byte_num == 2) { if (len1 < 2) { goto err; } temp = iot_bytes_to_uint16(sec->data, 1); ds = sec->data + 2; len1 -= 2; } else { goto err; } if (len1 < temp) { goto err; } len1 = temp; break; } default: break; } *data = ds; *len = len1; *hdr = hdr_temp; return ERR_OK; err: if (sub_data && sub_len) { proto_69845_add33_handle(sub_data, sub_len); } return ERR_FAIL; } iot_pkt_t *proto_69845_build_event_msg(uint8_t *addr) { uint8_t *data; uint32_t len; iot_pkt_t *pkt; proto_645_header_t *hdr; len = sizeof(*hdr) + PROTO_69845_EVENT_DATA_LEN + sizeof(proto_645_tailer_t); pkt = iot_pkt_alloc(len, IOT_SMART_GRID_MID); if (!pkt) { goto out; } data = (uint8_t*)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); hdr->len = PROTO_69845_EVENT_DATA_LEN; os_mem_cpy(hdr->data, proto_69845_event_report_data, PROTO_69845_EVENT_DATA_LEN); proto_645_tail_init(hdr); iot_pkt_put(pkt, len); out: return pkt; } uint32_t proto_69845_get_oad(uint8_t *data, uint32_t data_len, proto_69845_app_oad_t *oad) { uint32_t ret = ERR_FAIL; proto_69845_app_get_req_normal_t *req = (proto_69845_app_get_req_normal_t*)data; if (data_len < sizeof(*req)) { goto out; } oad->oi = proto_69845_byte_to_oi((uint8_t*)&req->oad.oi); oad->element_index = req->oad.element_index; oad->attribute_id = req->oad.attribute_id; oad->attribute_char = req->oad.attribute_char; ret = ERR_OK; out: return ret; } uint32_t proto_69845_get_omd(uint8_t *data, uint32_t data_len, proto_69845_app_omd_t *omd) { uint32_t ret = ERR_FAIL; proto_69845_app_action_req_single_t *req = (proto_69845_app_action_req_single_t*)data; if (data_len < sizeof(*req)) { goto out; } omd->oi = proto_69845_byte_to_oi((uint8_t*)&req->omd.oi); omd->method_id = req->omd.method_id; omd->operation_mode = req->omd.operation_mode; ret = ERR_OK; out: return ret; } static uint8_t proto_69845_get_data_len_type(uint8_t data_type) { uint8_t data_len_type = PROTO_69845_DATA_LEN_TYPE_UNKNOW; for (uint8_t i = 0; i < PROTO_69845_DATA_DESC_LIST_MAX; i++) { if (data_type == proto_69845_data_desc_list[i].type) { data_len_type = proto_69845_data_desc_list[i].len_type; break; } } return data_len_type; } uint32_t proto_69845_get_normal_data_len(uint8_t data_type) { uint32_t data_len = 0; for (uint8_t i = 0; i < PROTO_69845_DATA_DESC_LIST_MAX; i++) { if (data_type == proto_69845_data_desc_list[i].type) { data_len = proto_69845_data_desc_list[i].len; break; } } return data_len; } uint32_t proto_69845_get_div8_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *len_data; uint32_t ret = ERR_OK, len, bit_len = 0; proto_69845_app_len_descript_t *len_desc; if (rec_data_len < sizeof(*len_desc)) { goto drop; } len_desc = (proto_69845_app_len_descript_t *)data; if (!len_desc->mub_flag) { bit_len = data[0]; } else { if (rec_data_len < sizeof(*len_desc) + len_desc->byte_num) { goto drop; } len_data = data + sizeof(*len_desc); if (len_desc->byte_num == 1) { bit_len = len_data[0]; } else if (len_desc->byte_num == 2) { bit_len = iot_bytes_to_uint16(len_data, 1); } else { goto drop; } } len = bit_len / 8; if ((bit_len % 8) != 0) { len++; } len += sizeof(*len_desc); if (len_desc->mub_flag) { len += len_desc->byte_num; } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static uint32_t proto_69845_get_multi_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *len_data; uint32_t ret = ERR_OK, len = 0; proto_69845_app_len_descript_t *len_desc; if (rec_data_len < sizeof(*len_desc)) { goto drop; } len_desc = (proto_69845_app_len_descript_t *)data; if (!len_desc->mub_flag) { len = data[0]; } else { if (rec_data_len < sizeof(*len_desc) + len_desc->byte_num) { goto drop; } len_data = data + sizeof(*len_desc); if (len_desc->byte_num == 1) { len = len_data[0]; } else if (len_desc->byte_num == 2) { len = iot_bytes_to_uint16(len_data, 1); } else { goto drop; } } len += sizeof(*len_desc); if (len_desc->mub_flag) { len += len_desc->byte_num; } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } uint32_t proto_69845_get_road_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint32_t ret = ERR_OK, len; proto_69845_app_road_t *road_hdr; if (rec_data_len < sizeof(*road_hdr)) { goto drop; } road_hdr = (proto_69845_app_road_t*)data; len = proto_69845_get_normal_data_len(PROTO_69845_APP_DATA_OAD); len *= road_hdr->cnt; len += sizeof(*road_hdr); *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } uint32_t proto_69845_get_csd_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *ptr = (uint8_t*)data; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len; proto_69845_app_data_csd_t *csd_hdr; if (rec_len < sizeof(*csd_hdr)) { goto drop; } csd_hdr = (proto_69845_app_data_csd_t*)ptr; len = sizeof(*csd_hdr); ptr += sizeof(*csd_hdr); rec_len -= sizeof(*csd_hdr); switch (csd_hdr->type) { case PROTO_OI_CSD_TYPE_OAD: { len += proto_69845_get_normal_data_len(PROTO_69845_APP_DATA_OAD); break; } case PROTO_OI_CSD_TYPE_ROAD: { if (proto_69845_get_road_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } default: goto drop; } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } uint32_t proto_69845_get_rcsd_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *ptr = (uint8_t*)data, i; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len; proto_69845_app_data_rcsd_t *rcsd_hdr; if (rec_len < sizeof(*rcsd_hdr)) { goto drop; } rcsd_hdr = (proto_69845_app_data_rcsd_t*)ptr; len = sizeof(*rcsd_hdr); ptr += sizeof(*rcsd_hdr); rec_len -= sizeof(*rcsd_hdr); for (i = 0; i < rcsd_hdr->cnt; i++) { cache_len = 0; if (proto_69845_get_csd_data_len(ptr, rec_len, &cache_len)) { goto drop; } if (rec_len < cache_len) { goto drop; } len += cache_len; ptr += cache_len; rec_len -= cache_len; } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static uint32_t proto_69845_get_tsa_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint32_t ret = ERR_OK, len; proto_69845_app_data_tsa_t *tsa_hdr; if (rec_data_len < sizeof(*tsa_hdr)) { goto drop; } tsa_hdr = (proto_69845_app_data_tsa_t*)data; len = tsa_hdr->flag.sa_len + 1; len += sizeof(*tsa_hdr); *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static uint32_t proto_69845_get_ms_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *ptr = (uint8_t*)data, i; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len; proto_69845_app_data_ms_t *ms_hdr; proto_69845_app_data_ms_type_t *type_list_hdr; proto_69845_app_data_tsa_seq_t *tsa_list_hdr; if (rec_len < sizeof(*ms_hdr)) { goto drop; } ms_hdr = (proto_69845_app_data_ms_t*)ptr; len = sizeof(*ms_hdr); ptr += sizeof(*ms_hdr); rec_len -= sizeof(*ms_hdr); switch (ms_hdr->type) { case PROTO_OI_MS_TYPE_ALL_PM: { break; } case PROTO_OI_MS_TYPE_GROUP_PM_TYPE: { if (rec_len < sizeof(*type_list_hdr)) { goto drop; } type_list_hdr = (proto_69845_app_data_ms_type_t*)ptr; cache_len = type_list_hdr->cnt * sizeof(type_list_hdr->type_list[0]) + sizeof(*type_list_hdr); if (rec_len < cache_len) { goto drop; } len += cache_len; break; } case PROTO_OI_MS_TYPE_GROUP_PM_ADDR: { if (rec_len < sizeof(*tsa_list_hdr)) { goto drop; } tsa_list_hdr = (proto_69845_app_data_tsa_seq_t*)ptr; len += sizeof(*tsa_list_hdr); ptr += sizeof(*tsa_list_hdr); rec_len -= sizeof(*tsa_list_hdr); for (i = 0; i < tsa_list_hdr->cnt; i++) { cache_len = 0; if (proto_69845_get_tsa_data_len(ptr, rec_len, &cache_len)) { goto drop; } if (rec_len < cache_len) { goto drop; } len += cache_len; ptr += cache_len; rec_len -= cache_len; } break; } default: goto drop; } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static uint32_t proto_69845_get_rsd_type_2_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *ptr = (uint8_t*)data, data_len_type; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len; proto_69845_app_data_rsd_type2_t *rsd_type2_hdr; proto_69845_app_data_t *data_hdr; if (rec_len < sizeof(*rsd_type2_hdr)) { goto drop; } rsd_type2_hdr = (proto_69845_app_data_rsd_type2_t*)ptr; len = sizeof(*rsd_type2_hdr); ptr += sizeof(*rsd_type2_hdr); rec_len -= sizeof(*rsd_type2_hdr); for (uint8_t i = 0; i < PROTO_OI_RSD_TYPE_2_DATA_CNT; i++) { if (rec_len < sizeof(*data_hdr)) { goto drop; } data_hdr = (proto_69845_app_data_t*)ptr; len += sizeof(*data_hdr); ptr += sizeof(*data_hdr); rec_len -= sizeof(*data_hdr); data_len_type = proto_69845_get_data_len_type(data_hdr->data_type); if (data_len_type != PROTO_69845_DATA_LEN_TYPE_NORMAL) { goto drop; } cache_len = proto_69845_get_normal_data_len(data_hdr->data_type); if (rec_len < cache_len) { goto drop; } len += cache_len; ptr += cache_len; rec_len -= cache_len; } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static uint32_t proto_69845_get_rsd_type_678_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *ptr = (uint8_t*)data; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len; proto_69845_app_data_rsd_type678_t *rsd_hdr; if (rec_len < sizeof(*rsd_hdr)) { goto drop; } rsd_hdr = (proto_69845_app_data_rsd_type678_t*)ptr; len = sizeof(rsd_hdr->start_time) + sizeof(rsd_hdr->end_time) + sizeof(rsd_hdr->ti); ptr = (uint8_t*)&rsd_hdr->meter_set; rec_len = rec_len - len; if (proto_69845_get_ms_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static uint32_t proto_69845_get_rsd_type_10_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *ptr = (uint8_t*)data; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len; proto_69845_app_data_rsd_type10_t *rsd_hdr; if (rec_len < sizeof(*rsd_hdr)) { goto drop; } rsd_hdr = (proto_69845_app_data_rsd_type10_t*)ptr; len = sizeof(rsd_hdr->record_num); ptr = (uint8_t*)&rsd_hdr->meter_set; rec_len = rec_len - len; if (proto_69845_get_ms_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } uint32_t proto_69845_get_rsd_data_len(uint8_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *ptr = (uint8_t*)data; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len; proto_69845_app_data_rsd_t *rsd_hdr; if (rec_len < sizeof(*rsd_hdr)) { goto drop; } rsd_hdr = (proto_69845_app_data_rsd_t*)ptr; len = sizeof(*rsd_hdr); ptr += sizeof(*rsd_hdr); rec_len -= sizeof(*rsd_hdr); switch (rsd_hdr->type) { case PROTO_OI_RSD_TYPE_2: { cache_len = 0; if (proto_69845_get_rsd_type_2_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_OI_RSD_TYPE_6: case PROTO_OI_RSD_TYPE_7: case PROTO_OI_RSD_TYPE_8: { cache_len = 0; if (proto_69845_get_rsd_type_678_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_OI_RSD_TYPE_9: { len += 1; break; } case PROTO_OI_RSD_TYPE_10: { cache_len = 0; if (proto_69845_get_rsd_type_10_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } default: goto drop; } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static uint32_t proto_69845_get_base_data_len(proto_69845_app_data_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t *ptr = (uint8_t*)data, data_len_type; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len = 0; if (rec_len < sizeof(*data)) { goto drop; } ptr += sizeof(*data); rec_len -= sizeof(*data); len = sizeof(*data); data_len_type = proto_69845_get_data_len_type(data->data_type); switch (data_len_type){ case PROTO_69845_DATA_LEN_TYPE_NORMAL: { len += proto_69845_get_normal_data_len(data->data_type); break; } case PROTO_69845_DATA_LEN_TYPE_ROAD: { if (proto_69845_get_road_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_69845_DATA_LEN_TYPE_TSA: { if (proto_69845_get_tsa_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_69845_DATA_LEN_TYPE_RSD: { if (proto_69845_get_rsd_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_69845_DATA_LEN_TYPE_CSD: { if (proto_69845_get_csd_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_69845_DATA_LEN_TYPE_MS: { if (proto_69845_get_ms_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_69845_DATA_LEN_TYPE_RCSD: { if (proto_69845_get_rcsd_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_69845_DATA_LEN_TYPE_DIV8: { if (proto_69845_get_div8_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_69845_DATA_LEN_TYPE_MULTI_BTYE: { if (proto_69845_get_multi_data_len(ptr, rec_len, &cache_len)) { goto drop; } len += cache_len; break; } case PROTO_69845_DATA_LEN_TYPE_UNKNOW: default: goto drop; } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static uint32_t proto_69845_get_element_data_len(proto_69845_app_ele_data_t *data, uint32_t rec_data_len, uint32_t *data_len, uint8_t recursion_cnt) { uint8_t *ptr = (uint8_t*)data, data_len_type; uint8_t i; uint8_t cnt; uint32_t ret = ERR_OK, rec_len = rec_data_len, len, cache_len; proto_69845_app_ele_data_t *element_hdr; proto_69845_app_data_t *base_data_hdr; if (rec_len < sizeof(*data)) { goto drop; } ptr += sizeof(*data); rec_len -= sizeof(*data); len = sizeof(*data); cnt = data->num_of_data; for (i = 0; i < cnt; i++) { if (rec_len < sizeof(*base_data_hdr)) { goto drop; } base_data_hdr = (proto_69845_app_data_t*)ptr; data_len_type = proto_69845_get_data_len_type(base_data_hdr->data_type); if (data_len_type == PROTO_69845_DATA_LEN_TYPE_ELEMENT) { if (!recursion_cnt) { goto drop; } if (rec_len < sizeof(*element_hdr)) { goto drop; } element_hdr = (proto_69845_app_ele_data_t*)base_data_hdr; cache_len = 0; if (proto_69845_get_element_data_len(element_hdr, rec_len, &cache_len, (recursion_cnt - 1))) { goto drop; } if (rec_len < cache_len) { goto drop; } ptr += cache_len; rec_len -= cache_len; len += cache_len; } else { cache_len = 0; if (proto_69845_get_base_data_len(base_data_hdr, rec_data_len, &cache_len)) { goto drop; } if (rec_len < cache_len) { goto drop; } ptr += cache_len; rec_len -= cache_len; len += cache_len; } } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } uint32_t proto_69845_get_data_len(proto_69845_app_data_t *data, uint32_t rec_data_len, uint32_t *data_len) { uint8_t data_len_type; uint32_t ret = ERR_OK, len = 0; proto_69845_app_ele_data_t *element_hdr; if (!rec_data_len || !data) { goto drop; } data_len_type = proto_69845_get_data_len_type(data->data_type); if (data_len_type == PROTO_69845_DATA_LEN_TYPE_ELEMENT) { element_hdr = (proto_69845_app_ele_data_t*)data; if (proto_69845_get_element_data_len(element_hdr, rec_data_len, &len, PROTO_69845_ELEMENT_DATA_RECURSION_CNT_MAX)) { goto drop; } } else { if (proto_69845_get_base_data_len(data, rec_data_len, &len)) { goto drop; } } *data_len = len; goto out; drop: ret = ERR_FAIL; out: return ret; } static iot_pkt_t *proto_69845_get_rpt_noti_rcsd() { uint8_t i = 0, *data = NULL, oad_cnt = 0; uint16_t rcsd_len = 0; iot_pkt_t *pkt = NULL; proto_69845_app_data_rcsd_t *p_rcsd; proto_69845_app_data_csd_t *p_csd; proto_69845_app_oad_t* p_oad; const uint16_t evt_oi[] = { PROTO_69845_APP_OI_EVENT_REC_SEQ, PROTO_69845_APP_OI_EVENT_START_TM, PROTO_69845_APP_OI_EVENT_END_TM, PROTO_69845_APP_OI_EVENT_OCCUR_SOURCE, PROTO_69845_APP_OI_EVENT_RPT_STA}; oad_cnt = sizeof(evt_oi)/sizeof(evt_oi[0]); rcsd_len = sizeof(proto_69845_app_data_rcsd_t) + (sizeof(proto_69845_app_data_csd_t) + sizeof(proto_69845_app_oad_t)) * oad_cnt; pkt = iot_pkt_alloc(rcsd_len, IOT_SMART_GRID_MID); if (!pkt) { goto out; } p_rcsd = (proto_69845_app_data_rcsd_t *)iot_pkt_data(pkt); p_rcsd->cnt = oad_cnt; data = (uint8_t*)p_rcsd->csd_list; for (i = 0; i < p_rcsd->cnt; i++) { p_csd = (proto_69845_app_data_csd_t*)data; p_csd->type = 0; p_oad = (proto_69845_app_oad_t*)(p_csd->csd_data); proto_69845_oi_to_byte(evt_oi[i], (uint8_t*)&p_oad->oi); p_oad->attribute_id = 2; p_oad->attribute_char = 0; p_oad->element_index = 0; data += sizeof(proto_69845_app_data_csd_t) + sizeof(proto_69845_app_oad_t); } iot_pkt_put(pkt, rcsd_len); out: return pkt; } static iot_pkt_t *proto_69845_get_rpt_noti_ele( proto_69845_app_data_time_s_t *evt_start_tm, proto_69845_app_data_time_s_t *evt_end_tm, rpt_status_t *rpt_status) { uint16_t evt_unit_len = 0; proto_69845_app_norm_evt_unit_t *evt_unit; proto_69845_app_unrecover_evt_unit_t *evt_unit_ab; iot_pkt_t *pkt = NULL; /* there is power off and power on record */ if (rpt_status->pf_rpt && rpt_status->po_rpt) { evt_unit_len = sizeof(proto_69845_app_norm_evt_unit_t); pkt = iot_pkt_alloc(evt_unit_len, IOT_SMART_GRID_MID); if (!pkt) { goto out; } evt_unit = (proto_69845_app_norm_evt_unit_t *) iot_pkt_put(pkt, evt_unit_len); evt_unit->data0_type = PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED; iot_uint32_to_bytes(0x01, (uint8_t *)&evt_unit->evt_seq, 1); evt_unit->data1_type = PROTO_69845_APP_DATA_TIME_S; os_mem_cpy(&evt_unit->evt_start_time, (uint8_t *)evt_start_tm, sizeof(proto_69845_app_data_time_s_t)); evt_unit->data2_type = PROTO_69845_APP_DATA_TIME_S; os_mem_cpy(&evt_unit->evt_end_time, (uint8_t *)evt_end_tm, sizeof(proto_69845_app_data_time_s_t)); evt_unit->data3_type = PROTO_69845_APP_DATA_ENUM; evt_unit->evt_soc = PROTO_69845_APP_EVT_SOC_485_FALT; evt_unit->data4_type = PROTO_69845_APP_DATA_ARRAY; evt_unit->channel_cnt = 1; evt_unit->data5_type = PROTO_69845_APP_DATA_STRUCTURE; evt_unit->member_cnt = 2; evt_unit->data6_type = PROTO_69845_APP_DATA_OAD; proto_69845_oi_to_byte(PROTO_69845_APP_OI_PLC_WIRELESS_INTERFACE, (uint8_t*)&evt_unit->channel_oad.oi); evt_unit->channel_oad.attribute_id = 2; evt_unit->channel_oad.attribute_char = 0; evt_unit->channel_oad.element_index = 1; evt_unit->data7_type = PROTO_69845_APP_DATA_UNSIGNED; evt_unit->pf_rpt = rpt_status->pf_rpt; evt_unit->pf_rpt_ok = rpt_status->pf_rpt_ok; evt_unit->po_rpt = rpt_status->po_rpt; evt_unit->po_rpt_ok = rpt_status->po_rpt_ok; /* there is power off record, not power on record */ } else if (rpt_status->pf_rpt && !rpt_status->po_rpt) { evt_unit_len = sizeof(proto_69845_app_unrecover_evt_unit_t); pkt = iot_pkt_alloc(evt_unit_len, IOT_SMART_GRID_MID); if (!pkt) { goto out; } evt_unit_ab = (proto_69845_app_unrecover_evt_unit_t *) iot_pkt_put(pkt, evt_unit_len); evt_unit_ab->data0_type = PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED; iot_uint32_to_bytes(0x01, (uint8_t *)&evt_unit_ab->evt_seq, 1); evt_unit_ab->data1_type = PROTO_69845_APP_DATA_TIME_S; os_mem_cpy(&evt_unit_ab->evt_start_time, (uint8_t *)evt_start_tm, sizeof(proto_69845_app_data_time_s_t)); evt_unit_ab->data2_type = 0; evt_unit_ab->data3_type = PROTO_69845_APP_DATA_ENUM; evt_unit_ab->evt_soc = PROTO_69845_APP_EVT_SOC_485_FALT; evt_unit_ab->data4_type = PROTO_69845_APP_DATA_ARRAY; evt_unit_ab->channel_cnt = 1; evt_unit_ab->data5_type = PROTO_69845_APP_DATA_STRUCTURE; evt_unit_ab->member_cnt = 2; evt_unit_ab->data6_type = PROTO_69845_APP_DATA_OAD; proto_69845_oi_to_byte(PROTO_69845_APP_OI_PLC_WIRELESS_INTERFACE, (uint8_t*)&evt_unit_ab->channel_oad.oi); evt_unit_ab->channel_oad.attribute_id = 2; evt_unit_ab->channel_oad.attribute_char = 0; evt_unit_ab->channel_oad.element_index = 1; evt_unit_ab->data7_type = PROTO_69845_APP_DATA_UNSIGNED; evt_unit_ab->pf_rpt = rpt_status->pf_rpt; evt_unit_ab->pf_rpt_ok = rpt_status->pf_rpt_ok; evt_unit_ab->po_rpt = rpt_status->po_rpt; evt_unit_ab->po_rpt_ok = rpt_status->po_rpt_ok; /* only exist last two case when actively report pof event */ } out: return pkt; } iot_pkt_t *proto_69845_build_rpt_noti_sus_pof_msg( proto_69845_app_rpt_noti_info_t* noti_info, const server_addr_info_t* server_info, proto_69845_app_data_time_s_t *evt_start_tm, proto_69845_app_data_time_s_t *evt_end_tm, rpt_status_t *rpt_status) { iot_pkt_t *pkt = NULL, *rcsd_pkt = NULL, *ele_pkt = NULL; uint8_t *data, ser_len; uint16_t length, rcsd_len = 0, ele_load_len = 0; uint16_t head_len, tail_len; addr_info_t addr_info = { 0 }; proto_69845_frame_head_info_t *head; proto_69845_app_noti_resp_t *noti; proto_69845_app_rpt_noti_t *rpt_noti; proto_69845_app_rpt_record_list_t *record_list; proto_69845_app_rpt_result_record_t *result_record; proto_69845_app_rpt_noti_result_t *noti_result; proto_69845_app_rpt_record_row_t *record_row; if (noti_info == NULL || server_info == NULL) { goto drop; } ser_len = proto_69845_server_len_calc(server_info); if (ser_len > PROTO_69845_SA_MAX_LEN || !ser_len) { goto drop; } length = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + PROTO_69845_NO_TIME_TAG_LEN + PROTO_69845_NO_FLW_DATA_LEN + sizeof(proto_69845_tailer_t); rcsd_pkt = proto_69845_get_rpt_noti_rcsd(); if(!rcsd_pkt) goto drop; rcsd_len = (uint16_t)iot_pkt_data_len(rcsd_pkt); ele_pkt = proto_69845_get_rpt_noti_ele(evt_start_tm, evt_end_tm, rpt_status); if(!ele_pkt) goto drop; ele_load_len = (uint16_t)iot_pkt_data_len(ele_pkt); switch (noti_info->type) { case PROTO_69845_APP_REPRORT_RECORDLIST: { length = length + sizeof(*noti) + sizeof(*rpt_noti) + sizeof(*record_list) + sizeof(*result_record) + sizeof(*noti_result) + sizeof(*record_row) + rcsd_len + ele_load_len - sizeof(proto_69845_app_data_rcsd_t); break; } default: goto drop; } pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) goto drop; /* fill 698.45 proto header */ data = iot_pkt_data(pkt); head = (proto_69845_frame_head_info_t *)data; addr_info.ser_info = *server_info; addr_info.cli_addr = PROTO_69845_CA_INVAILD_ADD; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, length, &addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_SERVER_REPORT); data += head_len; /* fill apdu data */ noti = (proto_69845_app_noti_resp_t*)data; noti->type = PROTO_69845_S_APP_REPORT_NOTI; rpt_noti = (proto_69845_app_rpt_noti_t*)noti->data; rpt_noti->data_type = noti_info->type; data = data + sizeof(proto_69845_app_noti_resp_t) + sizeof(proto_69845_app_rpt_noti_t); switch (rpt_noti->data_type) { case PROTO_69845_APP_REPRORT_RECORDLIST: { record_list = (proto_69845_app_rpt_record_list_t*)rpt_noti->data; record_list->piid_acd = noti_info->piid_acd; record_list->att_cnt = 1; data += sizeof(proto_69845_app_rpt_record_list_t); result_record = (proto_69845_app_rpt_result_record_t*)data; proto_69845_oi_to_byte(noti_info->oad.oi, (uint8_t*)&result_record->oad.oi); result_record->oad.attribute_id = noti_info->oad.attribute_id; result_record->oad.attribute_char = noti_info->oad.attribute_char; result_record->oad.element_index = noti_info->oad.element_index; os_mem_cpy(&result_record->rcsd, iot_pkt_data(rcsd_pkt), rcsd_len); data = data + sizeof(proto_69845_app_rpt_result_record_t) + rcsd_len - sizeof(proto_69845_app_data_rcsd_t); noti_result = (proto_69845_app_rpt_noti_result_t *)data; noti_result->type = PROTO_69845_APP_RPT_RESULT_DATA; data += sizeof(proto_69845_app_rpt_noti_result_t); record_row = (proto_69845_app_rpt_record_row_t *)data; record_row->record_num = 1; os_mem_cpy(record_row->data, iot_pkt_data(ele_pkt), ele_load_len); data = data + sizeof(proto_69845_app_rpt_record_row_t) + ele_load_len; break; } default: goto drop; } tail_len = PROTO_69845_NO_TIME_TAG_LEN + PROTO_69845_NO_FLW_DATA_LEN + sizeof(proto_69845_tailer_t); proto_69845_tail_fill_without_ts_fl(head, data, tail_len); iot_pkt_put(pkt, head->len + PROTO_69845_START_END_LEN); goto out; drop: if (pkt) { iot_pkt_free(pkt); pkt = NULL; } out: if (rcsd_pkt) { iot_pkt_free(rcsd_pkt); } if (ele_pkt) { iot_pkt_free(ele_pkt); } return pkt; } iot_pkt_t *proto_69845_build_rpt_noti_list_msg( uint8_t* result_list, uint16_t list_len, uint8_t list_cnt, const server_addr_info_t* server_info, uint8_t sn) { iot_pkt_t *pkt = NULL; uint8_t *data, ser_len; uint16_t length; uint16_t head_len, tail_len; addr_info_t addr_info = { 0 }; proto_69845_frame_head_info_t *head; proto_69845_app_noti_resp_t *noti; proto_69845_app_rpt_noti_t *rpt_noti; proto_69845_app_rpt_nor_list_t *nor_list; if (server_info == NULL) { goto out; } ser_len = proto_69845_server_len_calc(server_info); if (ser_len > PROTO_69845_SA_MAX_LEN || !ser_len) { goto out; } length = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + PROTO_69845_NO_TIME_TAG_LEN + PROTO_69845_NO_FLW_DATA_LEN + sizeof(proto_69845_tailer_t) + sizeof(*noti) + sizeof(*rpt_noti) + sizeof(*nor_list) + list_len; pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) { goto out; } /* fill 698.45 proto header */ data = iot_pkt_data(pkt); head = (proto_69845_frame_head_info_t *)data; addr_info.ser_info = *server_info; addr_info.cli_addr = PROTO_69845_CA_INVAILD_ADD; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, length, &addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_SERVER_REPORT); data += head_len; /* fill apdu data */ noti = (proto_69845_app_noti_resp_t*)data; noti->type = PROTO_69845_S_APP_REPORT_NOTI; rpt_noti = (proto_69845_app_rpt_noti_t*)noti->data; rpt_noti->data_type = PROTO_69845_APP_REPRORT_NORMALLIST; nor_list = (proto_69845_app_rpt_nor_list_t*)rpt_noti->data; nor_list->piid_acd.sn = sn; nor_list->piid_acd.priority = PROTO_69845_APP_PIID_PRIORITY_GENERAL; nor_list->piid_acd.acd = 0; nor_list->att_cnt = list_cnt; os_mem_cpy(nor_list->data, result_list, list_len); data = data + sizeof(*noti) + sizeof(*rpt_noti) + sizeof(*nor_list) + list_len; tail_len = PROTO_69845_NO_TIME_TAG_LEN + PROTO_69845_NO_FLW_DATA_LEN + sizeof(proto_69845_tailer_t); proto_69845_tail_fill_without_ts_fl(head, data, tail_len); iot_pkt_put(pkt, head->len + PROTO_69845_START_END_LEN); out: return pkt; } void proto_69845_check_frame_handler(uint8_t* buffer, uint32_t buffer_len, bool_t* is_frame) { proto_69845_frame_head_info_t *head; do { if (buffer_len < sizeof(proto_69845_frame_head_info_t)) { *is_frame = false; break; } head = (proto_69845_frame_head_info_t*)buffer; if ((uint16_t)buffer_len != (head->len + PROTO_69845_START_END_LEN)) { *is_frame = false; break; } if (buffer[0] != PROTO_69845_START_BYTE || buffer[head->len + 1] != PROTO_69845_END_BYTE) { *is_frame = false; break; } /* 698.45 frame check sum */ if (proto_fcs16_check(buffer + 1, head->len)) { *is_frame = false; break; } *is_frame = true; } while(0); } proto_69845_app_data_time_s_t *proto_69845_get_time_rsp_msg_handle( uint8_t *data, uint16_t len) { uint32_t ret, data_len; proto_69845_frame_head_info_t *hdr_698; proto_69845_app_req_resp_t *resp; proto_69845_app_get_resp_t *get_resp; proto_69845_app_get_resp_normal_t *resp_normal; proto_69845_app_data_time_s_t *time = NULL; proto_69845_app_data_t *app_data; apdu_info_t apdu; hdr_698 = proto_69845_sanity_check(data, len); if (!hdr_698) { goto out; } if ((hdr_698->ctrl.dir_prm != PROTO_69845_D_P_SERVER_RESPONSE) && (hdr_698->ctrl.dir_prm != PROTO_69845_D_P_SERVER_REPORT)) { goto out; } ret = proto_69845_get_apdu(hdr_698, len, &apdu); if (ret != ERR_OK) { goto out; } data_len = sizeof(*resp) + sizeof(*get_resp) + sizeof(*resp_normal) + sizeof(*app_data) + sizeof(*time); if (apdu.len < data_len) { goto out; } resp = (proto_69845_app_req_resp_t*)(apdu.ptr); if (resp->type == PROTO_69845_S_APP_GET_RESP) { get_resp = (proto_69845_app_get_resp_t *)resp->data; if (get_resp->data_type == PROTO_69845_APP_GET_NORMAL) { resp_normal = (proto_69845_app_get_resp_normal_t *)get_resp->data; if ((proto_69845_byte_to_oi((uint8_t *)&resp_normal->oad.oi) == PROTO_69845_APP_OI_TIME) && (resp_normal->oad.attribute_id == 2) && (resp_normal->result_type == PROTO_69845_APP_GET_RESULT_DATA)) { app_data = (proto_69845_app_data_t*)resp_normal->result; if (app_data->data_type == PROTO_69845_APP_DATA_TIME_S) { time = (proto_69845_app_data_time_s_t *)app_data->data; } } } } out: return time; } uint64_t proto_69845_ti_data_to_sec(proto_69845_app_data_ti_t *ti) { uint64_t uint = 0; switch (ti->uint) { case PROTO_OI_TI_INTERVAL_UNIT_TYPE_SEC: { uint = PROTO_OI_TI_INTERVAL_UNIT_SEC; break; } case PROTO_OI_TI_INTERVAL_UNIT_TYPE_MIN: { uint = PROTO_OI_TI_INTERVAL_UNIT_MIN; break; } case PROTO_OI_TI_INTERVAL_UNIT_TYPE_HOUR: { uint = PROTO_OI_TI_INTERVAL_UNIT_HOUR; break; } case PROTO_OI_TI_INTERVAL_UNIT_TYPE_DAY: { uint = PROTO_OI_TI_INTERVAL_UNIT_DAY; break; } case PROTO_OI_TI_INTERVAL_UNIT_TYPE_MON: { uint = PROTO_OI_TI_INTERVAL_UNIT_MON; break; } case PROTO_OI_TI_INTERVAL_UNIT_TYPE_YEAR: { uint = PROTO_OI_TI_INTERVAL_UNIT_YEAR; break; } default: break; } return (uint * ti->value); } uint32_t proto_69845_apdu_sec_ciphertext_check(uint8_t *apdu, uint32_t len) { uint32_t ret = ERR_FAIL; proto_69845_app_req_resp_t *req; proto_69845_app_sec_req_resp_info_t *req_info; if (len < (sizeof(*req) + sizeof(*req_info))) { goto out; } req = (proto_69845_app_req_resp_t*)apdu; if (req->type != PROTO_69845_C_APP_SECURITY_REQ && req->type != PROTO_69845_S_APP_SECURITY_RESP) { goto out; } req_info = (proto_69845_app_sec_req_resp_info_t*)req->data; if (req_info->type != PROTO_69845_SEC_DATA_TYPE_CIPHERTEXT) { goto out; } ret = ERR_OK; out: return ret; } uint32_t proto_69845_corr_msg_check(uint8_t *data, uint32_t len, uint8_t *addr) { uint32_t ret = ERR_INVAL; uint16_t oi; proto_69845_frame_head_info_t *hdr_698 = NULL; proto_69845_apdu_t *apdu_hdr; proto_69845_app_action_req_t *req_hdr; proto_69845_app_action_req_single_t *action_hdr; apdu_info_t apdu = { 0 }; addr_info_t addr_info = {0}; if (!data || !len || !addr) { goto out; } if (proto_69845_parse(&data, &len, &hdr_698, &apdu) != ERR_OK) { goto out; } if (apdu.len < (sizeof(*apdu_hdr) + sizeof(*req_hdr) + sizeof(*action_hdr) + sizeof(proto_69845_app_data_time_s_t))) { goto out; } proto_69845_oi_to_byte(PROTO_69845_APP_OI_TIME, (uint8_t*)&oi); apdu_hdr = (proto_69845_apdu_t*)apdu.ptr; req_hdr = (proto_69845_app_action_req_t*)apdu_hdr->data; action_hdr = (proto_69845_app_action_req_single_t*)req_hdr->data; if (apdu_hdr->type != PROTO_69845_C_APP_ACTION_REQ || req_hdr->data_type != PROTO_69845_APP_ACTION_NORMAL || action_hdr->omd.oi != oi || action_hdr->omd.method_id != PROTO_OMD_CORRECT_TIME_METHOD_ID || action_hdr->data.data_type != PROTO_69845_APP_DATA_TIME_S) { goto out; } proto_69845_get_addr_info(hdr_698, &addr_info); if (addr_info.ser_info.type == PROTO_69845_SA_TYPE_SIG) { if (addr_info.ser_info.len != IOT_MAC_ADDR_LEN) { goto out; } iot_mac_addr_cpy(addr, addr_info.ser_info.addr); } else if (hdr_698->addr.flag.sa_type == PROTO_69845_SA_TYPE_BROADCAST) { os_mem_set(addr, 0xAA, IOT_MAC_ADDR_LEN); } else { goto out; } ret = ERR_OK; out: if (hdr_698 && hdr_698->ctrl.flag_scramble) { /* the message is forwarded after recovery */ proto_69845_add33_handle(apdu.ptr, apdu.len); } return ret; } #if PLC_SUPPORT_STA_ROLE iot_pkt_t *proto_69845_build_get_req_msg( proto_69845_app_get_req_info_t* req_info, const server_addr_info_t* server_info) { iot_pkt_t *pkt = NULL; uint8_t *data, ser_len; uint16_t length, head_len, tail_len; addr_info_t addr_info = { 0 }; proto_69845_frame_head_info_t *head; proto_69845_app_req_resp_t *req; proto_69845_app_get_req_t *get_req; proto_69845_app_get_req_normal_t *get_req_normal; if (req_info == NULL || server_info == NULL) { goto out; } ser_len = proto_69845_server_len_calc(server_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } length = PROTO_69845_PREAMBLE_LEN + sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + PROTO_69845_NO_TIME_TAG_LEN + sizeof(proto_69845_tailer_t); switch (req_info->type) { case PROTO_69845_APP_GET_NORMAL: length = length + sizeof(*req) + sizeof(*get_req) + sizeof(*get_req_normal); break; default: goto out; } pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) goto out; iot_pkt_reserve(pkt, PROTO_69845_PREAMBLE_LEN); /* fill 698.45 proto header */ data = iot_pkt_data(pkt); head = (proto_69845_frame_head_info_t *)data; addr_info.ser_info = *server_info; addr_info.cli_addr = PROTO_69845_CA_INVAILD_ADD; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, length - PROTO_69845_PREAMBLE_LEN, &addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_CLIENT_REQUEST); data += head_len; /* fill apdu data */ req = (proto_69845_app_req_resp_t*)data; req->type = PROTO_69845_C_APP_GET_REQ; get_req = (proto_69845_app_get_req_t*)req->data; get_req->data_type = req_info->type; data = data + sizeof(proto_69845_app_req_resp_t) + sizeof(proto_69845_app_get_req_t); switch (get_req->data_type) { case PROTO_69845_APP_GET_NORMAL: get_req_normal = (proto_69845_app_get_req_normal_t*)get_req->data; get_req_normal->piid = req_info->piid; proto_69845_oi_to_byte(req_info->oad.oi, (uint8_t*)&get_req_normal->oad.oi); get_req_normal->oad.attribute_id = req_info->oad.attribute_id; get_req_normal->oad.attribute_char = req_info->oad.attribute_char; get_req_normal->oad.element_index = req_info->oad.element_index; data += sizeof(proto_69845_app_get_req_normal_t); break; default: IOT_ASSERT(0); } tail_len = PROTO_69845_NO_TIME_TAG_LEN + sizeof(proto_69845_tailer_t); proto_69845_tail_fill_without_ts_fl(head, data, tail_len); iot_pkt_put(pkt, head->len + PROTO_69845_START_END_LEN); out: return pkt; } iot_pkt_t *proto_69845_build_get_req_msg_with_rn( proto_69845_app_get_list_req_info_t* req_info, const server_addr_info_t* server_info) { iot_pkt_t *pkt = NULL; uint8_t *data, *time_tag; uint8_t plaintext_len, ser_len; uint16_t length, head_len; addr_info_t addr_info = { 0 }; proto_69845_frame_head_info_t *head; proto_69845_app_sec_req_resp_info_t *sec_req; proto_69845_app_req_resp_t *req; proto_69845_app_get_req_t *get_req; proto_69845_app_get_req_normal_list_t *get_req_normal; proto_69845_app_sec_req_resp_vali_info_t *vali_data; proto_69845_app_sec_rn_info_t *rn; if (req_info == NULL || server_info == NULL) { goto out; } ser_len = proto_69845_server_len_calc(server_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } length = PROTO_69845_PREAMBLE_LEN + sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + sizeof(*req) + sizeof(*sec_req) + sizeof(*vali_data) + sizeof(*rn) + PROTO_69845_SECURITY_RN_LEN + sizeof(proto_69845_tailer_t); switch (req_info->type) { case PROTO_69845_APP_GET_NORMALLIST: plaintext_len = sizeof(*req) + sizeof(*get_req) + sizeof(*get_req_normal) + sizeof(proto_69845_app_oad_t) * req_info->oad_cnt + PROTO_69845_NO_TIME_TAG_LEN; break; default: goto out; } length += plaintext_len; pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) goto out; iot_pkt_reserve(pkt, PROTO_69845_PREAMBLE_LEN); /* fill 698.45 proto header */ data = iot_pkt_data(pkt); head = (proto_69845_frame_head_info_t *)data; addr_info.ser_info = *server_info; addr_info.cli_addr = PROTO_69845_CA_INVAILD_ADD; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, length - PROTO_69845_PREAMBLE_LEN, &addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_CLIENT_REQUEST); data += head_len; /* fill security request */ req = (proto_69845_app_req_resp_t*)data; req->type = PROTO_69845_C_APP_SECURITY_REQ; sec_req = (proto_69845_app_sec_req_resp_info_t*)req->data; sec_req->type = PROTO_69845_SEC_DATA_TYPE_PLAINTEXT; sec_req->len = plaintext_len; data = data + sizeof(proto_69845_app_req_resp_t) + sizeof(proto_69845_app_sec_req_resp_info_t); /* fill plaintext apdu data */ req = (proto_69845_app_req_resp_t*)sec_req->data; req->type = PROTO_69845_C_APP_GET_REQ; get_req = (proto_69845_app_get_req_t*)req->data; get_req->data_type = req_info->type; data = data + sizeof(proto_69845_app_req_resp_t) + sizeof(proto_69845_app_get_req_t); switch (get_req->data_type) { case PROTO_69845_APP_GET_NORMALLIST: { get_req_normal = (proto_69845_app_get_req_normal_list_t*)get_req->data; get_req_normal->piid = req_info->piid; get_req_normal->oad_cnt = req_info->oad_cnt; data += sizeof(proto_69845_app_get_req_normal_list_t); for (uint8_t i = 0; i < req_info->oad_cnt; i++) { proto_69845_oi_to_byte(req_info->oad[i].oi, (uint8_t*)&get_req_normal->oad[i].oi); get_req_normal->oad[i].attribute_id = req_info->oad[i].attribute_id; get_req_normal->oad[i].attribute_char = req_info->oad[i].attribute_char; get_req_normal->oad[i].element_index = req_info->oad[i].element_index; data += sizeof(proto_69845_app_oad_t); } break; } default: IOT_ASSERT(0); } /* There is no time tag field, so time_tag is 0 */ time_tag = data; (*time_tag) = 0; data += 1; /* fill 698.45 proto security validation data */ vali_data = (proto_69845_app_sec_req_resp_vali_info_t*)data; vali_data->type = PROTO_69845_SEC_REQ_VALI_TYPE_RN; rn = (proto_69845_app_sec_rn_info_t*)vali_data->data; rn->len = PROTO_69845_SECURITY_RN_LEN; os_mem_cpy(rn->data, proto_69845_rn, PROTO_69845_SECURITY_RN_LEN); data = data + sizeof(proto_69845_app_sec_req_resp_vali_info_t) + sizeof(proto_69845_app_sec_rn_info_t) + PROTO_69845_SECURITY_RN_LEN; /* fill 698.45 proto tailer */ proto_69845_tail_fill(head, data, sizeof(proto_69845_tailer_t)); iot_pkt_put(pkt, head->len + PROTO_69845_START_END_LEN); out: return pkt; } iot_pkt_t *proto_69845_build_action_req_single_msg( const proto_69845_app_action_req_single_t *req_info, uint16_t app_data_len, const server_addr_info_t* server_info) { iot_pkt_t *pkt = NULL; proto_69845_frame_head_info_t *head; proto_69845_app_req_resp_t *apdu_head; proto_69845_app_action_req_single_t *src_req_info; proto_69845_app_action_req_t *req; uint8_t ser_len; uint16_t length, head_len; uint8_t *data, *time_tag; addr_info_t addr_info = { 0 }; if (req_info == NULL || server_info == NULL) { goto out; } ser_len = proto_69845_server_len_calc(server_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } length = PROTO_69845_PREAMBLE_LEN + sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + sizeof(*apdu_head) + sizeof(*req) + sizeof(*req_info) + app_data_len + PROTO_69845_NO_TIME_TAG_LEN + sizeof(proto_69845_tailer_t); pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) goto out; iot_pkt_reserve(pkt, PROTO_69845_PREAMBLE_LEN); /* fill 698.45 proto header */ data = iot_pkt_data(pkt); head = (proto_69845_frame_head_info_t *)data; addr_info.ser_info = *server_info; addr_info.cli_addr = PROTO_69845_CA_INVAILD_ADD; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, length - PROTO_69845_PREAMBLE_LEN, &addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_CLIENT_REQUEST); data += head_len; /* fill apdu data */ apdu_head = (proto_69845_app_req_resp_t*)data; apdu_head->type = PROTO_69845_C_APP_ACTION_REQ; data += sizeof(*apdu_head); /* fill 698.45 action req single object header */ req = (proto_69845_app_action_req_t *)data; req->data_type = PROTO_69845_APP_ACTION_NORMAL; data += sizeof(*req); /* fill 698.45 action req single object info */ os_mem_cpy(data, req_info, sizeof(*req_info)); src_req_info = (proto_69845_app_action_req_single_t *)data; proto_69845_oi_to_byte(req_info->omd.oi, (uint8_t *)&(src_req_info->omd.oi)); data += sizeof(*req_info); /* fill 698.45 action req single object app data */ if (app_data_len) { os_mem_cpy(data, req_info->data.data, app_data_len); data += app_data_len; } /* There is no time tag field, so time_tag is 0 */ time_tag = data; (*time_tag) = 0; data += 1; /* fill 698.45 proto tailer */ proto_69845_tail_fill(head, data, sizeof(proto_69845_tailer_t)); iot_pkt_put(pkt, head->len + PROTO_69845_START_END_LEN); out: return pkt; } uint8_t proto_69845_oad_cmp(proto_69845_app_oad_t *oad_1, proto_69845_app_oad_t *oad_2) { if (!oad_1 || !oad_2) { return 0; } if (oad_1->oi == oad_2->oi && oad_1->attribute_id == oad_2->attribute_id && oad_1->attribute_char == oad_2->attribute_char && oad_1->element_index == oad_2->element_index) { return 1; } return 0; } iot_pkt_t *proto_69845_build_apdu_data_with_rn_msg(uint8_t *apdu_data, uint32_t data_len, const server_addr_info_t* server_info) { iot_pkt_t *pkt = NULL; uint8_t *data, *len, ser_len, info_len_byte = 0; uint16_t head_len; uint32_t length; proto_69845_frame_head_info_t *head; proto_69845_app_req_resp_t *req; proto_69845_app_sec_req_resp_info_t *req_info; proto_69845_app_sec_req_resp_vali_info_t *vali_data; proto_69845_app_sec_rn_info_t *rn; proto_69845_app_len_descript_t *len_desc; addr_info_t addr_info = { 0 }; if (apdu_data == NULL || server_info == NULL) { goto out; } ser_len = proto_69845_server_len_calc(server_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } if (data_len > 255) { info_len_byte = 2; } else if (data_len > 127) { info_len_byte = 1; } length = PROTO_69845_PREAMBLE_LEN + sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + sizeof(*req) + sizeof(*req_info) + sizeof(*vali_data) + sizeof(*rn) + PROTO_69845_SECURITY_RN_LEN + sizeof(proto_69845_tailer_t) + data_len + info_len_byte; pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) { goto out; } iot_pkt_reserve(pkt, PROTO_69845_PREAMBLE_LEN); /* fill 698.45 proto header */ data = iot_pkt_put(pkt, length - PROTO_69845_PREAMBLE_LEN); head = (proto_69845_frame_head_info_t *)data; addr_info.ser_info = *server_info; addr_info.cli_addr = PROTO_69845_CA_INVAILD_ADD; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, (uint16_t)(length - PROTO_69845_PREAMBLE_LEN), &addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_CLIENT_REQUEST); data += head_len; /* fill app req */ req = (proto_69845_app_req_resp_t *)data; req->type = PROTO_69845_C_APP_SECURITY_REQ; req_info = (proto_69845_app_sec_req_resp_info_t *)req->data; req_info->type = PROTO_69845_SEC_DATA_TYPE_PLAINTEXT; if (!info_len_byte) { req_info->len = (uint8_t)data_len; data += (sizeof(*req) + sizeof(*req_info)); } else { len_desc = (proto_69845_app_len_descript_t*)&req_info->len; len_desc->mub_flag = 1; len_desc->byte_num = info_len_byte; len = (uint8_t*)req_info->data; if (info_len_byte == 2) { *len = (uint8_t)(data_len >> 8); len++; } *len = (uint8_t)data_len; data += (sizeof(*req) + sizeof(*req_info) + info_len_byte); } /* fill apdu data */ os_mem_cpy(req_info->data, apdu_data, data_len); data += data_len; /* fill 698.45 proto security validation data */ vali_data = (proto_69845_app_sec_req_resp_vali_info_t*)data; vali_data->type = PROTO_69845_SEC_REQ_VALI_TYPE_RN; rn = (proto_69845_app_sec_rn_info_t*)vali_data->data; rn->len = PROTO_69845_SECURITY_RN_LEN; os_mem_cpy(rn->data, proto_69845_rn, PROTO_69845_SECURITY_RN_LEN); data = data + sizeof(proto_69845_app_sec_req_resp_vali_info_t) + sizeof(proto_69845_app_sec_rn_info_t) + PROTO_69845_SECURITY_RN_LEN; /* fill 698.45 proto tailer */ proto_69845_tail_fill(head, data, sizeof(proto_69845_tailer_t)); out: return pkt; } static uint8_t proto_69845_get_tans_baud_id(uint32_t baud) { uint8_t i = 0; for (i = 0; i < PROTO_69845_TANS_BAUD_MAX; i++) { if (proto_69845_tans_baud[i] == baud) { return i; } } return PORTO_645_BAUD_ID_AUTO; } iot_pkt_t *proto_69845_build_proxy_trans_data_msg(uint8_t *data, uint32_t data_len, uint32_t baud, uint8_t port, uint8_t parity, uint16_t timeout, const server_addr_info_t* server_info, uint8_t sn) { iot_pkt_t *pkt = NULL; uint8_t *time_flag, *data_in, ser_len; uint16_t head_len; uint32_t length; proto_69845_frame_head_info_t *head; proto_69845_apdu_t *apdu_req; proto_69845_app_data_proxy_req_t *proxy_request; proto_69845_app_data_proxy_tans_req_t *proxy_cmd_request; addr_info_t addr_info; if (!data || !server_info) { goto out; } if (port != PROTO_PORT_RS485_1 && port != PROTO_PORT_RS485_2) { goto out; } ser_len = proto_69845_server_len_calc(server_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } length = PROTO_69845_PREAMBLE_LEN + sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + sizeof(*proxy_request) + sizeof(*proxy_cmd_request) + sizeof(*apdu_req) + sizeof(proto_69845_tailer_t) + sizeof(*time_flag) + data_len; pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) { goto out; } iot_pkt_reserve(pkt, PROTO_69845_PREAMBLE_LEN); /* fill 698.45 proto header */ data_in = iot_pkt_put(pkt, length - PROTO_69845_PREAMBLE_LEN); head = (proto_69845_frame_head_info_t *)data_in; addr_info.ser_info = *server_info; addr_info.cli_addr = PROTO_69845_CA_INVAILD_ADD; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, (uint16_t)(length - PROTO_69845_PREAMBLE_LEN), &addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_CLIENT_REQUEST); data_in += head_len; /* fill app req */ apdu_req = (proto_69845_apdu_t *)data_in; apdu_req->type = PROTO_69845_C_APP_PROXY_REQ; proxy_request = (proto_69845_app_data_proxy_req_t *)apdu_req->data; proxy_request->proxy_type = PROTO_69845_PROXY_TRANS_COMMAND_REQUEST; proxy_cmd_request = (proto_69845_app_data_proxy_tans_req_t*)proxy_request->data; proxy_cmd_request->piid.priority = PROTO_69845_APP_PIID_PRIORITY_GENERAL; proxy_cmd_request->piid.sn = sn; if (port == PROTO_PORT_RS485_1) { iot_uint32_to_bytes(PROTO_69845_APP_OAD_PORT_RS485I, (uint8_t*)&proxy_cmd_request->oad, 1); } else { iot_uint32_to_bytes(PROTO_69845_APP_OAD_PORT_RS485II, (uint8_t*)&proxy_cmd_request->oad, 1); } proxy_cmd_request->comdcb.buad = proto_69845_get_tans_baud_id(baud); proxy_cmd_request->comdcb.parity = parity; proxy_cmd_request->comdcb.stop = PROTO_69845_STOP_1_BITS; proxy_cmd_request->comdcb.data_bit = PROTO_69845_DLEN_8_BITS; proxy_cmd_request->comdcb.flow_mode = 0; iot_uint16_to_bytes(timeout, (uint8_t*)&proxy_cmd_request->timeout1, 1); iot_uint16_to_bytes(30, (uint8_t*)&proxy_cmd_request->timeout2, 1); proxy_cmd_request->data_len = (uint8_t)data_len; /* fill trans data */ os_mem_cpy(proxy_cmd_request->data, data, data_len); time_flag = proxy_cmd_request->data + data_len; *time_flag = 0; /* fill 698.45 proto tailer */ proto_69845_tail_fill(head, time_flag + sizeof(*time_flag), sizeof(proto_69845_tailer_t)); out: return pkt; } iot_pkt_t *proto_69845_build_get_version_msg_with_rn( const server_addr_info_t *server_info, uint8_t sn) { uint8_t *data = NULL; proto_69845_apdu_t *apdu; proto_69845_app_get_req_t *get_req = NULL; proto_69845_app_get_req_normal_t *normal = NULL; uint32_t req_size = 0; iot_pkt_t *pkt = NULL, *req = NULL; req_size = sizeof(*apdu) + sizeof(*get_req) + sizeof(*normal) + PROTO_69845_NO_TIME_TAG_LEN; req = iot_pkt_alloc(req_size, IOT_SMART_GRID_MID); if (!req) { goto out; } data = iot_pkt_put(req, req_size); apdu = (proto_69845_apdu_t *)data; apdu->type = PROTO_69845_C_APP_GET_REQ; get_req = (proto_69845_app_get_req_t *)apdu->data; get_req->data_type = PROTO_69845_APP_GET_NORMAL; normal = (proto_69845_app_get_req_normal_t *)get_req->data; normal->piid.sn = sn; normal->piid.priority = PROTO_69845_APP_PIID_PRIORITY_GENERAL; proto_69845_oi_to_byte(PROTO_69845_APP_OI_GET_VERSION, (uint8_t *)&normal->oad.oi); normal->oad.attribute_id = 3; normal->oad.attribute_char = 0; normal->oad.element_index = 1; pkt = proto_69845_build_apdu_data_with_rn_msg(data, req_size, server_info); iot_pkt_free(req); out: return pkt; } iot_pkt_t *proto_69845_build_comdcb_msg(uint32_t baud, const server_addr_info_t *server_info, uint8_t sn) { uint16_t data_len = 0; iot_pkt_t *ret = NULL, *pkt = NULL; proto_69845_app_action_req_single_t *request = NULL; proto_69845_app_ele_data_t *app_ele_data = NULL; proto_69845_app_oad_t *app_oad = NULL; proto_69845_app_data_t *app_data = NULL; proto_69845_app_data_comdcb_t *comdcb = NULL; data_len = sizeof(*app_data) + sizeof(*app_data) + sizeof(*app_oad) + sizeof(*app_data) + sizeof(*comdcb); pkt = iot_pkt_alloc(data_len + sizeof(*request), IOT_SMART_GRID_MID); if (!pkt) { goto out; } request = (proto_69845_app_action_req_single_t *)iot_pkt_data(pkt); request->piid.sn = sn; request->omd.oi = PROTO_69845_APP_OI_PLC_WIRELESS_INTERFACE; request->omd.method_id = 0x80; request->omd.operation_mode = 0x00; app_ele_data = (proto_69845_app_ele_data_t *)&request->data; app_ele_data->data_type = PROTO_69845_APP_DATA_STRUCTURE; app_ele_data->num_of_data = 2; app_data = (proto_69845_app_data_t *)app_ele_data->data; app_data->data_type = PROTO_69845_APP_DATA_OAD; app_oad = (proto_69845_app_oad_t *)app_data->data; app_oad->oi = PROTO_69845_APP_OI_PLC_WIRELESS_INTERFACE; proto_69845_oi_to_byte(app_oad->oi, (uint8_t *)&(app_oad->oi)); app_oad->attribute_id = 0x02; app_oad->element_index = 0xFD; app_data = (proto_69845_app_data_t *)(app_oad + 1); app_data->data_type = PROTO_69845_APP_DATA_COMDCB; comdcb = (proto_69845_app_data_comdcb_t *)app_data->data; comdcb->buad = proto_69845_get_tans_baud_id(baud); comdcb->parity = PROTO_69845_PARITY_EVEN; comdcb->data_bit = PROTO_69845_DLEN_8_BITS; comdcb->stop = PROTO_69845_STOP_1_BITS; comdcb->flow_mode = 0; ret = proto_69845_build_action_req_single_msg( request, data_len, server_info); out: if (pkt) { iot_pkt_free(pkt); } return ret; } uint32_t proto_69845_proxy_trans_resp_parse(uint8_t **data, uint16_t *len, uint8_t *seq) { uint32_t oad, apdu_len, err = ERR_OK; proto_69845_frame_head_info_t *hdr_698; apdu_info_t apdu_desc = { 0 }; proto_69845_apdu_t *apdu_resq; proto_69845_app_data_proxy_req_t *proxy_resq; proto_69845_app_data_proxy_tans_resp_t *proxy_tans_resp; if (!data || !(*data) || !len) { err = ERR_FAIL; goto out; } hdr_698 = proto_69845_sanity_check(*data, *len); if (!hdr_698) { err = ERR_FAIL; goto out; } if (proto_69845_get_apdu(hdr_698, *len, &apdu_desc) != ERR_OK) { err = ERR_FAIL; goto out; } if (!apdu_desc.len || !apdu_desc.ptr) { err = ERR_FAIL; goto out; } apdu_len = apdu_desc.len; if (apdu_len < sizeof(*apdu_resq) + sizeof(*proxy_resq) + sizeof(*proxy_tans_resp)) { err = ERR_FAIL; goto out; } apdu_len -= sizeof(*apdu_resq) + sizeof(*proxy_resq) + sizeof(*proxy_tans_resp); apdu_resq = (proto_69845_apdu_t *)apdu_desc.ptr; if (apdu_resq->type != PROTO_69845_S_APP_PROXY_RESP) { err = ERR_FAIL; goto out; } proxy_resq = (proto_69845_app_data_proxy_req_t *)apdu_resq->data; if (proxy_resq->proxy_type != PROTO_69845_PROXY_TRANS_COMMAND_REQUEST) { err = ERR_FAIL; goto out; } proxy_tans_resp = (proto_69845_app_data_proxy_tans_resp_t *)proxy_resq->data; oad = iot_bytes_to_uint32((uint8_t*)&proxy_tans_resp->oad, 1); if (oad != PROTO_69845_APP_OAD_PORT_RS485I && oad != PROTO_69845_APP_OAD_PORT_RS485II) { err = ERR_FAIL; goto out; } if (proxy_tans_resp->data_type != PROTO_69845_APP_DATA_ARRAY || !proxy_tans_resp->data_len) { err = ERR_FAIL; goto out; } if (apdu_len < proxy_tans_resp->data_len) { err = ERR_FAIL; goto out; } *len = proxy_tans_resp->data_len; *data = proxy_tans_resp->data; *seq = proxy_tans_resp->piid.sn; out: return err; } iot_pkt_t *proto_69845_build_apdu_data_msg(uint8_t *apdu_data, uint32_t data_len, addr_info_t* addr_info, uint8_t dir_and_prm) { iot_pkt_t *pkt = NULL; uint8_t *data, ser_len; uint16_t head_len; uint32_t length; proto_69845_frame_head_info_t *head; if (apdu_data == NULL || addr_info == NULL) { goto out; } ser_len = proto_69845_server_len_calc(&addr_info->ser_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } length = PROTO_69845_PREAMBLE_LEN + sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + data_len + sizeof(proto_69845_tailer_t); pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) { goto out; } iot_pkt_reserve(pkt, PROTO_69845_PREAMBLE_LEN); /* fill 698.45 proto header */ data = iot_pkt_put(pkt, length - PROTO_69845_PREAMBLE_LEN); head = (proto_69845_frame_head_info_t *)data; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, (uint16_t)(length - PROTO_69845_PREAMBLE_LEN), addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, dir_and_prm); data += head_len; /* fill apdu data */ os_mem_cpy(data, apdu_data, data_len); data += data_len; /* fill 698.45 proto tailer */ proto_69845_tail_fill(head, data, sizeof(proto_69845_tailer_t)); out: return pkt; } iot_pkt_t *proto_69845_build_apdu_data_with_security_resp_msg(uint8_t *apdu_data, uint32_t data_len, addr_info_t* addr_info) { iot_pkt_t *pkt = NULL; uint8_t *data, *len, info_len_byte = 0, ser_len; uint16_t head_len; uint32_t length; proto_69845_frame_head_info_t *head; proto_69845_app_req_resp_t *resp; proto_69845_app_sec_req_resp_info_t *resp_info; proto_69845_app_sec_optinon_info_t *vali_data; proto_69845_app_sec_mac_info_t *sec_mac; proto_69845_app_len_descript_t *len_desc; if (apdu_data == NULL || addr_info == NULL) { goto out; } ser_len = proto_69845_server_len_calc(&addr_info->ser_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } if (data_len > 255) { info_len_byte = 2; } else if (data_len > 127) { info_len_byte = 1; } length = PROTO_69845_PREAMBLE_LEN + sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + sizeof(*resp) + sizeof(*resp_info) + sizeof(*vali_data) + sizeof(*sec_mac) + info_len_byte + PROTO_69845_SECURITY_SEQUEN_LEN + sizeof(proto_69845_tailer_t) + data_len; pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) { goto out; } iot_pkt_reserve(pkt, PROTO_69845_PREAMBLE_LEN); /* fill 698.45 proto header */ data = iot_pkt_put(pkt, length - PROTO_69845_PREAMBLE_LEN); head = (proto_69845_frame_head_info_t *)data; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, (uint16_t)(length - PROTO_69845_PREAMBLE_LEN), addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_SERVER_RESPONSE); data += head_len; /* fill app req */ resp = (proto_69845_app_req_resp_t *)data; resp->type = PROTO_69845_S_APP_SECURITY_RESP; resp_info = (proto_69845_app_sec_req_resp_info_t *)resp->data; resp_info->type = PROTO_69845_SEC_DATA_TYPE_PLAINTEXT; if (!info_len_byte) { resp_info->len = (uint8_t)data_len; data += (sizeof(*resp) + sizeof(*resp_info)); } else { len_desc = (proto_69845_app_len_descript_t*)&resp_info->len; len_desc->mub_flag = 1; len_desc->byte_num = info_len_byte; len = (uint8_t*)resp_info->data; if (info_len_byte == 2) { *len = (uint8_t)(data_len >> 8); len++; } *len = (uint8_t)data_len; data += (sizeof(*resp) + sizeof(*resp_info) + info_len_byte); } /* fill apdu data */ os_mem_cpy(data, apdu_data, data_len); data += data_len; /* fill 698.45 proto security validation data */ vali_data = (proto_69845_app_sec_optinon_info_t*)data; vali_data->type = PROTO_69845_SEC_RESP_VALI_TYPE_MAC_RN; vali_data->choice = PROTO_69845_SEC_DATA_TYPE_PLAINTEXT; sec_mac = (proto_69845_app_sec_mac_info_t*)vali_data->data; sec_mac->len = PROTO_69845_SECURITY_SEQUEN_LEN; os_mem_cpy(sec_mac->data, proto_69845_rn, PROTO_69845_SECURITY_SEQUEN_LEN); data = data + sizeof(proto_69845_app_sec_optinon_info_t) + sizeof(proto_69845_app_sec_mac_info_t) + PROTO_69845_SECURITY_SEQUEN_LEN; /* fill 698.45 proto tailer */ proto_69845_tail_fill(head, data, sizeof(proto_69845_tailer_t)); out: return pkt; } iot_pkt_t *proto_69845_set_normal_ack(addr_info_t *addr_info, proto_69845_app_piid_t *piid, proto_69845_app_oad_t *oad, uint8_t dar) { iot_pkt_t *pkt = NULL; uint8_t *data, ser_len; uint16_t length, head_len, tail_len; proto_69845_frame_head_info_t *head; proto_69845_app_req_resp_t *resp; proto_69845_app_set_resp_t *set_resp; proto_69845_app_set_resp_normal_t *set_normal; if (addr_info == NULL || piid == NULL || oad == NULL) { goto out; } ser_len = proto_69845_server_len_calc(&addr_info->ser_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } length = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + sizeof(*resp) + sizeof(*set_resp) + sizeof(*set_normal) + PROTO_69845_NO_TIME_TAG_LEN + PROTO_69845_NO_FLW_DATA_LEN + sizeof(proto_69845_tailer_t); pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) goto out; /* fill 698.45 proto header */ data = iot_pkt_data(pkt); head = (proto_69845_frame_head_info_t *)data; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, length, addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_SERVER_RESPONSE); data += head_len; /* fill plaintext apdu data */ resp = (proto_69845_app_req_resp_t*)data; resp->type = PROTO_69845_S_APP_SET_RESP; set_resp = (proto_69845_app_set_resp_t*)resp->data; set_resp->data_type = PROTO_69845_APP_SET_NORMAL; data = data + sizeof(*resp) + sizeof(*set_resp); set_normal = (proto_69845_app_set_resp_normal_t*)set_resp->data; set_normal->piid_acd.sn = piid->sn; set_normal->piid_acd.priority = piid->priority; set_normal->piid_acd.acd = 0; proto_69845_oi_to_byte(oad->oi, (uint8_t*)&set_normal->result.oad.oi); set_normal->result.oad.attribute_char = oad->attribute_char; set_normal->result.oad.attribute_id = oad->attribute_id; set_normal->result.oad.element_index = oad->element_index; set_normal->result.dar = dar; data += sizeof(*set_normal); /* There is no time tag field, so time_tag is 0 */ tail_len = PROTO_69845_NO_TIME_TAG_LEN + PROTO_69845_NO_FLW_DATA_LEN + sizeof(proto_69845_tailer_t); proto_69845_tail_fill_without_ts_fl(head, data, tail_len); iot_pkt_put(pkt, head->len + PROTO_69845_START_END_LEN); out: return pkt; } iot_pkt_t *proto_69845_action_single_ack(addr_info_t *addr_info, proto_69845_app_piid_t *piid, proto_69845_app_omd_t *omd, uint8_t dar) { iot_pkt_t *pkt = NULL; uint8_t *data, ser_len; uint16_t length, head_len, tail_len; proto_69845_frame_head_info_t *head; proto_69845_app_req_resp_t *resp; proto_69845_app_action_resp_t *action_resp; proto_69845_app_action_resp_normal_t *action_normal; if (addr_info == NULL || piid == NULL || omd == NULL) { goto out; } ser_len = proto_69845_server_len_calc(&addr_info->ser_info); if ((ser_len > PROTO_69845_SA_MAX_LEN) || !ser_len) { goto out; } length = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN + sizeof(*resp) + sizeof(*action_resp) + sizeof(*action_normal) + PROTO_69845_NO_TIME_TAG_LEN + PROTO_69845_NO_FLW_DATA_LEN + sizeof(proto_69845_tailer_t); pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID); if (!pkt) goto out; /* fill 698.45 proto header */ data = iot_pkt_data(pkt); head = (proto_69845_frame_head_info_t *)data; head_len = sizeof(*head) + ser_len + PROTO_69845_CA_LEN + PROTO_69845_CHECKSUM_LEN; proto_69845_head_fill(head, head_len, length, addr_info, PROTO_69845_FN_USER_DATA, PROTO_69845_APDU_WHOLE, PROTO_69845_D_P_SERVER_RESPONSE); data += head_len; /* fill plaintext apdu data */ resp = (proto_69845_app_req_resp_t*)data; resp->type = PROTO_69845_S_APP_ACTION_RESP; action_resp = (proto_69845_app_action_resp_t*)resp->data; action_resp->data_type = PROTO_69845_APP_ACTION_NORMAL; data = data + sizeof(*resp) + sizeof(*action_resp); action_normal = (proto_69845_app_action_resp_normal_t*)action_resp->data; action_normal->piid_acd.sn = piid->sn; action_normal->piid_acd.priority = piid->priority; action_normal->piid_acd.acd = 0; proto_69845_oi_to_byte(omd->oi, (uint8_t*)&action_normal->result.omd.oi); action_normal->result.omd.method_id = omd->method_id; action_normal->result.omd.operation_mode = omd->operation_mode; action_normal->result.dar = dar; action_normal->result.optional = PROTO_69845_APP_OPTIONAL_NO_DATA; data += sizeof(*action_normal); /* There is no time tag field, so time_tag is 0 */ tail_len = PROTO_69845_NO_TIME_TAG_LEN + PROTO_69845_NO_FLW_DATA_LEN + sizeof(proto_69845_tailer_t); proto_69845_tail_fill_without_ts_fl(head, data, tail_len); iot_pkt_put(pkt, head->len + PROTO_69845_START_END_LEN); out: return pkt; } /* create a meter correcting time message for the 69845 protocol */ iot_pkt_t *proto_69845_build_corr_msg(server_addr_info_t *server_addr, iot_time_tm_t *tm, proto_69845_app_piid_t *piid, uint8_t with_rn) { uint8_t *time_tag, *data; uint32_t action_req_size; proto_69845_apdu_t *apdu; proto_69845_app_action_req_t *act_req; proto_69845_app_action_req_single_t *req_single; proto_69845_app_data_time_s_t *time; iot_pkt_t *pkt = NULL, *get_action_req = NULL; addr_info_t addr_info = { 0 }; if (!tm || !piid) { goto out; } action_req_size = sizeof(*apdu) + sizeof(*act_req) + sizeof(*req_single) + sizeof(*time) + sizeof(*time_tag); get_action_req = iot_pkt_alloc(action_req_size, IOT_SMART_GRID_MID); if (!get_action_req) { goto out; } data = iot_pkt_put(get_action_req, action_req_size); apdu = (proto_69845_apdu_t *)data; apdu->type = PROTO_69845_C_APP_ACTION_REQ; act_req = (proto_69845_app_action_req_t *)apdu->data; act_req->data_type = PROTO_69845_APP_ACTION_NORMAL; req_single = (proto_69845_app_action_req_single_t *)act_req->data; req_single->piid.priority = piid->priority; req_single->piid.sn = piid->sn; proto_69845_oi_to_byte(PROTO_69845_APP_OI_TIME, (uint8_t*)&req_single->omd.oi); req_single->omd.method_id = PROTO_OMD_CORRECT_TIME_METHOD_ID; req_single->omd.operation_mode = 0; req_single->data.data_type = PROTO_69845_APP_DATA_TIME_S; time = (proto_69845_app_data_time_s_t *)req_single->data.data; time->year = iot_bytes_to_uint16((uint8_t *)&tm->tm_year, 1); time->month = tm->tm_mon; time->day = tm->tm_mday; time->hour = tm->tm_hour; time->minute = tm->tm_min; time->second = tm->tm_sec; time_tag = data + sizeof(*apdu) + sizeof(*act_req) + sizeof(*req_single) + sizeof(*time); *time_tag = 0; if (!server_addr) { if (with_rn) { pkt = proto_69845_build_apdu_data_with_rn_msg((uint8_t *)apdu, action_req_size, &proto_69845_any_server_addr); } else { addr_info.ser_info = proto_69845_any_server_addr; pkt = proto_69845_build_apdu_data_msg((uint8_t *)apdu, action_req_size, &addr_info, PROTO_69845_D_P_CLIENT_REQUEST); } } else { if (with_rn) { pkt = proto_69845_build_apdu_data_with_rn_msg((uint8_t *)apdu, action_req_size, server_addr); } else { addr_info.ser_info = *server_addr; pkt = proto_69845_build_apdu_data_msg((uint8_t *)apdu, action_req_size, &addr_info, PROTO_69845_D_P_CLIENT_REQUEST); } } iot_pkt_free(get_action_req); out: return pkt; } uint32_t proto_69845_dlong_unsign_data_to_meter_bcd_data( uint8_t *dlong_data, uint8_t dlong_data_len, uint8_t *meter_bcd_data, uint8_t bcd_len) { uint32_t data; if (dlong_data == NULL || dlong_data_len != PROTO_69845_METER_DATA_DOUBLE_LONG_LEN || meter_bcd_data == NULL || !bcd_len) { return ERR_FAIL; } data = iot_bytes_to_uint32(dlong_data, 1); iot_uint32_to_bcd(data, bcd_len, meter_bcd_data); return ERR_OK; } uint32_t proto_69845_long_unsign_to_meter_bcd_data( uint8_t *long_data, uint8_t long_data_len, uint8_t *meter_bcd_data, uint8_t bcd_len) { uint8_t high, low; uint16_t data; uint32_t ret = ERR_OK; if (long_data == NULL || long_data_len != PROTO_69845_METER_DATA_LONG_LEN || meter_bcd_data == NULL || !bcd_len) { ret = ERR_FAIL; goto out; } data = iot_bytes_to_uint16(long_data, 1); high = (uint8_t)(data / 100); low = (uint8_t)(data % 100); if (bcd_len > sizeof(data)) { bcd_len = sizeof(data); } if (!bcd_len) { ret = ERR_FAIL; goto out; } meter_bcd_data[0] = iot_byte_to_bcd(low); bcd_len--; if (!bcd_len) { ret = ERR_FAIL; goto out; } meter_bcd_data[1] = iot_byte_to_bcd(high); out: return ret; } uint32_t proto_69845_dlong_data_to_meter_bcd_data( uint8_t *dlong_data, uint8_t dlong_data_len, uint8_t *meter_bcd_data, uint8_t bcd_len) { uint8_t flag_neg = 0; int32_t data; if (dlong_data == NULL || dlong_data_len != PROTO_69845_METER_DATA_DOUBLE_LONG_LEN || meter_bcd_data == NULL || !bcd_len) { return ERR_FAIL; } data = (int32_t)iot_bytes_to_uint32(dlong_data, 1); if (data < 0) { flag_neg = 1; data = 0 - data; } iot_uint32_to_bcd((uint32_t)data, bcd_len, meter_bcd_data); if (flag_neg) { meter_bcd_data[bcd_len - 1] |= 0x80; } return ERR_OK; } uint32_t proto_69845_long_data_to_meter_bcd_data( uint8_t *long_data, uint8_t long_data_len, uint8_t *meter_bcd_data, uint8_t bcd_len) { uint8_t high, low, flag_neg = 0;; int16_t data; uint32_t ret = ERR_OK; if (long_data == NULL || long_data_len != PROTO_69845_METER_DATA_LONG_LEN || meter_bcd_data == NULL || !bcd_len) { ret = ERR_FAIL; goto out; } data = (int16_t)iot_bytes_to_uint16(long_data, 1); if (data < 0) { flag_neg = 1; data = 0 - data; } high = (uint8_t)(data / 100); low = (uint8_t)(data % 100); if (bcd_len > sizeof(data)) { bcd_len = sizeof(data); } if (!bcd_len) { ret = ERR_FAIL; goto out; } meter_bcd_data[0] = iot_byte_to_bcd(low); bcd_len--; if (!bcd_len) { ret = ERR_FAIL; goto out; } meter_bcd_data[1] = iot_byte_to_bcd(high); if (flag_neg) { meter_bcd_data[1] |= 0x80; } out: return ret; } uint32_t proto_69845_pf_ele_data_handle(proto_645_07_pf_t *meter_pf, proto_69845_app_ele_data_t *ele_data, uint32_t data_len) { uint8_t i, *meter_data, *data; uint32_t ele_len, ret = ERR_OK;; proto_69845_app_data_t *app_data; ele_len = sizeof(*app_data) + PROTO_69845_METER_DATA_LONG_LEN; if (data_len < ele_len * ele_data->num_of_data) { ret = ERR_FAIL; goto out; } data = ele_data->data; BUILD_BUG_ON(sizeof(meter_pf->total) == PROTO_645_07_PF_LEN); meter_data = meter_pf->total; for (i = 0; i < ele_data->num_of_data && i < PROTO_69845_POWER_MAX_ELE_NUM; i++) { app_data = (proto_69845_app_data_t *)data; if (app_data->data_type == PROTO_69845_APP_DATA_LONG) { if (proto_69845_long_data_to_meter_bcd_data(app_data->data, PROTO_69845_METER_DATA_LONG_LEN, meter_data, PROTO_645_07_PF_LEN) != ERR_OK) { ret = ERR_FAIL; goto out; } } data += ele_len; meter_data += PROTO_645_07_PF_LEN; } out: return ret; } uint32_t proto_69845_v_data_handle(proto_645_v_t *meter_v, proto_69845_app_ele_data_t *ele_data, uint32_t data_len) { uint8_t i, *meter_data, *data; uint32_t ele_len, ret = ERR_OK; proto_69845_app_data_t *app_data; ele_len = sizeof(*app_data) + PROTO_69845_METER_DATA_LONG_LEN; if (data_len < ele_len * ele_data->num_of_data) { ret = ERR_FAIL; goto out; } data = ele_data->data; meter_data = meter_v->a; BUILD_BUG_ON(sizeof(meter_v->a) == PROTO_645_V_LEN); for (i = 0; i < ele_data->num_of_data && i < PROTO_69845_SPLIT_PHASE_MAX_ELE_NUM; i++) { app_data = (proto_69845_app_data_t *)data; if (app_data->data_type == PROTO_69845_APP_DATA_LONG_UNSIGNED) { if (proto_69845_long_unsign_to_meter_bcd_data(app_data->data, PROTO_69845_METER_DATA_LONG_LEN, meter_data, PROTO_645_V_LEN) != ERR_OK) { ret = ERR_FAIL; goto out; } } data += ele_len; meter_data += PROTO_645_V_LEN; } out: return ret; } uint32_t proto_69845_a_data_handle(proto_645_07_a_t *meter_a, proto_69845_app_ele_data_t *ele_data, uint32_t data_len) { uint8_t i, *meter_data, *data; uint32_t ele_len, ret = ERR_OK; proto_69845_app_data_t *app_data; ele_len = sizeof(*app_data) + PROTO_69845_METER_DATA_DOUBLE_LONG_LEN; if (data_len < ele_len * ele_data->num_of_data) { ret = ERR_FAIL; goto out; } data = ele_data->data; meter_data = meter_a->a; BUILD_BUG_ON(sizeof(meter_a->a) == PROTO_645_07_A_LEN); for (i = 0; i < ele_data->num_of_data && i < PROTO_69845_SPLIT_PHASE_MAX_ELE_NUM; i++) { app_data = (proto_69845_app_data_t *)data; if (app_data->data_type == PROTO_69845_APP_DATA_DOUBLE_LONG) { if (proto_69845_dlong_data_to_meter_bcd_data(app_data->data, PROTO_69845_METER_DATA_DOUBLE_LONG_LEN, meter_data, PROTO_645_07_A_LEN) != ERR_OK){ ret = ERR_FAIL; goto out; } } data += ele_len; meter_data += PROTO_645_07_A_LEN; } out: return ret; } uint32_t proto_69845_gnd_a_data_handle(uint8_t *meter_gnd_a, uint8_t gnd_a_len, uint8_t *data, uint32_t data_len) { uint32_t ret = ERR_OK; proto_69845_app_data_t *app_data; if (data_len < sizeof(*app_data) || gnd_a_len < PROTO_645_07_A_LEN) { ret = ERR_FAIL; goto out; } app_data = (proto_69845_app_data_t *)data; data_len -= sizeof(*app_data); if (app_data->data_type != PROTO_69845_APP_DATA_DOUBLE_LONG) { ret = ERR_FAIL; goto out; } if (data_len < PROTO_69845_METER_DATA_DOUBLE_LONG_LEN) { ret = ERR_FAIL; goto out; } ret = proto_69845_dlong_data_to_meter_bcd_data(app_data->data, PROTO_69845_METER_DATA_DOUBLE_LONG_LEN, meter_gnd_a, PROTO_645_07_A_LEN); out: return ret; } uint32_t proto_69845_power_data_handle(int32_t power[], uint8_t **data, uint32_t *len) { uint32_t ret = ERR_OK; uint8_t *ds = *data, i, ele_len; proto_69845_app_data_t *fix_data; proto_69845_app_ele_data_t *var_data = (proto_69845_app_ele_data_t *)ds; if (*len < sizeof(*var_data)) { ret = ERR_FAIL; goto out; } *len -= sizeof(*var_data); ds += sizeof(*var_data); ele_len = PROTO_69845_METER_DATA_DOUBLE_LONG_LEN + sizeof(*fix_data); for (i = 0; i < var_data->num_of_data && *len > ele_len; i++) { fix_data = (proto_69845_app_data_t *)ds; if (fix_data->data_type == PROTO_69845_APP_DATA_DOUBLE_LONG) { power[i] = (int32_t)iot_bytes_to_uint32(fix_data->data, 1); } else { ret = ERR_FAIL; goto out; } ds += ele_len; *len -= ele_len; } *data = ds; out: return ret; } uint32_t proto_69845_time_data_handle(iot_time_tm_t *meter_time, uint8_t **data, uint32_t *len) { uint32_t ret = ERR_OK; proto_69845_app_data_t *app_data; proto_69845_app_data_time_s_t *time; app_data = (proto_69845_app_data_t*)(*data); if (*len < sizeof(*app_data) + sizeof(*time)) { ret = ERR_FAIL; goto out; } *data += sizeof(*app_data) + sizeof(*time); *len -= sizeof(*app_data) + sizeof(*time); if (app_data->data_type != PROTO_69845_APP_DATA_TIME_S) { ret = ERR_FAIL; goto out; } time = (proto_69845_app_data_time_s_t *)app_data->data; meter_time->tm_year = iot_bytes_to_uint16((uint8_t *)&time->year, 1); meter_time->tm_mon = time->month;; meter_time->tm_mday = time->day; meter_time->tm_hour = time->hour; meter_time->tm_min = time->minute; meter_time->tm_sec = time->second; out: return ret; } uint32_t proto_69845_run_state_data_handle(proto_69845_rs_word_t *rs_word, uint8_t **data, uint32_t *len) { uint8_t i, *ds; uint16_t *word; uint32_t ele_len, ret = ERR_OK; proto_69845_app_ele_data_t *var_data; proto_69845_app_ele_data_t *word_data; if (*len < sizeof(*var_data)) { ret = ERR_FAIL; goto out; } var_data = (proto_69845_app_ele_data_t *)(*data); *len -= sizeof(*var_data); if (var_data->num_of_data != PROTO_69845_RS_WORDS_NUM) { ret = ERR_FAIL; goto out; } ele_len = sizeof(*var_data) + PROTO_69845_METER_DATA_LONG_LEN; ds = var_data->data; word = (uint16_t *)rs_word; BUILD_BUG_ON(sizeof(*rs_word) == PROTO_69845_RS_WORDS_NUM * \ PROTO_69845_METER_DATA_LONG_LEN); for (i = 0; i < var_data->num_of_data && *len > ele_len; i++) { word_data = (proto_69845_app_ele_data_t *)ds; if (word_data->data_type != PROTO_69845_APP_DATA_BIT_STRING || word_data->num_of_data != PROTO_69845_APP_DATA_LONG) { break; } *word = iot_bytes_to_uint16(word_data->data, 1); *len -= ele_len; ds += ele_len; word++; } if (i != PROTO_69845_RS_WORDS_NUM) ret = ERR_FAIL; *data = ds; out: return ret; } uint32_t proto_69845_evt_cur_info_parse(uint32_t *occur_n, uint32_t *acc_time, uint8_t **data, uint32_t *len) { uint8_t *ds = *data, evt_src_len, ele_len; proto_69845_app_data_t *fix_data; proto_69845_app_ele_data_t *var_data; if (*len < sizeof (*var_data)) goto err; var_data = (proto_69845_app_ele_data_t *)ds; ds += sizeof (*var_data); *len -= sizeof (*var_data); if (var_data->data_type != PROTO_69845_APP_DATA_ARRAY) goto err; if (var_data->num_of_data != 1) goto err; if (*len < sizeof (*var_data)) goto err; var_data = (proto_69845_app_ele_data_t *)ds; ds += sizeof (*var_data); *len -= sizeof (*var_data); if (var_data->data_type != PROTO_69845_APP_DATA_STRUCTURE) goto err; if (var_data->num_of_data != 2) goto err; /* parsing the event source */ if (*len < sizeof(*fix_data)) { goto err; } fix_data = (proto_69845_app_data_t *)ds; ds += sizeof (*fix_data); *len -= sizeof (*fix_data); switch (fix_data->data_type) { case PROTO_69845_APP_DATA_NULL: evt_src_len = 0; break; default: goto err; } if (*len < evt_src_len) goto err; ds += evt_src_len; *len -= evt_src_len; if (*len < sizeof (*var_data)) goto err; var_data = (proto_69845_app_ele_data_t *)ds; ds += sizeof (*var_data); *len -= sizeof (*var_data); if (var_data->data_type != PROTO_69845_APP_DATA_STRUCTURE) { goto err; } if (var_data->num_of_data != 2) { goto err; } ele_len = PROTO_69845_METER_DATA_DOUBLE_LONG_LEN + sizeof(*fix_data); fix_data = (proto_69845_app_data_t *)ds; if (fix_data->data_type == PROTO_69845_APP_DATA_NULL) { ds += sizeof(*fix_data); *len -= sizeof(*fix_data); } else if (fix_data->data_type == PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED) { if (occur_n) *occur_n = iot_bytes_to_uint32(fix_data->data, 1); ds += ele_len; *len -= ele_len; } else { goto err; } fix_data = (proto_69845_app_data_t *)ds; if (fix_data->data_type == PROTO_69845_APP_DATA_NULL) { ds += sizeof (*fix_data); *len -= sizeof (*fix_data); } else if (fix_data->data_type == PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED) { if (acc_time) *acc_time = iot_bytes_to_uint32(fix_data->data, 1); ds += ele_len; *len -= ele_len; } else { goto err; } *data = ds; return ERR_OK; err: return ERR_FAIL; } uint32_t proto_69845_energy_data_handle(uint32_t *energy, uint8_t **data, uint32_t *in_len) { uint8_t *ds = *data, i, cnt; uint32_t len = *in_len; proto_69845_app_data_t *fix_data; uint32_t ele_len; if (len < sizeof(proto_69845_app_ele_data_t)) { return ERR_FAIL; } switch (ds[0]) { case PROTO_69845_APP_DATA_DOUBLE_LONG: case PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED: { cnt = 1; break; } case PROTO_69845_APP_DATA_ARRAY: { cnt = ds[1]; ds += sizeof(proto_69845_app_ele_data_t); len -= sizeof(proto_69845_app_ele_data_t); break; } default: return ERR_FAIL; } ele_len = sizeof(*fix_data) + PROTO_69845_METER_DATA_DOUBLE_LONG_LEN; for (i = 0; i < cnt && len > ele_len ; i++) { fix_data = (proto_69845_app_data_t *)ds; if (fix_data->data_type != PROTO_69845_APP_DATA_DOUBLE_LONG && fix_data->data_type != PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED) { return ERR_FAIL; } energy[i] = iot_bytes_to_uint32(fix_data->data, 1); ds += ele_len; len -= ele_len; } *data = ds; *in_len = len; return ERR_OK; } uint32_t proto_69845_energy_sum_data_handle(uint8_t *energy_sum, uint8_t *data, uint32_t data_len) { proto_69845_app_data_t *app_data; if (data_len < sizeof(*app_data)) { goto drop; } app_data = (proto_69845_app_data_t *)data; data_len -= sizeof(*app_data); if (app_data->data_type != PROTO_69845_APP_DATA_DOUBLE_LONG && app_data->data_type != PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED) { goto drop; } if (data_len < PROTO_69845_METER_DATA_DOUBLE_LONG_LEN) { goto drop; } BUILD_BUG_ON(PROTO_645_07_ENERGY_DATA_LEN == PROTO_69845_METER_DATA_DOUBLE_LONG_LEN); if (app_data->data_type == PROTO_69845_APP_DATA_DOUBLE_LONG) { proto_69845_dlong_data_to_meter_bcd_data(app_data->data, PROTO_69845_METER_DATA_DOUBLE_LONG_LEN, energy_sum, PROTO_645_07_ENERGY_DATA_LEN); } else { proto_69845_dlong_unsign_data_to_meter_bcd_data(app_data->data, PROTO_69845_METER_DATA_DOUBLE_LONG_LEN, energy_sum, PROTO_645_07_ENERGY_DATA_LEN); } return ERR_OK; drop: return ERR_FAIL; } uint32_t proto_69845_pf_data_handle(int16_t *pf, uint8_t **data, uint32_t *in_len) { uint8_t *ds = *data, i, cnt; uint32_t len = *in_len; proto_69845_app_data_t *fix_data; uint32_t ele_len; if (len < sizeof(proto_69845_app_ele_data_t)) { return ERR_FAIL; } switch (ds[0]) { case PROTO_69845_APP_DATA_LONG: { cnt = 1; break; } case PROTO_69845_APP_DATA_ARRAY: { cnt = ds[1]; ds += sizeof(proto_69845_app_ele_data_t); len -= sizeof(proto_69845_app_ele_data_t); break; } default: return ERR_FAIL; } ele_len = sizeof(*fix_data) + PROTO_69845_METER_DATA_LONG_LEN; for (i = 0; i < cnt && len > ele_len ; i++) { fix_data = (proto_69845_app_data_t *)ds; if (fix_data->data_type != PROTO_69845_APP_DATA_LONG) { return ERR_FAIL; } pf[i] = (int16_t)iot_bytes_to_uint16(fix_data->data, 1); ds += ele_len; len -= ele_len; } *data = ds; *in_len = len; return ERR_OK; } uint32_t proto_69845_p_data_handle(proto_645_07_p_t *meter_p, proto_69845_app_ele_data_t *ele_data, uint32_t data_len) { uint8_t i, *meter_data, *data; uint32_t ele_len; proto_69845_app_data_t *app_data; ele_len = sizeof(*app_data) + PROTO_69845_METER_DATA_DOUBLE_LONG_LEN; if (data_len < ele_len * ele_data->num_of_data) { return ERR_FAIL; } data = ele_data->data; BUILD_BUG_ON(sizeof(meter_p->total) == PROTO_645_07_P_LEN); meter_data = meter_p->total; for (i = 0; i < ele_data->num_of_data && i < PROTO_69845_POWER_MAX_ELE_NUM; i++) { app_data = (proto_69845_app_data_t *)data; if (app_data->data_type == PROTO_69845_APP_DATA_DOUBLE_LONG) { proto_69845_dlong_data_to_meter_bcd_data(app_data->data, PROTO_69845_METER_DATA_DOUBLE_LONG_LEN, meter_data, PROTO_645_07_P_LEN); } data += ele_len; meter_data += PROTO_645_07_P_LEN; } return ERR_OK; } iot_pkt_t * proto_69845_build_file_info_msg(uint32_t file_size, uint16_t file_crc, uint16_t block_size, uint32_t hw_ver, uint32_t sw_ver, uint32_t loader_id, uint8_t *server_addr) { iot_pkt_t *pkt = NULL; iot_pkt_t *tmp_pkt = NULL; proto_69845_app_action_req_single_t *req_info; uint8_t *app_data; uint16_t i; server_addr_info_t server_info = {0}; char ver_string[16]; server_info.len = PROTO_69845_SA_LEN; server_info.type = PROTO_69845_SA_TYPE_SIG; iot_mac_addr_cpy(server_info.addr, server_addr); tmp_pkt = iot_pkt_alloc(PROTO_69845_ACTION_REQUEST_COMMON_LEN, IOT_SMART_GRID_MID); if (tmp_pkt == NULL) { IOT_ASSERT(0); } req_info = (proto_69845_app_action_req_single_t *)iot_pkt_data(tmp_pkt); req_info->omd.method_id = PROTO_OMD_TRANSFILE_INFO_START_METHOD_ID; req_info->omd.oi = PROTO_69845_APP_OI_FILETRANS_BLOCK; req_info->omd.operation_mode = 0; req_info->data.data_type = PROTO_69845_APP_DATA_STRUCTURE; app_data = (iot_pkt_data(tmp_pkt) + sizeof(*req_info)); i = 0; app_data[i++] = 6; /* file info, type is struct */ app_data[i++] = PROTO_69845_APP_DATA_STRUCTURE; app_data[i++] = 6; /* src file path, type is visible string */ app_data[i++] = PROTO_69845_APP_DATA_VISIBLE_STRING; app_data[i++] = 1; /* src file is null */ app_data[i++] = 0x30; /* destination file path, type is visible string */ app_data[i++] = PROTO_69845_APP_DATA_VISIBLE_STRING; app_data[i++] = 1; /* destination file is null */ app_data[i++] = 0x30; /* file size type is double long unsigned */ app_data[i++] = PROTO_69845_APP_DATA_DOUBLE_LONG_UNSIGNED; iot_uint32_to_bytes(file_size, app_data + i, 1); i += PROTO_69845_METER_DATA_DOUBLE_LONG_LEN; /* file attribute, type is bit-string size 3, bit0 - 1 read, 0 not read; bit1 - 1 write, 0 not write; bit2 - 1 exe, 0 not exe. */ app_data[i++] = PROTO_69845_APP_DATA_BIT_STRING; app_data[i++] = 3; app_data[i++] = 0x07; /* file version, type is visible string */ app_data[i++] = PROTO_69845_APP_DATA_VISIBLE_STRING; app_data[i++] = 1; app_data[i++] = 0x30; /* file type, type is enum, 0 - local file, 1 - other file */ app_data[i++] = PROTO_69845_APP_DATA_ENUM; app_data[i++] = 1; /* translate block size, type is long unsigned */ app_data[i++] = PROTO_69845_APP_DATA_LONG_UNSIGNED; iot_uint16_to_bytes(block_size, app_data + i, 1); i += PROTO_69845_METER_DATA_LONG_LEN; /* check type, type is struct */ app_data[i++] = PROTO_69845_APP_DATA_STRUCTURE; app_data[i++] = 2; /* check mode, type is enum, 0 - crc, 1 -mdt, 2 - sha1, 255 - other */ app_data[i++] = PROTO_69845_APP_DATA_ENUM; app_data[i++] = 0; /* check value, type is octet-string */ app_data[i++] = PROTO_69845_APP_DATA_OCTET_STRING; app_data[i++] = sizeof(file_crc); iot_uint16_to_bytes(file_crc, app_data + i, 1); i += sizeof(file_crc); /* compatible soft version, type is array visible string */ app_data[i++] = PROTO_69845_APP_DATA_ARRAY; app_data[i++] = 2; app_data[i++] = PROTO_69845_APP_DATA_VISIBLE_STRING; app_data[i] = (uint8_t)iot_sprintf(ver_string, "%d", sw_ver); os_mem_cpy(app_data + i + 1, ver_string, app_data[i]); i += app_data[i] + 1; app_data[i++] = PROTO_69845_APP_DATA_VISIBLE_STRING; app_data[i] = (uint8_t)iot_sprintf(ver_string, "%d", sw_ver); os_mem_cpy(app_data + i + 1, ver_string, app_data[i]); i += app_data[i] + 1; /* compatible hardware version, type is array visible string */ app_data[i++] = PROTO_69845_APP_DATA_ARRAY; app_data[i++] = 2; app_data[i++] = PROTO_69845_APP_DATA_VISIBLE_STRING; app_data[i] = (uint8_t)iot_sprintf(ver_string, "%d", hw_ver); os_mem_cpy(app_data + i + 1, ver_string, app_data[i]); i += app_data[i] + 1; app_data[i++] = PROTO_69845_APP_DATA_VISIBLE_STRING; app_data[i] = (uint8_t)iot_sprintf(ver_string, "%d", hw_ver); os_mem_cpy(app_data + i + 1, ver_string, app_data[i]); i += app_data[i] + 1; /* loader id type is visible string */ app_data[i++] = PROTO_69845_APP_DATA_VISIBLE_STRING; app_data[i] = (uint8_t)iot_sprintf(ver_string, "%d", loader_id); os_mem_cpy(app_data + i + 1, ver_string, app_data[i]); i += app_data[i] + 1; pkt = proto_69845_build_action_req_single_msg(req_info, i, &server_info); if (tmp_pkt) { iot_pkt_free(tmp_pkt); } return pkt; } uint32_t proto_69845_handle_file_info_rsp(uint8_t *data, uint32_t data_len) { uint8_t reason = 0; uint32_t oad_value; apdu_info_t apdu_desc = { 0 }; proto_69845_frame_head_info_t *hdr_698; proto_69845_apdu_t *apdu; proto_69845_app_action_resp_t *act_resp; proto_69845_app_action_resp_normal_t *act_resp_single; if (ERR_OK != proto_69845_parse(&data, &data_len, &hdr_698, &apdu_desc)) { reason = 1; goto out; } apdu = (proto_69845_apdu_t *)apdu_desc.ptr; if (apdu_desc.len < (sizeof(*apdu) + sizeof(*act_resp) + sizeof(*act_resp_single))) { reason = 2; goto out; } if (apdu->type != PROTO_69845_S_APP_ACTION_RESP) { reason = 3; goto out; } act_resp = (proto_69845_app_action_resp_t*)apdu->data; if (act_resp->data_type != PROTO_69845_APP_ACTION_NORMAL) { reason = 4; goto out; } act_resp_single = (proto_69845_app_action_resp_normal_t*)act_resp->data; oad_value = iot_bytes_to_uint32((uint8_t*)&act_resp_single->result.omd.oi, 1); if (oad_value != PROTO_69845_APP_OAD_TRANSFILE_START) { reason = 5; goto out; } if (act_resp_single->result.dar != PROTO_69845_APP_DAR_SUCCESS) { reason = 6; goto out; } out: if (reason) { return ERR_FAIL; } return ERR_OK; } iot_pkt_t *proto_69845_build_file_data_msg(uint8_t *file_data, uint16_t data_len, uint16_t block_index, uint8_t *server_addr) { uint16_t i = 0; uint16_t len; uint8_t *data; uint8_t info_len_byte = 0; uint8_t *app_data; iot_pkt_t *pkt = NULL; iot_pkt_t *tmp_pkt = NULL; server_addr_info_t server_info = { 0 }; proto_69845_app_action_req_single_t *req_info; server_info.len = PROTO_69845_SA_LEN; server_info.type = PROTO_69845_SA_TYPE_SIG; iot_mac_addr_cpy(server_info.addr, server_addr); len = sizeof(*req_info) + data_len; if (data_len > 255) { info_len_byte = 2; } else if (data_len > 127) { info_len_byte = 1; } tmp_pkt = iot_pkt_alloc(len, IOT_SMART_GRID_MID); if (tmp_pkt == NULL) { IOT_ASSERT(0); } data = iot_pkt_data(tmp_pkt); req_info = (proto_69845_app_action_req_single_t *)data; req_info->omd.method_id = PROTO_OMD_TRANSFILE_DATA_METHOD_ID; req_info->omd.oi = PROTO_69845_APP_OI_FILETRANS_BLOCK; req_info->omd.operation_mode = 0; req_info->data.data_type = PROTO_69845_APP_DATA_STRUCTURE; app_data = data + sizeof(*req_info); /* element cnt in structure, it's always 2 */ app_data[i++] = 2; /* element1, block number, type is long-unsigned */ app_data[i++] = PROTO_69845_APP_DATA_LONG_UNSIGNED; /* long-unsigned size, 2 bytes */ iot_uint16_to_bytes(block_index, app_data + i, 1); i += PROTO_69845_METER_DATA_LONG_LEN; /* element2, block data, type is octet-string */ app_data[i++] = PROTO_69845_APP_DATA_OCTET_STRING; if (info_len_byte == 0) { app_data[i++] = (uint8_t)data_len; } else if (info_len_byte == 1) { app_data[i++] = 0x80 | info_len_byte; app_data[i++] = (uint8_t)data_len; } else if (info_len_byte == 2) { app_data[i++] = 0x80 | info_len_byte; iot_uint16_to_bytes(data_len, app_data + i, 1); i += PROTO_69845_METER_DATA_LONG_LEN; } os_mem_cpy(app_data + i, file_data, data_len); i += data_len; pkt = proto_69845_build_action_req_single_msg(req_info, i, &server_info); if (tmp_pkt) { iot_pkt_free(tmp_pkt); } return pkt; } uint32_t proto_69845_handle_file_data_rsp(uint8_t *data, uint32_t data_len) { uint8_t reason = 0; uint32_t oad_value; apdu_info_t apdu_desc = { 0 }; proto_69845_frame_head_info_t *hdr_698; proto_69845_apdu_t *apdu; proto_69845_app_action_resp_t *act_resp; proto_69845_app_action_resp_normal_t *act_resp_single; if (ERR_OK != proto_69845_parse(&data, &data_len, &hdr_698, &apdu_desc)) { reason = 1; goto out; } apdu = (proto_69845_apdu_t *)apdu_desc.ptr; if (apdu_desc.len < (sizeof(*apdu) + sizeof(*act_resp) + sizeof(*act_resp_single))) { reason = 2; goto out; } if (apdu->type != PROTO_69845_S_APP_ACTION_RESP) { reason = 3; goto out; } act_resp = (proto_69845_app_action_resp_t*)apdu->data; if (act_resp->data_type != PROTO_69845_APP_ACTION_NORMAL) { reason = 4; goto out; } act_resp_single = (proto_69845_app_action_resp_normal_t*)act_resp->data; oad_value = iot_bytes_to_uint32((uint8_t*)&act_resp_single->result.omd.oi, 1); if (oad_value != PROTO_69845_APP_OAD_TRANSFILE_DATA) { reason = 5; goto out; } if (act_resp_single->result.dar != PROTO_69845_APP_DAR_SUCCESS) { reason = 6; goto out; } out: if (reason) { return ERR_FAIL; } return ERR_OK; } iot_pkt_t *proto_69845_build_file_exe_msg(iot_time_tm_t *time, uint8_t *server_addr) { iot_pkt_t *pkt = NULL; iot_pkt_t *tmp_pkt = NULL; uint16_t i = 0; uint8_t *app_data; proto_69845_app_action_req_single_t *req_info; proto_69845_app_data_time_s_t *times; server_addr_info_t server_info = {0}; server_info.len = PROTO_69845_SA_LEN; server_info.type = PROTO_69845_SA_TYPE_SIG; iot_mac_addr_cpy(server_info.addr, server_addr); tmp_pkt = iot_pkt_alloc(PROTO_69845_ACTION_REQUEST_COMMON_LEN, IOT_SMART_GRID_MID); if (tmp_pkt == NULL) { IOT_ASSERT(0); } req_info = (proto_69845_app_action_req_single_t *)iot_pkt_data(tmp_pkt); req_info->omd.method_id = PROTO_OMD_TRANSFILE_INFO_EXE_METHOD_ID; req_info->omd.oi = PROTO_69845_APP_OI_FILETRANS_BLOCK; req_info->omd.operation_mode = 0; req_info->data.data_type = PROTO_69845_APP_DATA_STRUCTURE; app_data = (iot_pkt_data(tmp_pkt) + sizeof(*req_info)); app_data[i++] = 2; app_data[i++] = PROTO_69845_APP_DATA_TIME_S; times = (proto_69845_app_data_time_s_t*)(app_data + i); times->year = time->tm_year; times->month = time->tm_mon; times->day = time->tm_mday; times->hour = time->tm_hour; times->minute = time->tm_min; times->second = time->tm_sec; i += sizeof(proto_69845_app_data_time_s_t); app_data[i++] = PROTO_69845_APP_DATA_NULL; pkt = proto_69845_build_action_req_single_msg(req_info, i, &server_info); if (tmp_pkt) { iot_pkt_free(tmp_pkt); } return pkt; } uint32_t proto_69845_handle_file_exe_rsp(uint8_t *data, uint32_t data_len) { uint8_t reason = 0; uint32_t oad_value; apdu_info_t apdu_desc = { 0 }; proto_69845_frame_head_info_t *hdr_698; proto_69845_apdu_t *apdu; proto_69845_app_action_resp_t *act_resp; proto_69845_app_action_resp_normal_t *act_resp_single; if (ERR_OK != proto_69845_parse(&data, &data_len, &hdr_698, &apdu_desc)) { reason = 1; goto out; } apdu = (proto_69845_apdu_t *)apdu_desc.ptr; if (apdu_desc.len < (sizeof(*apdu) + sizeof(*act_resp) + sizeof(*act_resp_single))) { reason = 2; goto out; } if (apdu->type != PROTO_69845_S_APP_ACTION_RESP) { reason = 3; goto out; } act_resp = (proto_69845_app_action_resp_t*)apdu->data; if (act_resp->data_type != PROTO_69845_APP_ACTION_NORMAL) { reason = 4; goto out; } act_resp_single = (proto_69845_app_action_resp_normal_t*)act_resp->data; oad_value = iot_bytes_to_uint32((uint8_t*)&act_resp_single->result.omd.oi, 1); if (oad_value != PROTO_69845_APP_OAD_TRANSFILE_EXE) { reason = 5; goto out; } if (act_resp_single->result.dar != PROTO_69845_APP_DAR_SUCCESS) { reason = 6; goto out; } out: if (reason) { return ERR_FAIL; } return ERR_OK; } #else /* PLC_SUPPORT_STA_ROLE */ iot_pkt_t *proto_69845_build_get_req_msg( proto_69845_app_get_req_info_t* req_info, const server_addr_info_t* server_info) { (void)req_info; (void)server_info; return NULL; } iot_pkt_t *proto_69845_build_comdcb_msg(uint32_t baud, const server_addr_info_t *server_info, uint8_t sn) { (void)baud; (void)server_info; (void)sn; return NULL; } iot_pkt_t *proto_69845_build_get_req_msg_with_rn( proto_69845_app_get_list_req_info_t* req_info, const server_addr_info_t* server_info) { (void)req_info; (void)server_info; return NULL; } iot_pkt_t *proto_69845_build_get_version_msg_with_rn( const server_addr_info_t *server_info, uint8_t sn) { (void)server_info; (void)sn; return NULL; } iot_pkt_t *proto_69845_build_apdu_data_with_rn_msg(uint8_t *apdu_data, uint32_t data_len, const server_addr_info_t* server_info) { (void)apdu_data; (void)data_len; (void)server_info; return NULL; } iot_pkt_t *proto_69845_action_single_ack(addr_info_t *addr_info, proto_69845_app_piid_t *piid, proto_69845_app_omd_t *omd, uint8_t dar) { (void)addr_info; (void)piid; (void)omd; (void)dar; return NULL; } iot_pkt_t * proto_69845_build_file_info_msg(uint32_t file_size, uint16_t file_crc, uint16_t block_size, uint32_t hw_ver, uint32_t sw_ver, uint32_t loader_id, uint8_t *server_addr) { (void)file_size; (void)file_crc; (void)block_size; (void)hw_ver; (void)sw_ver; (void)loader_id; (void)server_addr; return NULL; } uint32_t proto_69845_handle_file_info_rsp(uint8_t *data, uint32_t data_len) { (void)data; (void)data_len; return ERR_OK; } iot_pkt_t *proto_69845_build_file_data_msg(uint8_t *data, uint16_t data_len, uint16_t block_index, uint8_t *server_addr) { (void)data; (void)data_len; (void)block_index; (void)server_addr; return NULL; } uint32_t proto_69845_handle_file_data_rsp(uint8_t *data, uint32_t data_len) { (void)data; (void)data_len; return ERR_OK; } iot_pkt_t *proto_69845_build_file_exe_msg(iot_time_tm_t *time, uint8_t *server_addr) { (void)time; (void)server_addr; return NULL; } uint32_t proto_69845_handle_file_exe_rsp(uint8_t *data, uint32_t data_len) { (void)data; (void)data_len; return ERR_OK; } #endif /* PLC_SUPPORT_STA_ROLE */