1814 lines
59 KiB
C
1814 lines
59 KiB
C
/*
|
|
* 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) */
|
|
|