/* * Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved. * Description: MRS cco 1376.2 handle. */ #include "mrs_cco_1376_2.h" #include "mrs_proto_1376_2.h" #include "mrs_msg.h" #include "mrs_common_uart.h" #include "mrs_common_tools.h" #include "mrs_cco_mr_list.h" #include "mrs_cco_xr.h" #include "mrs_cco_pr.h" #include "mrs_cco_archives.h" #include "mrs_cco_srv.h" #include "mrs_cco_evt.h" #include "mrs_cco_queue.h" #include "mrs_cco_upg.h" #include "mrs_cco_broadcast.h" #include "mrs_cco_tf.h" #include "soc_mdm_pi.h" #include "mrs_cco_tf.h" #include "mrs_dfx.h" #include "app_nv.h" #if defined(PRODUCT_CFG_PRODUCT_TYPE_CCO) #define MRS_10_F21_FIX_LEN 3 #define MRS_10_F21_NODE_LEN 11 #define MRS_TOPO_ROLE_INVALID 0 #define MRS_TOPO_ROLE_STA 1 #define MRS_TOPO_ROLE_PROXY 2 #define MRS_TOPO_ROLE_CCO 4 #define MRS_MR_TYPE_PR_F1_F1 0 #define MRS_MR_TYPE_XR_02_F1 1 #define MRS_MR_TYPE_XR_02_F255 2 #define MRS_MR_TYPE_XR_13_F1 3 #define MRS_MR_TYPE_XR_13_F255 4 typedef td_u32 (*mrs_1376_2_afn_func)(mrs_fn_param *param); typedef td_u32 (*mrs_create_plc_frame)(mr_task_node *, td_pbyte, td_u16); typedef td_u32 (*mrs_get_mr_data)(mrs_proto_1376_2_frame *, td_pbyte *, td_u16 *, td_u8 *, td_u8 *); typedef struct { td_u32 afn_data; mrs_1376_2_afn_func func; } mrs_afn_func_map; typedef struct { td_u8 state_lo; td_u8 state_ml; td_u8 state_mh; td_u8 state_hi; td_u16 wait_time; } mrs_afn_00_f1; #pragma pack(1) typedef struct { td_u8 node_addr[MRS_METER_ADDR_LEN]; td_u16 node_tei; td_u8 node_parent_addr[MRS_METER_ADDR_LEN]; td_u8 signal; /* signal itensity */ td_u8 stat_nw; /* net status */ td_u32 longitude; /* longitude: 6 bits valid */ td_u32 latitude; /* latitude: 6 bits valid */ td_u8 phase; /* phase */ td_u8 pad[MRS_AFN_10_F27_NODE_PAD]; /* pad(3) */ } mrs_afn_10_f27_node; #pragma pack() td_u32 mrs_cco_queue_rx(mrs_fn_param *param); td_u32 mrs_afn_0301_buf(td_pbyte buffer, td_u16 length); td_u32 mrs_afn_0310_buf(td_pbyte *buffer, td_u16 *length); td_u32 mrs_afn_10_f2_get_numbers(td_u16 *start_num, td_u8 *meter_num, td_u16 meters_total); td_u32 mrs_afn_10_f2_fill_reply_content(td_u8 *reply_content, td_u16 reply_content_len, td_u16 start_num, td_u8 meter_num); td_void mrs_afn_10_f27_get_numbers(td_u16 *start_num, td_u8 *node_num); td_u16 mrs_afn_10_f27_get_start_index(const ext_mdm_nm_topo_node_info *topo_info, td_u16 start_num); td_void mrs_afn_10_f27_get_node_info(ext_mdm_nm_topo_node_info *topo_info, const td_u8 *phase_info, td_u16 i, mrs_afn_10_f27_node *node); mrs_create_plc_frame mrs_1376_2_mr_handle_get_node_info(const mrs_proto_1376_2_frame *frame, td_u8 option, mr_task_node *node); td_u32 mrs_afn_10_f230_fill_up_data(td_u8 *payload, td_u16 start_seq, td_u8 need_node_num, td_u8 *actual_report_num); td_u32 mrs_afn_10_f230_fill_node_info(ext_mdm_nm_topo_node_info *topo_info, td_u8 *payload, td_u16 *data_offset, td_u16 my_tei); td_u32 mrs_query_topo_down_check(td_bool *start_flag, mrs_fn_param *param, td_u16 *start_seq, td_u8 *query_num); td_u32 mrs_afn10_query_data_check(mrs_fn_param *afn_param, td_u8 *query_num, td_u16 *start_seq, td_bool is_create_deny); td_u32 mrs_1376_2_afn_xx_xx(mrs_fn_param *param); td_u32 mrs_1376_2_afn_00_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_00_f2(mrs_fn_param *param); td_u32 mrs_1376_2_afn_01_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_01_f2(mrs_fn_param *param); td_u32 mrs_1376_2_afn_01_f3(mrs_fn_param *param); td_u32 mrs_1376_2_afn_02_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_02_f255(mrs_fn_param *param); td_u32 mrs_1376_2_afn_03_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_03_f4(mrs_fn_param *param); td_u32 mrs_1376_2_afn_03_f10(mrs_fn_param *param); td_u32 mrs_1376_2_afn_03_f16(mrs_fn_param *param); td_u32 mrs_1376_2_afn_05_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_05_f3(mrs_fn_param *param); td_u32 mrs_1376_2_afn_05_f16(mrs_fn_param *param); td_u32 mrs_1376_2_afn_05_f255(mrs_fn_param *param); td_u32 mrs_1376_2_afn_10_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_10_f2(mrs_fn_param *param); td_u32 mrs_1376_2_afn_10_f4(mrs_fn_param *param); td_u32 mrs_1376_2_afn_10_f27(mrs_fn_param *param); td_u32 mrs_1376_2_afn_10_f230(mrs_fn_param *param); td_u32 mrs_1376_2_afn_11_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_11_f2(mrs_fn_param *param); td_u32 mrs_1376_2_afn_11_f5(mrs_fn_param *param); td_u32 mrs_1376_2_afn_11_f6(mrs_fn_param *param); td_u32 mrs_1376_2_afn_12_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_12_f2(mrs_fn_param *param); td_u32 mrs_1376_2_afn_12_f3(mrs_fn_param *param); td_u32 mrs_1376_2_afn_13_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_13_f255(mrs_fn_param *param); td_u32 mrs_1376_2_afn_15_f1(mrs_fn_param *param); td_u32 mrs_1376_2_afn_f1_f1(mrs_fn_param *param); td_u32 mrs_1376_2_mr_handle(mrs_fn_param *param, td_u8 option); td_u32 mrs_cco_get_mr_data_13_f1(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny); td_u32 mrs_cco_get_mr_data_13_f255(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny); td_u32 mrs_cco_get_mr_data_02_f1(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny); td_u32 mrs_cco_get_mr_data_02_f255(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny); td_u32 mrs_cco_get_mr_data_f1_f1(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny); /* !!!NOTICE!!! elements in this array must in asending order by afn. And searching by halving method */ mrs_afn_func_map g_afn_func_map[] = { { 0x00000001, mrs_1376_2_afn_00_f1 }, { 0x00000002, mrs_1376_2_afn_00_f2 }, { 0x00000101, mrs_1376_2_afn_01_f1 }, { 0x00000102, mrs_1376_2_afn_01_f2 }, { 0x00000103, mrs_1376_2_afn_01_f3 }, { 0x00000201, mrs_1376_2_afn_02_f1 }, { 0x000002FF, mrs_1376_2_afn_02_f255 }, { 0x00000301, mrs_1376_2_afn_03_f1 }, { 0x00000304, mrs_1376_2_afn_03_f4 }, { 0x0000030A, mrs_1376_2_afn_03_f10 }, { 0x00000310, mrs_1376_2_afn_03_f16 }, { 0x00000501, mrs_1376_2_afn_05_f1 }, { 0x00000503, mrs_1376_2_afn_05_f3 }, { 0x00000510, mrs_1376_2_afn_05_f16 }, { 0x000005FF, mrs_1376_2_afn_05_f255 }, { 0x00001001, mrs_1376_2_afn_10_f1 }, { 0x00001002, mrs_1376_2_afn_10_f2 }, { 0x00001004, mrs_1376_2_afn_10_f4 }, { 0x0000101B, mrs_1376_2_afn_10_f27 }, { 0x000010E6, mrs_1376_2_afn_10_f230 }, { 0x00001101, mrs_1376_2_afn_11_f1 }, { 0x00001102, mrs_1376_2_afn_11_f2 }, { 0x00001105, mrs_1376_2_afn_11_f5 }, { 0x00001106, mrs_1376_2_afn_11_f6 }, { 0x00001201, mrs_1376_2_afn_12_f1 }, { 0x00001202, mrs_1376_2_afn_12_f2 }, { 0x00001203, mrs_1376_2_afn_12_f3 }, { 0x00001301, mrs_1376_2_afn_13_f1 }, { 0x000013FF, mrs_1376_2_afn_13_f255 }, { 0x00001501, mrs_1376_2_afn_15_f1 }, { 0x0000f101, mrs_1376_2_afn_f1_f1 }, }; td_u32 mrs_cco_1376_2_afn_dispatch(mrs_proto_1376_2_frame *frame, td_pbyte *buffer, td_u16 *length); mrs_1376_2_afn_func mrs_cco_376_2_find_afn_handler(td_u8 afn, td_u8 fn); td_void mrs_msg_on_app_frame_rx_13762(EXT_CONST mrs_queue_msg *msg) { td_u32 ret; mrs_proto_1376_2_frame *frame = TD_NULL; td_pbyte payload = (td_pbyte)msg->param1; td_u16 length = msg->param0; if (payload == TD_NULL) { return; } mrs_dfx_uart_chl_rx(payload, length, TD_TRUE); ret = mrs_proto_1376_2_decode(payload, length, &frame); if (ret == EXT_ERR_SUCCESS && frame != TD_NULL) { td_pbyte out_buf = TD_NULL; td_u16 out_len = 0; ret = mrs_cco_1376_2_afn_dispatch(frame, &out_buf, &out_len); if ((ret == EXT_ERR_SUCCESS) && (out_buf != TD_NULL)) { mrs_uart_tx(out_buf, out_len); } mrs_free(out_buf); mrs_free(frame); } else { mrs_dfx_uart_chl_err_rx(length, ret, TD_TRUE); } mrs_dfx_uart_chl_rx_frame(length, ret, TD_TRUE); mrs_free(payload); } mrs_1376_2_afn_func mrs_cco_376_2_find_afn_handler(td_u8 afn, td_u8 fn) { td_u32 afn_data = (td_u16)((afn << 8) + fn); /* AFN: high 8 bit */ td_s32 low, high, mid; low = 0; if (afn_data == g_afn_func_map[low].afn_data) { return g_afn_func_map[low].func; } high = ext_array_count(g_afn_func_map) - 1; if (afn_data == g_afn_func_map[high].afn_data) { return g_afn_func_map[high].func; } while (low <= high) { mid = low + (high - low) / 2; /* get middle index by devide 2 */ if (afn_data == g_afn_func_map[mid].afn_data) { return g_afn_func_map[mid].func; } if (afn_data < g_afn_func_map[mid].afn_data) { high = mid - 1; } else { low = mid + 1; } } return mrs_1376_2_afn_xx_xx; } td_u32 mrs_cco_1376_2_afn_dispatch(mrs_proto_1376_2_frame *frame, td_pbyte *buffer, td_u16 *length) { mrs_1376_2_afn_func afn_func = mrs_cco_376_2_find_afn_handler(frame->afn, frame->fn); mrs_fn_param param; param.frame = frame; param.out_buf = buffer; param.out_len = length; param.afn = frame->afn; param.fn = frame->fn; param.rsv = 0; return afn_func(¶m); } td_u32 mrs_cco_1376_2_ack_frame(const mrs_fn_param *dl_frame, td_u16 wait_time) { mrs_fn_param param; mrs_afn_00_f1 data; (td_void) memcpy_s(¶m, sizeof(param), dl_frame, sizeof(mrs_fn_param)); param.afn = 0; param.fn = 1; (td_void) memset_s(&data, sizeof(data), 0, sizeof(data)); data.wait_time = wait_time; return mrs_cco_1376_2_easy_encode(¶m, (td_pbyte)&data, (td_u16)sizeof(data)); } td_u32 mrs_cco_1376_2_deny_frame(const mrs_fn_param *dl_frame, td_u8 deny) { mrs_fn_param param; (td_void) memcpy_s(¶m, sizeof(param), dl_frame, sizeof(mrs_fn_param)); param.afn = 0; param.fn = 2; /* deny fn: 2 */ return mrs_cco_1376_2_easy_encode(¶m, (td_pbyte)&deny, (td_u16)sizeof(deny)); } td_u32 mrs_cco_1376_2_easy_encode(mrs_fn_param *param, td_pbyte data, td_u16 length) { mrs_proto_1376_2_encode encode; if ((param == TD_NULL) || ((length != 0) && (data == TD_NULL))) { return EXT_ERR_INVALID_PARAMETER; } (td_void) memset_s(&encode, sizeof(encode), 0, sizeof(encode)); encode.seq = param->frame->seq; encode.afn = param->afn; encode.fn = param->fn; encode.length = length; encode.data = data; return mrs_proto_1376_2_create_frame(&encode, param->out_buf, param->out_len); } td_u32 mrs_1376_2_afn_xx_xx(mrs_fn_param *param) { /* reply denial frame, when received unsupported frame */ return mrs_cco_1376_2_deny_frame(param, MRS_1376_2_DENY_FN_NOT_EXIST); } td_u32 mrs_cco_queue_rx(mrs_fn_param *param) { mrs_cco_queue *cco_queue = mrs_get_cco_queue(); mrs_cco_queue_item *item = TD_NULL; mrs_cco_queue_item *temp = TD_NULL; ext_unref_param(param); mrs_timer_stop(MRS_TIMER_ID_CCO_TO_HOST); if (mrs_cco_queue_get_fsm() != FSM_CCO_QUEUE_WAIT_ACK) { return EXT_ERR_SUCCESS; } item = (mrs_cco_queue_item *)mrs_queue_top(&cco_queue->queue); if (item == TD_NULL) { return EXT_ERR_FAILURE; } if (item->rx_handle) { item->rx_handle(item->param); } temp = (mrs_cco_queue_item *)mrs_queue_top(&cco_queue->queue); if (temp == item) { mrs_cco_queue_end(cco_queue); } return EXT_ERR_SUCCESS; } /* * 376.2 frame processing function */ td_u32 mrs_1376_2_afn_00_f1(mrs_fn_param *param) { return mrs_cco_queue_rx(param); } td_u32 mrs_1376_2_afn_00_f2(mrs_fn_param *param) { return mrs_cco_queue_rx(param); } /* AFN=01H initialization */ td_u32 mrs_1376_2_afn_01_f1(mrs_fn_param *param) { static td_bool recv_flag = TD_FALSE; if (recv_flag == TD_TRUE) { return mrs_cco_1376_2_deny_frame(param, MRS_1376_2_DENY_CCO_BUSY); } recv_flag = TD_TRUE; mrs_cco_1376_2_ack_frame(param, 1); mrs_timer_start(MRS_TIMER_ID_CCO_REBOOT, MRS_CCO_REBOOT_TIME, EXT_TIMER_TYPE_ONCE); return EXT_ERR_SUCCESS; } td_u32 mrs_1376_2_afn_01_f2(mrs_fn_param *param) { if (mrs_archives_clear() != EXT_ERR_SUCCESS) { return mrs_cco_1376_2_deny_frame(param, MRS_1376_2_DENY_TIMEOUT); } return mrs_cco_1376_2_ack_frame(param, 0); } td_u32 mrs_1376_2_afn_01_f3(mrs_fn_param *param) { return mrs_cco_1376_2_ack_frame(param, 0); } /* AFN=02H data transmit */ td_u32 mrs_1376_2_afn_02_f1(mrs_fn_param *param) { mrs_cco_upg_reset_file_rx_timeout(); /* Reset timeout calculator when CCO downloads file */ return mrs_1376_2_mr_handle(param, MRS_XR_02H_F1); } td_u32 mrs_1376_2_afn_02_f255(mrs_fn_param *param) { mrs_cco_upg_reset_file_rx_timeout(); /* Reset timeout calculator when CCO downloads file */ return mrs_1376_2_mr_handle(param, MRS_XR_02H_F255); } /* AFN=03H inquiry */ td_u32 mrs_afn_0301_buf(td_pbyte buffer, td_u16 length) { ext_mdm_user_info inf; if (length < 9) { /* buffer length: 9 */ return EXT_ERR_INVALID_PARAMETER; } uapi_get_user_info(&inf); /* use little-endian */ *buffer++ = (td_u8)inf.manu_code[0]; *buffer++ = (td_u8)inf.manu_code[1]; *buffer++ = (td_u8)inf.chip_code[0]; *buffer++ = (td_u8)inf.chip_code[1]; mrs_convert_int_to_bcd(inf.day, buffer++, 1); mrs_convert_int_to_bcd(inf.month, buffer++, 1); mrs_convert_int_to_bcd(inf.year, buffer++, 1); *buffer++ = (td_u8)(inf.sw_ver & 0xff); *buffer++ = (td_u8)((inf.sw_ver >> 8) & 0xff); /* low 8 bit */ return EXT_ERR_SUCCESS; } td_u32 mrs_1376_2_afn_03_f1(mrs_fn_param *param) { td_u32 ret; td_u8 buf[9] = { 0 }; /* buf length: 9 */ ret = mrs_afn_0301_buf(buf, sizeof(buf)); if (ret != EXT_ERR_SUCCESS) { return ret; } return mrs_cco_1376_2_easy_encode(param, buf, sizeof(buf)); } td_u32 mrs_1376_2_afn_03_f4(mrs_fn_param *param) { mrs_cco_srv_ctx *cco = mrs_cco_get_srv_ctx(); if (cco == TD_NULL) { return EXT_ERR_NO_INITILIZATION; } return mrs_cco_1376_2_easy_encode(param, cco->main_node, sizeof(cco->main_node)); } #pragma pack(1) typedef struct { td_u8 comm_mode : 4; /* bytes of local communication mode: communication mode */ td_u8 route_type : 1; /* bytes of local communication mode: route manage mode */ td_u8 node_mode : 1; /* bytes of local communication mode: measured point info mode */ td_u8 period_mr : 2; /* bytes of local communication mode: periodically read meter mode */ td_u8 trans_delay : 3; /* bytes of local communication mode: supportable for transmitting delay parameter */ td_u8 fail_switch : 2; /* bytes of local communication mode: failed node change starting mode */ td_u8 bc_confirm : 1; /* bytes of local communication mode: affirm braodcast command mode */ td_u8 bc_cmd_ch : 2; /* bytes of local communication mode: broadcast command execute mode with channel */ td_u8 ch_num : 4; /* bytes of local communication mode:quantity of channel */ td_u8 power_down_inf : 4; /* bytes of local communication mode:power down info of low voltage grid */ td_u8 speed_num : 3; /* bytes of local communication mode: quantity of rate, equal to 1 */ td_u8 rsv0 : 5; td_u8 rsv1; td_u8 rsv2; td_u8 xr_timeout; /* maximum monitoring timeout time of slave node (unit : s) */ td_u16 bc_cmd_timeout; /* maximum timeout time of broadcast command (unit : s) */ td_u16 frame_max_len; /* maximum supportable length of frame */ td_u16 upg_pkt_max; /* maximum supportable length of a package for file transmit */ td_u8 upg_wait_time; /* waitting time of upgrade */ td_u8 main_node[EXT_METER_ADDR_LEN]; /* address of main node */ td_u16 meter_max; /* maximum supportable quantity of slave nodes */ td_u16 meter_num; /* quantity of present secondary nodes */ td_u8 release_date[3]; /* release date of communication module protocol (BCD) ,3bytes */ td_u8 backup_date[3]; /* latest filed date of communication module protocol (BCD) , 3bytes */ td_u8 version_inf[9]; /* manufacturer code and version info of communication module, 9bytes */ td_u16 speed_rate : 15; /* communication rate, equal to 1 */ td_u16 speed_unit : 1; /* rate unit identification */ } mrs_cco_local_runtime_inf; #pragma pack() td_u32 mrs_afn_0310_buf(td_pbyte *buffer, td_u16 *length) { mrs_cco_local_runtime_inf *inf = (mrs_cco_local_runtime_inf *)mrs_malloc(sizeof(mrs_cco_local_runtime_inf)); mrs_cco_srv_ctx *cco = mrs_cco_get_srv_ctx(); if (inf == TD_NULL) { return EXT_ERR_MALLOC_FAILUE; } if (cco == TD_NULL) { mrs_free(inf); return EXT_ERR_NO_INITILIZATION; } (td_void) memset_s(inf, sizeof(mrs_cco_local_runtime_inf), 0, sizeof(mrs_cco_local_runtime_inf)); inf->comm_mode = 2; /* 2: broadband power line communication */ inf->route_type = 1; /* with route management feature */ inf->node_mode = 1; /* need send slave node info */ inf->period_mr = 1; /* 01 means communication module only support periodically read meter by concentrator */ inf->trans_delay = 0; /* supportable for transmit delay parameter: unsupported */ inf->fail_switch = 2; /* 2: failed node starting mode changed by concentrator */ inf->bc_confirm = 1; /* reply affirm frame before executing broadcast command */ inf->bc_cmd_ch = 0; /* execute broadcast command without channel identification */ inf->ch_num = 1; /* quantity of carrier channels */ inf->speed_num = 1; /* quantity of rate */ inf->xr_timeout = MRS_CFG_XR_13762_TIMEOUT; inf->bc_cmd_timeout = MRS_CFG_BC_TIMEOUT; inf->frame_max_len = MRS_DATA_BUFFER_SIZE; inf->upg_pkt_max = MRS_CFG_UPG_PKT_MAX; inf->upg_wait_time = MRS_CFG_UPG_WAIT_TIME; (td_void) memcpy_s(inf->main_node, sizeof(inf->main_node), cco->main_node, sizeof(cco->main_node)); inf->meter_max = MRS_CFG_METER_MAX; inf->meter_num = mrs_archives_get_number(); inf->release_date[0] = 0x18; inf->release_date[1] = 0x09; inf->release_date[2] = 0x13; /* index 2: filled with 0x13 */ inf->backup_date[0] = 0x18; inf->backup_date[1] = 0x09; inf->backup_date[2] = 0x13; /* index 2: filled with 0x13 */ if (mrs_afn_0301_buf(inf->version_inf, sizeof(inf->version_inf)) != EXT_ERR_SUCCESS) { mrs_free(inf); return EXT_ERR_INVALID_PARAMETER; } inf->speed_rate = 0; inf->speed_unit = 1; *buffer = (td_pbyte)inf; *length = sizeof(mrs_cco_local_runtime_inf); return EXT_ERR_SUCCESS; } td_u32 mrs_1376_2_afn_03_f10(mrs_fn_param *param) { td_u32 ret; td_pbyte buf = TD_NULL; td_u16 buf_len = 0; ret = mrs_afn_0310_buf(&buf, &buf_len); if (ret != EXT_ERR_SUCCESS) { return ret; } ret = mrs_cco_1376_2_easy_encode(param, buf, buf_len); mrs_free(buf); return ret; } td_void mrs_cco_report_afn_03f10(td_void) { mrs_proto_1376_2_encode encode; mrs_cco_srv_ctx *cco = mrs_cco_get_srv_ctx(); td_u32 ret; td_pbyte buf = TD_NULL; td_u16 buf_len = 0; td_u16 payload_len = 0; td_pbyte payload = TD_NULL; mrs_cco_queue_item *item = TD_NULL; ret = mrs_afn_0310_buf(&buf, &buf_len); if (ret != EXT_ERR_SUCCESS) { return; } do { (td_void) memset_s(&encode, sizeof(encode), 0, sizeof(encode)); encode.afn = 3; /* afn equal to 3 */ encode.fn = 10; /* fn equal to 10 */ encode.seq = ++cco->seq; encode.length = buf_len; encode.data = buf; ret = mrs_proto_1376_2_create_frame(&encode, &payload, &payload_len); if (ret != EXT_ERR_SUCCESS) { break; } item = (mrs_cco_queue_item *)mrs_malloc(sizeof(mrs_cco_queue_item) + payload_len); if (item == TD_NULL) { break; } (td_void) memset_s(item, sizeof(mrs_cco_queue_item) + payload_len, 0, sizeof(mrs_cco_queue_item) + payload_len); item->valid = TD_TRUE; item->afn = encode.afn; item->fn = encode.fn; item->retry_max = 0; item->timeout = 500; /* element timeout time: 500 */ item->data_len = payload_len; if (memcpy_s(item->data, item->data_len, payload, payload_len) != EOK) { mrs_free(payload); mrs_free(buf); mrs_free(item); return; } mrs_cco_queue_enqueue(item); mrs_cco_queue_active(); } while (0); mrs_free(payload); mrs_free(buf); } td_u32 mrs_1376_2_afn_03_f11(mrs_fn_param *param) { mrs_proto_1376_2_frame *frame = param->frame; td_u8 payload[33] = { 0 }; /* payload length equal to 33 */ if (frame->data_len != 1) { return EXT_ERR_BAD_DATA; } payload[0] = frame->content[0]; switch (frame->content[0]) { case 0x00: case 0x11: payload[1] = 0x03; /* 0000 0011 1,2 */ break; case 0x01: case 0x12: payload[1] = 0x07; /* 0000 0111 1,2,3 */ break; case 0x03: payload[1] = 0x09; /* 0000 1001 1,4 */ payload[2] = 0x86; /* index 2: 0x86: 1000 0110 10,11,16 */ break; case 0x05: payload[1] = 0x01; /* 0000 0001 1 */ payload[2] = 0x80; /* index 2: 0x80: 1000 0000 16 */ break; case 0x13: case 0x15: case 0xF1: payload[1] = 0x01; /* 0000 0001 1 */ break; case 0x06: payload[1] = 0x1C; /* 0001 1100 3,4,5 */ break; case 0x10: payload[1] = 0x0B; /* 0000 1011 1,2,4 */ payload[3] = 0x10; /* index 3: 0x10: 0001 0000 21 */ break; default: break; } return mrs_cco_1376_2_easy_encode(param, payload, sizeof(payload)); } td_u32 mrs_1376_2_afn_03_f16(mrs_fn_param *param) { td_u8 freq = uapi_get_whole_net_work_freq(); return mrs_cco_1376_2_easy_encode(param, &freq, sizeof(freq)); } td_u32 mrs_1376_2_afn_05_f1(mrs_fn_param *param) { mrs_cco_srv_ctx *cco = mrs_cco_get_srv_ctx(); mrs_proto_1376_2_frame *frame = param->frame; app_dev_addr_inf nv = { { 0 }, { 0 } }; td_u32 ret; errno_t err; if (cco == TD_NULL) { return EXT_ERR_NO_INITILIZATION; } if (frame->data_len != sizeof(cco->main_node)) { return mrs_cco_1376_2_deny_frame(param, MRS_1376_2_DENY_LEN_ERR); } if (memcmp(cco->main_node, frame->content, EXT_METER_ADDR_LEN) == 0) { return mrs_cco_1376_2_ack_frame(param, 0); } err = memcpy_s(cco->main_node, sizeof(cco->main_node), frame->content, frame->data_len); if (err != EOK) { return mrs_cco_1376_2_deny_frame(param, MRS_1376_2_DENY_TIMEOUT); } mrs_cco_1376_2_ack_frame(param, 0); ret = uapi_nv_read(ID_NV_APP_DEV_ADDR_INF, &nv, sizeof(nv)); if (ret == EXT_ERR_SUCCESS) { mrs_hex_invert(nv.dev_addr, (td_u16)sizeof(nv.dev_addr)); if (memcmp(nv.dev_addr, cco->main_node, sizeof(cco->main_node)) != 0) { td_u8 mac[EXT_METER_ADDR_LEN] = { 0 }; err = memcpy_s(nv.dev_addr, sizeof(nv.dev_addr), cco->main_node, sizeof(cco->main_node)); if (err == EOK) { mrs_hex_invert(nv.dev_addr, (td_u16)sizeof(nv.dev_addr)); uapi_nv_write(ID_NV_APP_DEV_ADDR_INF, &nv, sizeof(nv)); } mrs_convert_meter_to_mac(cco->main_node, sizeof(cco->main_node), mac, sizeof(mac)); uapi_set_cco_mac_addr(mac); } } return EXT_ERR_SUCCESS; } /* AFN=05H control command */ td_u32 mrs_1376_2_afn_05_f3(mrs_fn_param *param) { td_u32 ret; mrs_proto_1376_2_frame *frame = param->frame; td_u16 data_len = frame->data_len; td_u8 *content = frame->content; td_u8 deny_code = MRS_1376_2_DENY_TIMEOUT; do { if (data_len != MRS_CCO_BC_CTRL_LEN + MRS_CCO_BC_MSG_LEN_SIZE + content[1]) { deny_code = MRS_1376_2_DENY_LEN_ERR; ret = EXT_ERR_BAD_DATA; break; } ret = mrs_cco_broadcast_proc(&deny_code, (td_pbyte)&content[MRS_CCO_BC_CTRL_LEN + MRS_CCO_BC_MSG_LEN_SIZE], content[1]); } while (0); if (ret != EXT_ERR_SUCCESS) { mrs_cco_1376_2_deny_frame(param, deny_code); } else { mrs_cco_1376_2_ack_frame(param, MRS_CFG_BC_TIMEOUT); } return EXT_ERR_SUCCESS; } td_u32 mrs_1376_2_afn_05_f16(mrs_fn_param *param) { mrs_proto_1376_2_frame *frame = param->frame; td_u8 new_freq; td_u8 old_freq; if (frame->data_len != 1) { return mrs_cco_1376_2_deny_frame(param, MRS_1376_2_DENY_LEN_ERR); } new_freq = frame->content[0]; /* 1: 2.5M-5.7M_IS * 5: 0.5M-3.7M_IS */ if ((new_freq != 1) && (new_freq != 5)) { /* frequency must be 5: 0.5M-3.7M_IS */ return mrs_cco_1376_2_deny_frame(param, MRS_1376_2_DENY_INVALID_DATA); } old_freq = uapi_get_whole_net_work_freq(); if (new_freq != old_freq) { uapi_set_whole_net_work_freq(frame->content[0], 300); /* change frequency delay time: 300 */ return mrs_cco_1376_2_ack_frame(param, 300); /* wait time: 300 */ } return mrs_cco_1376_2_ack_frame(param, 0); } td_u32 mrs_1376_2_afn_05_f255(mrs_fn_param *param) { /* Long message type */ td_u32 ret; mrs_proto_1376_2_frame *frame = param->frame; td_u16 data_len = frame->data_len; td_u16 msg_len; td_u8 *content = frame->content; td_u8 deny_code = MRS_1376_2_DENY_TIMEOUT; do { msg_len = uapi_make_u16(content[1], content[2]); /* make 1 and 2 bytes into U16 */ if (data_len != MRS_CCO_BC_CTRL_LEN + MRS_CCO_BC_MSG_LONG_LEN_SIZE + msg_len) { deny_code = MRS_1376_2_DENY_LEN_ERR; ret = EXT_ERR_BAD_DATA; break; } ret = mrs_cco_broadcast_proc(&deny_code, (td_pbyte)&content[MRS_CCO_BC_CTRL_LEN + MRS_CCO_BC_MSG_LONG_LEN_SIZE], msg_len); } while (0); if (ret != EXT_ERR_SUCCESS) { mrs_cco_1376_2_deny_frame(param, deny_code); } else { mrs_cco_1376_2_ack_frame(param, MRS_CFG_BC_TIMEOUT); } return EXT_ERR_SUCCESS; } /* AFN=10H route inquiry */ td_u32 mrs_1376_2_afn_10_f1(mrs_fn_param *param) { td_u16 slave_num[2] = { 0 }; /* slave number use 2 bytes */ slave_num[0] = mrs_archives_get_number(); slave_num[1] = ARCHIVES_NUM_MAX; return mrs_cco_1376_2_easy_encode(param, (td_pbyte)slave_num, sizeof(slave_num)); } typedef struct { td_u8 node_addr[EXT_METER_ADDR_LEN]; td_u8 relay_level : 4; td_u8 quality : 4; td_u8 phase : 3; td_u8 protocol : 3; td_u8 rsv : 2; } mrs_afn_10_f2_node; td_u32 mrs_afn_10_f2_get_numbers(td_u16 *start_num, td_u8 *meter_num, td_u16 meters_total) { td_u32 ret = EXT_ERR_SUCCESS; td_u8 meter = *meter_num; td_u16 start = *start_num; do { /* if starting sequence start from 0, the quantity is one fewer than start from 1 */ if (start == 0) { if (meter > 0) { meter--; } } else { start--; } /* Calc enough memory */ if (meters_total <= start) { ret = EXT_ERR_FAILURE; break; } if (meters_total < (start + (td_u16)meter)) { meter = (td_u8)(meters_total - start); } if (meter > MRS_3762_SEC_NODE_MAX_NUM) { /* Out of range */ meter = MRS_3762_SEC_NODE_MAX_NUM; } } while (TD_FALSE); *meter_num = meter; *start_num = start; return ret; } td_u32 mrs_afn_10_f2_fill_reply_content(td_u8 *reply_content, td_u16 reply_content_len, td_u16 start_num, td_u8 meter_num) { td_u32 ret; meter_item *meter_items = TD_NULL; /* < The meter list after index */ td_u8 i; do { if (reply_content == TD_NULL) { ret = EXT_ERR_MALLOC_FAILUE; break; } /* Get meter addresses from archives */ ret = (td_u32)memset_s(reply_content, reply_content_len, 0, reply_content_len); if (ret != EOK) { ret = EXT_ERR_FAILURE; break; } meter_items = mrs_archives_get_by_idx(start_num); if (meter_items == TD_NULL) { ret = EXT_ERR_BAD_DATA; break; } /* Build reply */ for (i = 0; i < meter_num; i++) { mrs_afn_10_f2_node node; ret = (td_u32)memset_s(&node, sizeof(node), 0, sizeof(node)); ret |= (td_u32)memcpy_s(node.node_addr, sizeof(node.node_addr), meter_items[i].addr, sizeof(meter_items[i].addr)); node.protocol = (meter_items[i].protocol & 0x7); ret |= (td_u32)memcpy_s(reply_content + MRS_1376_2_SEC_NODE_INFO_LEN + i * sizeof(mrs_afn_10_f2_node), reply_content_len - (MRS_1376_2_SEC_NODE_INFO_LEN + i * sizeof(mrs_afn_10_f2_node)), &node, sizeof(node)); if (ret != EOK) { ret = EXT_ERR_FAILURE; break; } } } while (TD_FALSE); return ret; } td_u32 mrs_1376_2_afn_10_f2(mrs_fn_param *param) { td_u32 ret = EXT_ERR_BAD_DATA; mrs_proto_1376_2_frame *frame = param->frame; td_u16 meters_total = mrs_archives_get_number(); /* < Totoal meters in the archives */ td_u16 start_num, reply_content_len; /* < Start meter index */ td_u16 data_len = frame->data_len; td_u8 meter_num; /* < Required meter number */ td_u8 *content = frame->content; td_u8 *reply_content = 0; do { if (data_len < MRS_1376_2_SEC_NODE_INFO_LEN) { break; } if (meters_total == 0) { break; } /* Analyse content */ start_num = uapi_make_u16(content[0], content[1]); meter_num = content[2]; /* index 2 means meter number */ ret = mrs_afn_10_f2_get_numbers(&start_num, &meter_num, meters_total); if (ret != EXT_ERR_SUCCESS) { break; } if (meter_num > MRS_3762_SEC_NODE_MAX_NUM) { /* Out of range */ meter_num = MRS_3762_SEC_NODE_MAX_NUM; } /* Length = total meter number(2 bytes) + meter number replied(1 byte) + meter info */ reply_content_len = 2 + 1 + meter_num * sizeof(mrs_afn_10_f2_node); /* total meter 2B, number replied 1B */ reply_content = mrs_malloc(reply_content_len); ret = mrs_afn_10_f2_fill_reply_content(reply_content, reply_content_len, start_num, meter_num); if (ret != EXT_ERR_SUCCESS) { break; } } while (0); if (ret != EXT_ERR_SUCCESS) { mrs_free(reply_content); meter_num = 0; reply_content_len = MRS_1376_2_SEC_NODE_INFO_LEN; reply_content = mrs_malloc(reply_content_len); if (reply_content == TD_NULL) { return EXT_ERR_MALLOC_FAILUE; } } if (reply_content != TD_NULL) { if (memcpy_s(reply_content, reply_content_len, &meters_total, sizeof(meters_total)) == EOK) { reply_content[2] = meter_num; /* index 2 means meter number */ mrs_cco_1376_2_easy_encode(param, reply_content, reply_content_len); } } mrs_free(reply_content); return EXT_ERR_SUCCESS; } td_u32 mrs_1376_2_afn_10_f4(mrs_fn_param *param) { mrs_cco_srv_ctx *cco = mrs_cco_get_srv_ctx(); mrs_cco_evt_ctx *evt = mrs_cco_get_evt_ctx(); td_u8 buffer[16] = { 0 }; /* buffer length 16 */ td_u16 meter_num = mrs_archives_get_number(); /* * bytes of running status * [D0:D0] route finished identification: 1: route study finished; 0:unfinished * [D1:D1] working identification: 1: in process of working; 0:working stoped [one more definition in beijing: * working includes transformer identify] * [D2:D2] report events identification: 1: events reported by slave nodes; 0: no events reported * [D3:D3] upgrade identification: 1: in process of upgrading; 0: upgrade stopped * [D7:D4] error correction code */ buffer[0] = (td_u8)((evt->acd_flg << 2) | (cco->chl_status)); /* bit2: evt report flag */ if (mrs_cco_upg_is_idle() != TD_TRUE) { buffer[0] |= 0x08; } buffer[1] = (td_u8)(meter_num & 0xff); buffer[2] = (td_u8)((meter_num >> 8) & 0xff); /* meter number 2bytes, index 2: high 8 bits */ /* * working switch * [D0:D0] working status: 1:study; 0:read meter * [D1:D1] allowed register status: 1: allow; 0: not allow * [D7:D2] reserved */ buffer[7] = 0x2; /* index 7: working switch 0x2 */ buffer[13] = 0x08; /* index 13:working steps,equal to 08 */ buffer[14] = 0x08; /* index 14:working steps,equal to 08 */ buffer[15] = 0x08; /* index 15:working steps,equal to 08 */ return mrs_cco_1376_2_easy_encode(param, buffer, sizeof(buffer)); } td_void mrs_afn_10_f27_get_numbers(td_u16 *start_num, td_u8 *node_num) { td_u16 topo_total = uapi_get_topo_node_num(); td_u8 node_cnt = *node_num; if (node_cnt > MRS_AFN_QUERY_NODE_MAX_NUM) { node_cnt = MRS_AFN_QUERY_NODE_MAX_NUM; } if (*start_num == 0) { *start_num = 1; if (node_cnt > 0) { node_cnt--; } } if (topo_total < *start_num) { node_cnt = 0; } else { node_cnt = (td_u8)uapi_min(node_cnt, (topo_total - *start_num)); } *node_num = node_cnt; } td_u16 mrs_afn_10_f27_get_start_index(const ext_mdm_nm_topo_node_info *topo_info, td_u16 start_num) { td_u16 i = 0; td_u16 num = 0; for (; (i < EXT_MDM_NM_TOPO_NODE_NUM_MAX) && (num < start_num); i++) { if (topo_info[i].state != STATE_NOT_USED) { num++; } } return i; } td_void mrs_afn_10_f27_get_node_info(ext_mdm_nm_topo_node_info *topo_info, const td_u8 *phase_info, td_u16 i, mrs_afn_10_f27_node *node) { td_u16 proxy_tei; td_u8 *parent_mac = TD_NULL; /* Get mac */ (td_void) memcpy_s(node->node_addr, sizeof(node->node_addr), topo_info[i].mac, sizeof(topo_info[i].mac)); mrs_hex_invert(node->node_addr, sizeof(node->node_addr)); /* Get short address */ node->node_tei = i + 1; /* Get parent address */ proxy_tei = topo_info[i].proxy_tei; if (proxy_tei > 0) { proxy_tei--; } if (topo_info[proxy_tei].state != STATE_NOT_USED) { parent_mac = topo_info[proxy_tei].mac; } else { /* Use CCO address instead */ parent_mac = topo_info[0].mac; } if (memcpy_s(node->node_parent_addr, sizeof(node->node_parent_addr), parent_mac, MRS_METER_ADDR_LEN) != EOK) { return; } mrs_hex_invert(node->node_parent_addr, sizeof(node->node_parent_addr)); /* Get signal qulity */ node->signal = uapi_get_rcv_atten_by_tei(node->node_tei); /* Get network status */ node->stat_nw = 1; if (uapi_topo_get_state_by_tei(node->node_tei) != EXT_TP_IN_USE) { node->stat_nw = 0; } /* Get location */ node->longitude = 0xFFFFFFFF; node->latitude = 0xFFFFFFFF; /* Get pharse */ if (phase_info == TD_NULL) { node->phase = 0; } else if (((phase_info[node->node_tei] & 0xC) >> 2) == EXT_MAC_PHASE_IDENTIFY_STATE_OVER) { /* bit 2&3:0xC */ node->phase = phase_info[node->node_tei] & 0x3; } else { /* Skip the first invalid value in the phase results */ node->phase = 0; } } td_u32 mrs_1376_2_afn_10_f27(mrs_fn_param *param) { td_u32 ret = EXT_ERR_SUCCESS; ext_mdm_nm_topo_node_info *topo_info = TD_NULL; td_u8 *phase_info = uapi_get_phase_result_table(); td_pbyte payload = TD_NULL; td_u16 i, num, start_num, payload_len; mrs_afn_10_f27_node node = { 0 }; td_u8 node_num; if (param->frame->data_len != 3) { /* 3: start num 2B + node num 1B */ return EXT_ERR_BAD_DATA; } start_num = uapi_make_u16(param->frame->content[0], param->frame->content[1]); node_num = param->frame->content[2]; /* index 2: node number */ mrs_afn_10_f27_get_numbers(&start_num, &node_num); node_num = (node_num > MRS_AFN_QUERY_NODE_MAX_NUM) ? MRS_AFN_QUERY_NODE_MAX_NUM : node_num; do { td_u16 offset = 1; payload_len = 1 + node_num * (sizeof(mrs_afn_10_f27_node) - MRS_AFN_10_F27_NODE_PAD); payload = (td_u8 *)mrs_malloc(payload_len); if (payload == TD_NULL) { ret = EXT_ERR_FAILURE; break; } payload[0] = node_num; if (node_num == 0) { break; } uapi_get_topo_info(&topo_info); if (topo_info == TD_NULL) { ret = EXT_ERR_FAILURE; break; } /* Move to right start index in topo */ i = mrs_afn_10_f27_get_start_index(topo_info, start_num); for (num = 0; (i < EXT_MDM_NM_TOPO_NODE_NUM_MAX) && (num < node_num); i++) { if (topo_info[i].state != STATE_NOT_USED) { mrs_afn_10_f27_get_node_info(topo_info, phase_info, i, &node); memcpy_s(payload + offset, payload_len - offset, &node, (sizeof(node) - MRS_AFN_10_F27_NODE_PAD)); offset += (sizeof(node) - MRS_AFN_10_F27_NODE_PAD); num++; } } } while (0); if (ret != EXT_ERR_SUCCESS) { mrs_cco_1376_2_deny_frame(param, MRS_1376_2_DENY_METER_NOT_EXIST); } else { mrs_cco_1376_2_easy_encode(param, payload, payload_len); } mrs_free(payload); return EXT_ERR_SUCCESS; } td_u32 mrs_afn10_query_data_check(mrs_fn_param *afn_param, td_u8 *query_num, td_u16 *start_seq, td_bool is_create_deny) { td_u8 *content = afn_param->frame->content; td_u16 content_len = afn_param->frame->data_len; td_u32 ret = EXT_ERR_SUCCESS; mrs_proto_1376_2_deny_code deny_data = MRS_1376_2_DENY_INVALID_DATA; do { if (content_len != MRS_CCO_AFN10_DOWN_DATA_LEN) { deny_data = MRS_1376_2_DENY_LEN_ERR; ret = EXT_ERR_BAD_DATA; break; } if (memcpy_s(start_seq, sizeof(td_u16), content, sizeof(td_u16)) != EOK) { return EXT_ERR_MEMCPY_FAIL; } if (!(*start_seq)) { ret = EXT_ERR_INVALID_PARAMETER; break; } *query_num = *(content + MRS_CCO_AFN10_QUERY_NUM_OFFSET); if (*query_num > MRS_AFN_QUERY_TOPO_NODE_NUM_MAX) { *query_num = MRS_AFN_QUERY_TOPO_NODE_NUM_MAX; } } while (0); if (is_create_deny == TD_TRUE && (ret == EXT_ERR_BAD_DATA || ret == EXT_ERR_INVALID_PARAMETER)) { ret = mrs_cco_1376_2_deny_frame(afn_param, deny_data); if (ret == EXT_ERR_SUCCESS) { ret = EXT_ERR_SKIP; } } return ret; } td_u32 mrs_query_topo_down_check(td_bool *start_flag, mrs_fn_param *param, td_u16 *start_seq, td_u8 *query_num) { td_u32 ret; mrs_proto_1376_2_deny_code deny_data = MRS_1376_2_DENY_INVALID_DATA; do { ret = mrs_afn10_query_data_check(param, query_num, start_seq, TD_FALSE); if (ret != EXT_ERR_SUCCESS) { if (ret == EXT_ERR_BAD_DATA) { deny_data = MRS_1376_2_DENY_LEN_ERR; } break; } if (((*start_flag) == TD_FALSE) && (*start_seq != MRS_CCO_START_SEQ_ONE)) { ret = EXT_ERR_INVALID_PARAMETER; break; } if (*start_seq == MRS_CCO_START_SEQ_ONE) { (*start_flag) = TD_TRUE; } } while (0); if (ret == EXT_ERR_BAD_DATA || ret == EXT_ERR_INVALID_PARAMETER) { ret = mrs_cco_1376_2_deny_frame(param, deny_data); if (ret == EXT_ERR_SUCCESS) { ret = EXT_ERR_SKIP; } } return ret; } td_u32 mrs_afn_10_f230_fill_node_info(ext_mdm_nm_topo_node_info *topo_info, td_u8 *payload, td_u16 *data_offset, td_u16 my_tei) { td_u8 role; td_u16 my_proxy_tei; td_u8 meter_address[EXT_PLC_MAC_ADDR_LEN] = { 0 }; td_u16 current_offset = *data_offset; if (memcpy_s(meter_address, sizeof(meter_address), topo_info->mac, EXT_PLC_MAC_ADDR_LEN) != EOK) { return EXT_ERR_MEMCPY_FAIL; } mrs_hex_invert(meter_address, sizeof(meter_address)); if (meter_address[0] == 0xFE) { meter_address[0] = 0x00; } if (memcpy_s(payload + current_offset, EXT_PLC_MAC_ADDR_LEN, meter_address, sizeof(meter_address)) != EOK) { return EXT_ERR_MEMCPY_FAIL; } current_offset += EXT_PLC_MAC_ADDR_LEN; if (memcpy_s(payload + current_offset, sizeof(td_u16), &my_tei, sizeof(my_tei)) != EOK) { return EXT_ERR_MEMCPY_FAIL; } current_offset += (td_u16)sizeof(td_u16); my_proxy_tei = topo_info->proxy_tei; if (memcpy_s(payload + current_offset, sizeof(td_u16), &my_proxy_tei, sizeof(my_proxy_tei)) != EOK) { return EXT_ERR_MEMCPY_FAIL; } current_offset += (td_u16)sizeof(td_u16); role = topo_info->ability; *(payload + current_offset) = (td_u8)((role << MRS_CCO_TOPO_ROLE_OFFSET) + topo_info->level); current_offset += (td_u16)sizeof(td_u8); *data_offset = current_offset; return EXT_ERR_SUCCESS; } td_u32 mrs_afn_10_f230_fill_up_data(td_u8 *payload, td_u16 start_seq, td_u8 need_node_num, td_u8 *actual_report_num) { ext_mdm_nm_topo_node_info *topo_info = TD_NULL; td_u16 online_sta_num, find_index; td_u16 data_offset = 0; td_u8 report_num = 0; td_u16 max_tei = uapi_topo_get_max_tei(); uapi_get_topo_info(&topo_info); if (topo_info == TD_NULL) { return EXT_ERR_FAILURE; } online_sta_num = uapi_get_topo_node_num(); if (memcpy_s(payload, sizeof(td_u16), &online_sta_num, sizeof(online_sta_num)) != EOK) { return EXT_ERR_MEMCPY_FAIL; } data_offset += (td_u16)sizeof(td_u16); if (memcpy_s(payload + data_offset, sizeof(td_u16), &start_seq, sizeof(start_seq)) != EOK) { return EXT_ERR_MEMCPY_FAIL; } data_offset += (td_u16)sizeof(start_seq) + (td_u16)sizeof(report_num); for (find_index = start_seq; (online_sta_num != 0) && find_index < (need_node_num + start_seq); find_index++) { if (max_tei < find_index) { break; } if (topo_info[find_index - 1].state == STATE_NOT_USED) { continue; } if (mrs_afn_10_f230_fill_node_info(&topo_info[find_index - 1], payload, &data_offset, find_index) != EXT_ERR_SUCCESS) { return EXT_ERR_FAILURE; } report_num++; } *(payload + MRS_CCO_TOPO_REPORT_NUM_OFFSET) = report_num; *actual_report_num = report_num; return EXT_ERR_SUCCESS; } /* Querying Network Topology Information */ td_u32 mrs_1376_2_afn_10_f230(mrs_fn_param *param) { td_u32 ret; td_u16 start_seq = 0; td_u8 need_query_num = 0; td_u8 actual_report_num = 0; td_u16 payload_len; td_u8 *payload = TD_NULL; EXT_PRV td_bool mrs_afn_10_f230_state = TD_FALSE; do { ret = mrs_query_topo_down_check(&mrs_afn_10_f230_state, param, &start_seq, &need_query_num); if (ret == EXT_ERR_SKIP) { return EXT_ERR_SUCCESS; } else if (ret != EXT_ERR_SUCCESS) { return ret; } payload_len = MRS_AFN_10_F230_DATA_FIX_LEN + need_query_num * MRS_AFN_10_F230_TOPO_INFO_LEN; payload = (td_u8 *)mrs_malloc(payload_len); if (payload == TD_NULL) { return EXT_ERR_NOT_ENOUGH_MEMORY; } (td_void)memset_s(payload, payload_len, 0, payload_len); ret = mrs_afn_10_f230_fill_up_data(payload, start_seq, need_query_num, &actual_report_num); } while (0); if (ret == EXT_ERR_SUCCESS) { td_u16 reply_len = (td_u16)(MRS_AFN_10_F230_DATA_FIX_LEN + actual_report_num * MRS_AFN_10_F230_TOPO_INFO_LEN); mrs_cco_1376_2_easy_encode(param, payload, reply_len); } mrs_free(payload); return ret; } /* AFN=11H route settings */ td_u32 mrs_1376_2_afn_11_f1(mrs_fn_param *param) { td_u32 ret; td_u8 deny_code = MRS_1376_2_DENY_TIMEOUT; mrs_proto_1376_2_frame *frame = param->frame; td_u16 data_len = frame->data_len; td_u8 *content = frame->content; td_u8 add_meter_num = content[0]; do { if (data_len < MRS_1376_2_SEC_NODE_NUM_LEN_MIN) { deny_code = MRS_1376_2_DENY_LEN_ERR; ret = EXT_ERR_BAD_DATA; break; } if (data_len != (add_meter_num * MRS_1376_2_SEC_NODE_ITEM_SIZE + 1)) { deny_code = MRS_1376_2_DENY_LEN_ERR; ret = EXT_ERR_BAD_DATA; break; } if (add_meter_num == 0) { deny_code = MRS_1376_2_DENY_INVALID_DATA; ret = EXT_ERR_BAD_DATA; break; } content += 1; ret = mrs_archives_append(content, add_meter_num); if (ret != EXT_ERR_SUCCESS) { if (ret == EXT_ERR_FULL) { deny_code = MRS_1376_2_DENY_TIMEOUT; } else { deny_code = MRS_1376_2_DENY_CCO_BUSY; } } } while (0); if (ret != EXT_ERR_SUCCESS) { mrs_cco_1376_2_deny_frame(param, deny_code); } else { mrs_cco_1376_2_ack_frame(param, 0); } return EXT_ERR_SUCCESS; } td_u32 mrs_1376_2_afn_11_f2(mrs_fn_param *param) { td_u32 ret; td_u8 deny_code = MRS_1376_2_DENY_TIMEOUT; mrs_proto_1376_2_frame *frame = param->frame; td_u16 data_len = frame->data_len; td_u8 *content = frame->content; td_u8 del_meter_num = content[0]; td_pbyte del_meter_list = content + 1; do { if (data_len < MRS_1376_2_SEC_NODE_ITEM_SIZE) { deny_code = MRS_1376_2_DENY_LEN_ERR; ret = EXT_ERR_BAD_DATA; break; } if (del_meter_num == 0) { /* Delete nothing */ deny_code = MRS_1376_2_DENY_INVALID_DATA; ret = EXT_ERR_BAD_DATA; break; } if (data_len != (del_meter_num * ARCHIVES_METER_ADDR_SIZE + 1)) { deny_code = MRS_1376_2_DENY_LEN_ERR; ret = EXT_ERR_BAD_DATA; break; } ret = mrs_archives_delete(del_meter_list, del_meter_num); if (ret == EXT_ERR_NOT_FOUND) { deny_code = MRS_1376_2_DENY_METER_NOT_EXIST; break; } } while (0); if (ret != EXT_ERR_SUCCESS) { mrs_cco_1376_2_deny_frame(param, deny_code); } else { mrs_cco_1376_2_ack_frame(param, 0); } return EXT_ERR_SUCCESS; } td_u32 mrs_1376_2_afn_11_f5(mrs_fn_param *param) { mrs_proto_1376_2_frame *frame = param->frame; td_u32 ret; td_pbyte data = frame->content; td_u16 data_len = frame->data_len; td_u8 deny = MRS_1376_2_DENY_TIMEOUT; do { td_u32 duration; if (data_len != 10) { /* note:length (10B) = time (6B) + duration (4B) */ ret = EXT_ERR_BAD_DATA; deny = MRS_1376_2_DENY_LEN_ERR; break; } ret = mrs_1376_2_time_verify(data, 6); /* date time 6B */ if (ret != EXT_ERR_SUCCESS) { ret = EXT_ERR_BAD_DATA; deny = MRS_1376_2_DENY_FORMAT_ERR; break; } duration = ext_make_u32(uapi_make_u16(data[6], data[7]), /* 6&7:low 16b */ uapi_make_u16(data[8], data[9])); /* 8&9:high 16b */ ret = mrs_cco_start_tf_identify(duration); if (ret != EXT_ERR_SUCCESS) { deny = MRS_1376_2_DENY_TIMEOUT; break; } } while (0); if (ret == EXT_ERR_SUCCESS) { return mrs_cco_1376_2_ack_frame(param, 0); } else { return mrs_cco_1376_2_deny_frame(param, deny); } } td_u32 mrs_1376_2_afn_11_f6(mrs_fn_param *param) { mrs_cco_stop_tf_identify(); return mrs_cco_1376_2_ack_frame(param, 0); } /* AFN=12H route control */ td_u32 mrs_1376_2_afn_12_f1(mrs_fn_param *param) { return mrs_cco_1376_2_ack_frame(param, 0); } td_u32 mrs_1376_2_afn_12_f2(mrs_fn_param *param) { return mrs_cco_1376_2_ack_frame(param, 0); } td_u32 mrs_1376_2_afn_12_f3(mrs_fn_param *param) { return mrs_cco_1376_2_ack_frame(param, 0); } /* AFN=13H data transmit by route */ td_u32 mrs_1376_2_afn_13_f1(mrs_fn_param *param) { mrs_cco_upg_reset_file_rx_timeout(); /* Reset timeout calculator when CCO downloads file */ return mrs_1376_2_mr_handle(param, MRS_XR_13H_F1); } td_u32 mrs_1376_2_afn_13_f255(mrs_fn_param *param) { mrs_cco_upg_reset_file_rx_timeout(); /* Reset timeout calculator when CCO downloads file */ return mrs_1376_2_mr_handle(param, MRS_XR_13H_F255); } /* AFN=F1H parallel read meter */ td_u32 mrs_1376_2_afn_f1_f1(mrs_fn_param *param) { return mrs_1376_2_mr_handle(param, MRS_PR_F1H_F1); } td_u32 mrs_cco_get_mr_data_13_f1(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny) { td_u8 sub_node_num; td_u8 length; if (frame->data_len < 4) { /* length must more than 4B */ *deny = MRS_1376_2_DENY_LEN_ERR; return EXT_ERR_BAD_DATA; } *proto = frame->content[0]; sub_node_num = frame->content[2]; /* index 2: node number */ length = frame->content[3]; /* index 3: length */ if (sub_node_num != 0) { *deny = MRS_1376_2_DENY_FORMAT_ERR; return EXT_ERR_NOT_SUPPORT; } if ((frame->data_len != length + 4) || (length == 0)) { /* data length: 4B + data length */ *deny = MRS_1376_2_DENY_LEN_ERR; return EXT_ERR_BAD_DATA; } *data = frame->content + 4; /* data length: 4B + data length */ *data_len = length; return EXT_ERR_SUCCESS; } td_u32 mrs_cco_get_mr_data_13_f255(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny) { td_u8 sub_node_num; td_u16 length; if (frame->data_len < 5) { /* data length: 5B + data length */ *deny = MRS_1376_2_DENY_LEN_ERR; return EXT_ERR_BAD_DATA; } *proto = frame->content[0]; sub_node_num = frame->content[2]; /* index 2: node number */ length = uapi_make_u16(frame->content[3], frame->content[4]); /* index 3&4: length */ if (sub_node_num != 0) { *deny = MRS_1376_2_DENY_FORMAT_ERR; return EXT_ERR_NOT_SUPPORT; } if ((frame->data_len != length + 5) || (length == 0)) { /* data length: 5B + data length */ *deny = MRS_1376_2_DENY_LEN_ERR; return EXT_ERR_BAD_DATA; } *data = frame->content + 5; /* data length: 5B + data length */ *data_len = length; return EXT_ERR_SUCCESS; } td_u32 mrs_cco_get_mr_data_02_f1(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny) { td_u8 length = frame->content[1]; if ((frame->data_len != length + 2) || (length == 0)) { /* data length: 2B + data length */ *deny = MRS_1376_2_DENY_LEN_ERR; return EXT_ERR_BAD_DATA; } *proto = frame->content[0]; *data = frame->content + 2; /* data length: 2B + data length */ *data_len = length; return EXT_ERR_SUCCESS; } td_u32 mrs_cco_get_mr_data_02_f255(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny) { td_u16 length = uapi_make_u16(frame->content[1], frame->content[2]); /* index 1&2: length */ if ((frame->data_len != length + 3) || (length == 0)) { /* data length: 3B + data length */ *deny = MRS_1376_2_DENY_LEN_ERR; return EXT_ERR_BAD_DATA; } *proto = frame->content[0]; *data = frame->content + 3; /* data length: 3B + data length */ *data_len = length; return EXT_ERR_SUCCESS; } typedef struct { td_u8 protocol; td_u8 rsv; td_u16 length; td_u8 data[0]; } mrs_1376_2_pr_dn; td_u32 mrs_cco_get_mr_data_f1_f1(mrs_proto_1376_2_frame *frame, td_pbyte *data, td_u16 *data_len, td_u8 *proto, td_u8 *deny) { mrs_1376_2_pr_dn *head = (mrs_1376_2_pr_dn *)frame->content; if ((frame->data_len != sizeof(mrs_1376_2_pr_dn) + head->length) || (head->length == 0)) { *deny = MRS_1376_2_DENY_LEN_ERR; return EXT_ERR_BAD_DATA; } *data = head->data; *data_len = head->length; *proto = head->protocol; return EXT_ERR_SUCCESS; } mrs_create_plc_frame mrs_1376_2_mr_handle_get_node_info(const mrs_proto_1376_2_frame *frame, td_u8 option, mr_task_node *node) { mrs_create_plc_frame create_plc_frame = TD_NULL; mrs_cco_srv_ctx *cco = mrs_cco_get_srv_ctx(); (td_void) memset_s(node, sizeof(mr_task_node), 0, sizeof(mr_task_node)); (td_void) memcpy_s(node->src_addr, sizeof(node->src_addr), frame->src_addr, sizeof(frame->src_addr)); (td_void) memcpy_s(node->dst_addr, sizeof(node->dst_addr), frame->dst_addr, sizeof(frame->dst_addr)); node->seq = frame->seq; node->plc_seq = ++cco->plc_seq; node->rx_time = uapi_get_seconds(); node->send_uart_frame = mrs_uart_tx; node->option = option; if (option == MRS_PR_F1H_F1) { node->priority = MRS_MR_TASK_PRI_LO; node->type = MRS_CCO_MR_TYPE_PR; node->tx_max = MRS_CFG_PR_PLC_TRY_MAX; node->timeout = MRS_CFG_PR_PLC_TIMEOUT; node->create_uart_frame = mrs_cco_create_pr_1376_2_frame; create_plc_frame = mrs_cco_create_pr_plc_frame; } else { node->priority = MRS_MR_TASK_PRI_HI; node->type = MRS_CCO_MR_TYPE_XR; node->tx_max = MRS_CFG_XR_PLC_TRY_MAX; node->timeout = MRS_CFG_XR_PLC_TIMEOUT; node->create_uart_frame = mrs_cco_create_xr_1376_2_frame; create_plc_frame = mrs_cco_create_xr_plc_frame; } return create_plc_frame; } td_u32 mrs_1376_2_mr_handle(mrs_fn_param *param, td_u8 option) { td_u32 ret; mrs_proto_1376_2_frame *frame = param->frame; mr_task_node *node = TD_NULL; mrs_create_plc_frame create_plc_frame; mrs_get_mr_data get_mr_data[] = { mrs_cco_get_mr_data_13_f1, mrs_cco_get_mr_data_13_f255, mrs_cco_get_mr_data_02_f1, mrs_cco_get_mr_data_02_f255, mrs_cco_get_mr_data_f1_f1, }; td_u8 deny = MRS_1376_2_DENY_CCO_BUSY; if (option > MRS_PR_F1H_F1) { return EXT_ERR_INVALID_PARAMETER; } node = (mr_task_node *)mrs_malloc(sizeof(mr_task_node)); if (node == TD_NULL) { return EXT_ERR_MALLOC_FAILUE; } create_plc_frame = mrs_1376_2_mr_handle_get_node_info(frame, option, node); do { ext_mdm_nm_topo_node_info entry; td_pbyte data = TD_NULL; td_u16 data_len = 0; ret = get_mr_data[option](frame, &data, &data_len, &node->protocol, &deny); if (ret != EXT_ERR_SUCCESS) { break; } ret = create_plc_frame(node, data, data_len); if (ret != EXT_ERR_SUCCESS) { break; } ret = uapi_query_mac_attr(node->plc_frame->addr, &entry); if (ret != EXT_ERR_SUCCESS) { deny = MRS_1376_2_DENY_STA_NOT_IN_TOPO; break; } ret = mrs_cco_mr_list_insert(node); if (ret != EXT_ERR_SUCCESS) { deny = MRS_1376_2_DENY_RM_POOL_FULL; break; } } while (0); if (ret != EXT_ERR_SUCCESS) { ret = mrs_cco_1376_2_deny_frame(param, deny); mrs_free(node->plc_frame); mrs_free(node); } return ret; } td_u32 mrs_1376_2_afn_15_f1(mrs_fn_param *param) { /* Every frame size (contains segment size) must be less than MRS_DATA_BUFFER_SIZE */ td_u32 ret = EXT_ERR_BAD_DATA; mrs_upg_param upg_param; td_u32 segment = 0; td_u16 data_len = param->frame->data_len; td_u8 *content = param->frame->content; do { /* Length check */ if (data_len < MRS_CCO_UPG_FRAME_DATA_SIZE_MIN) { break; } upg_param.file_flag = content[MRS_CCO_UPG_FILE_FLAG_OFFSET]; upg_param.file_property = content[MRS_CCO_UPG_FILE_PROPERTY_OFFSET]; upg_param.file_ins = content[MRS_CCO_UPG_FILE_INS_OFFSET]; upg_param.seg_totoal = uapi_make_u16(content[MRS_CCO_UPG_SEG_TOTOAL_OFFSET], content[MRS_CCO_UPG_SEG_TOTOAL_OFFSET + 1]); upg_param.seg_curr = uapi_make_identifier(content[MRS_CCO_UPG_SEG_CURRENT_OFFSET], content[MRS_CCO_UPG_SEG_CURRENT_OFFSET + 1], content[MRS_CCO_UPG_SEG_CURRENT_OFFSET + 2], /* index 7:5+2 */ content[MRS_CCO_UPG_SEG_CURRENT_OFFSET + 3]); /* index 8:5+3 */ upg_param.data_len = uapi_make_u16(content[MRS_CCO_UPG_SEG_DATA_LEN_OFFSET], content[MRS_CCO_UPG_SEG_DATA_LEN_OFFSET + 1]); if (data_len != upg_param.data_len + MRS_CCO_UPG_FRAME_DATA_SIZE_MIN) { break; } upg_param.data = (upg_param.data_len > 0) ? (content + MRS_CCO_UPG_SEG_DATA_OFFSET) : TD_NULL; /* Analyse content */ switch (upg_param.file_flag) { case MRS_CCO_UPG_FILE_FLAG_CLR: mrs_cco_upg_set_frame(param->frame); ret = mrs_upg_clr(); break; case MRS_CCO_UPG_FILE_FLAG_CCO: case MRS_CCO_UPG_FILE_FLAG_STA: ret = mrs_upg_file_rx(&upg_param, &segment); break; default: break; } } while (0); if (ret != EXT_ERR_CONTINUE) { if (ret != EXT_ERR_SUCCESS) { segment = MRS_CCO_UPG_ERROR_SEG; } mrs_cco_1376_2_easy_encode(param, (td_u8 *)&segment, (td_u16)sizeof(td_u32)); } return EXT_ERR_SUCCESS; } #endif /* defined(PRODUCT_CFG_PRODUCT_TYPE_CCO) */