410 lines
12 KiB
C
410 lines
12 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved.
|
||
|
|
* Description: MRS STA EVENT report.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "mrs_sta_evt.h"
|
||
|
|
#include "mrs_sta_io.h"
|
||
|
|
#include "mrs_sta_srv.h"
|
||
|
|
#include "mrs_sta_plc.h"
|
||
|
|
#include "mrs_common_tools.h"
|
||
|
|
#include "mrs_common_power_failure.h"
|
||
|
|
#include "mrs_sta_power_failure.h"
|
||
|
|
|
||
|
|
#if defined(PRODUCT_CFG_PRODUCT_TYPE_STA)
|
||
|
|
|
||
|
|
#define MRS_STA_EVT_FROM_SIMU 1
|
||
|
|
#define MRS_STA_EVT_FROM_METER 2
|
||
|
|
#define MRS_STA_DETECT_POWER_FAILURE_ENABLE 1 /* enable for STA power down detection */
|
||
|
|
|
||
|
|
#define MRS_STA_EVT_STATUS_IDLE 0
|
||
|
|
#define MRS_STA_EVT_STATUS_QUERY 1
|
||
|
|
#define MRS_STA_EVT_STATUS_REPORT 2
|
||
|
|
|
||
|
|
#define MRS_STA_645_EVT_DI 0x04001501
|
||
|
|
|
||
|
|
mrs_sta_evt_ctx g_sta_evt_ctx;
|
||
|
|
|
||
|
|
mrs_sta_evt_ctx *mrs_sta_get_evt_ctx(td_void)
|
||
|
|
{
|
||
|
|
return &g_sta_evt_ctx;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Event control context reset */
|
||
|
|
td_void mrs_sta_event_ctx_reset(td_void);
|
||
|
|
|
||
|
|
/* Meter event detected */
|
||
|
|
td_u32 mrs_sta_event_io_callback(td_u8 praram, td_bool value);
|
||
|
|
|
||
|
|
/* Event option selector */
|
||
|
|
td_u32 mrs_sta_event_chl_notify(td_bool chl_status, uintptr_t option, td_bool *one_shot);
|
||
|
|
|
||
|
|
/* Query meter events */
|
||
|
|
td_void mrs_sta_event_query_meter_event(td_void);
|
||
|
|
|
||
|
|
/* Recevie handler */
|
||
|
|
td_void mrs_sta_event_uart_rx(EXT_CONST mrs_mr_queue_item *item, td_pbyte data, td_u16 data_len);
|
||
|
|
|
||
|
|
td_void mrs_sta_event_uart_timeout(td_void);
|
||
|
|
|
||
|
|
/* Create event report on PLC */
|
||
|
|
td_u32 mrs_sta_create_event_report_plc(const td_pbyte buffer, td_u16 length);
|
||
|
|
|
||
|
|
/* Send event report on PLC */
|
||
|
|
td_u32 mrs_sta_send_event_report_plc(td_void);
|
||
|
|
|
||
|
|
/* Query EVENT notify */
|
||
|
|
td_void mrs_sta_event_query_notify(td_void);
|
||
|
|
|
||
|
|
/* PLC ACK notify */
|
||
|
|
td_void mrs_sta_event_plc_ack_notify(td_void);
|
||
|
|
|
||
|
|
/* EVENT trigger notify */
|
||
|
|
td_void mrs_sta_event_trigger_notify(td_void);
|
||
|
|
|
||
|
|
td_u32 mrs_sta_event_init(td_void)
|
||
|
|
{
|
||
|
|
(td_void) memset_s(&g_sta_evt_ctx, sizeof(g_sta_evt_ctx), 0, sizeof(g_sta_evt_ctx));
|
||
|
|
g_sta_evt_ctx.max_retry = MRS_STA_EVT_PLC_TIMES_MAX;
|
||
|
|
g_sta_evt_ctx.seq = (td_u16)uapi_get_random_num32(1, EXT_U16_MAX);
|
||
|
|
|
||
|
|
mrs_sta_io_register_evtout_callback(mrs_sta_event_io_callback, MRS_STA_EVT_FROM_METER);
|
||
|
|
|
||
|
|
mrs_sta_event_register_query_notify(mrs_sta_event_query_meter_event);
|
||
|
|
mrs_sta_event_register_plc_ack_notify(TD_NULL);
|
||
|
|
mrs_sta_event_register_trigger_notify(TD_NULL);
|
||
|
|
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
td_void mrs_sta_event_ctx_reset(td_void)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
|
||
|
|
mrs_timer_stop(MRS_TIMER_ID_STA_EVT_REPORT);
|
||
|
|
|
||
|
|
mrs_free(evt->report_frame);
|
||
|
|
evt->retry = 0;
|
||
|
|
|
||
|
|
mrs_sta_clear_chl_notify(mrs_sta_event_chl_notify);
|
||
|
|
}
|
||
|
|
|
||
|
|
td_u32 mrs_sta_event_io_callback(td_u8 param, td_bool value)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
|
||
|
|
ext_unref_param(param);
|
||
|
|
|
||
|
|
evt->hard_evt_out = value;
|
||
|
|
evt->evt_out = value;
|
||
|
|
|
||
|
|
if (evt->evt_out == TD_TRUE) {
|
||
|
|
mrs_sta_event_ctx_reset();
|
||
|
|
mrs_sta_event_trigger_notify();
|
||
|
|
|
||
|
|
/* channel available */
|
||
|
|
if (mrs_sta_plc_chl_status() == TD_TRUE) {
|
||
|
|
mrs_sta_event_query_notify();
|
||
|
|
} else {
|
||
|
|
mrs_sta_register_chl_notify(mrs_sta_event_chl_notify, MRS_STA_EVT_STATUS_QUERY);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
td_void mrs_sta_event_query_meter_event(td_void)
|
||
|
|
{
|
||
|
|
td_u8 query_frame[] = {
|
||
|
|
0x68, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x68, 0x11, 0x04, 0x34, 0x48, 0x33, 0x37, 0xC7, 0x16
|
||
|
|
};
|
||
|
|
mrs_sta_srv_ctx *sta = mrs_sta_get_srv_ctx();
|
||
|
|
td_u16 payload_len = sizeof(mrs_mr_queue_item) + sizeof(query_frame);
|
||
|
|
td_pbyte payload;
|
||
|
|
mrs_mr_queue_item *item = TD_NULL;
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
|
||
|
|
if (!mrs_invalid_meter(sta->meter)) {
|
||
|
|
if (memcpy_s(query_frame + 1, MRS_METER_ADDR_LEN, sta->meter, MRS_METER_ADDR_LEN) != EOK) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
query_frame[sizeof(query_frame) - 2] = mrs_checksum8(query_frame, sizeof(query_frame) - 2); /* 2: check sum */
|
||
|
|
}
|
||
|
|
|
||
|
|
payload = (td_pbyte)mrs_malloc(payload_len);
|
||
|
|
if (payload == TD_NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
(td_void) memset_s(payload, payload_len, 0, payload_len);
|
||
|
|
item = (mrs_mr_queue_item *)payload;
|
||
|
|
item->id = MRS_STA_ITME_ID_EVENT_QRY;
|
||
|
|
item->seq = ++evt->sta_queue_seq;
|
||
|
|
item->timeout = MRS_CFG_METER_TIMEOUT;
|
||
|
|
item->protocol = METER_PROTO_645_2007;
|
||
|
|
item->data_len = sizeof(query_frame);
|
||
|
|
item->rx_handle = mrs_sta_event_uart_rx;
|
||
|
|
if (memcpy_s(item->data, item->data_len, query_frame, item->data_len) != EOK) {
|
||
|
|
mrs_free(payload);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mrs_sta_try_enqueue(&sta->mr_queue, item) != TD_TRUE) {
|
||
|
|
mrs_free(payload);
|
||
|
|
}
|
||
|
|
|
||
|
|
mrs_sta_queue_notify();
|
||
|
|
}
|
||
|
|
|
||
|
|
td_void mrs_sta_event_uart_rx(EXT_CONST mrs_mr_queue_item *item, td_pbyte data, td_u16 data_len)
|
||
|
|
{
|
||
|
|
mrs_proto_645_frame_inf frame;
|
||
|
|
td_u32 ret;
|
||
|
|
td_u32 di;
|
||
|
|
|
||
|
|
ext_unref_param(item);
|
||
|
|
|
||
|
|
if (memset_s(&frame, sizeof(frame), 0, sizeof(frame)) != EOK) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mrs_proto_645_decode_frame(data, data_len, &frame) != EXT_ERR_SUCCESS) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (frame.data_len <= MRS_645_DATA_DI_SIZE) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (memcpy_s(&di, sizeof(di), frame.data, MRS_645_DATA_DI_SIZE) != EOK) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
mrs_proto_645_data_decode((td_u8 *)&di, sizeof(di));
|
||
|
|
if (di != MRS_STA_645_EVT_DI) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = mrs_sta_create_event_report_plc(data, data_len);
|
||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = mrs_sta_send_event_report_plc();
|
||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
td_u32 mrs_sta_create_event_report_plc(const td_pbyte buffer, td_u16 length)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
mrs_sta_srv_ctx *sta = mrs_sta_get_srv_ctx();
|
||
|
|
mrs_plc_frame_data *plc = TD_NULL;
|
||
|
|
mrs_meter_event_info *inf = TD_NULL;
|
||
|
|
td_u16 payload_len = sizeof(mrs_plc_frame_data) + sizeof(mrs_meter_event_info) + length;
|
||
|
|
td_pbyte payload;
|
||
|
|
|
||
|
|
payload = mrs_malloc(payload_len);
|
||
|
|
if (payload == TD_NULL) {
|
||
|
|
return EXT_ERR_MALLOC_FAILUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
(td_void) memset_s(payload, payload_len, 0, payload_len);
|
||
|
|
|
||
|
|
plc = (mrs_plc_frame_data *)payload;
|
||
|
|
plc->id = PLC_CMD_ID_EVT;
|
||
|
|
plc->payload_len = sizeof(mrs_meter_event_info) + length;
|
||
|
|
plc->payload = payload + sizeof(mrs_plc_frame_data);
|
||
|
|
|
||
|
|
inf = (mrs_meter_event_info *)plc->payload;
|
||
|
|
inf->stru_ver = MRS_PLC_PROTO_VERSION;
|
||
|
|
inf->stru_size = sizeof(mrs_meter_event_info);
|
||
|
|
inf->dir = MRS_PLC_UP_FLG;
|
||
|
|
inf->prm = MRS_EVENT_PRM_HOST;
|
||
|
|
inf->func_code = MRS_EVENT_FUNC_METER_REPORT;
|
||
|
|
inf->data_len = length;
|
||
|
|
inf->seq = ++evt->seq;
|
||
|
|
if (memcpy_s(inf->meter, sizeof(inf->meter), sta->meter, sizeof(sta->meter)) != EOK) {
|
||
|
|
mrs_free(payload);
|
||
|
|
return EXT_ERR_FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (length > 0 && memcpy_s(inf->data, length, buffer, length) != EOK) {
|
||
|
|
mrs_free(payload);
|
||
|
|
return EXT_ERR_FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
evt->report_frame = plc;
|
||
|
|
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
td_u32 mrs_sta_send_event_report_plc(td_void)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
td_u32 ret;
|
||
|
|
|
||
|
|
if (evt->report_frame == TD_NULL) {
|
||
|
|
return EXT_ERR_BAD_DATA;
|
||
|
|
}
|
||
|
|
|
||
|
|
do {
|
||
|
|
if (mrs_sta_plc_chl_status() != TD_TRUE) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (evt->retry >= evt->max_retry) {
|
||
|
|
evt->retry = 0;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = mrs_plc_frame_send(evt->report_frame);
|
||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
evt->retry++;
|
||
|
|
mrs_timer_start(MRS_TIMER_ID_STA_EVT_REPORT,
|
||
|
|
uapi_min(MRS_STA_EVT_PLC_TIMEOUT * evt->retry, MRS_STA_EVT_PLC_TIMEOUT_MAX),
|
||
|
|
EXT_TIMER_TYPE_ONCE);
|
||
|
|
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
} while (0);
|
||
|
|
|
||
|
|
mrs_sta_register_chl_notify(mrs_sta_event_chl_notify, MRS_STA_EVT_STATUS_REPORT);
|
||
|
|
return EXT_ERR_NOT_CONNECT;
|
||
|
|
}
|
||
|
|
|
||
|
|
td_u32 mrs_sta_event_chl_notify(td_bool chl_status, uintptr_t option, td_bool *one_shot)
|
||
|
|
{
|
||
|
|
*one_shot = chl_status;
|
||
|
|
if (chl_status == TD_FALSE) {
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (option == MRS_STA_EVT_STATUS_QUERY) {
|
||
|
|
mrs_sta_event_query_meter_event();
|
||
|
|
} else {
|
||
|
|
mrs_sta_send_event_report_plc();
|
||
|
|
}
|
||
|
|
|
||
|
|
return EXT_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
td_void mrs_sta_event_report_plc_timeout_handle(td_void)
|
||
|
|
{
|
||
|
|
td_u32 ret;
|
||
|
|
ret = mrs_sta_send_event_report_plc();
|
||
|
|
if (ret != EXT_ERR_SUCCESS) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
td_void mrs_sta_evt_plc_frame_rx(const mrs_plc_frame_data *plc)
|
||
|
|
{
|
||
|
|
mrs_meter_event_info *evt_frm = (mrs_meter_event_info *)plc->payload;
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
mrs_power_failure_ctrl_st *power_failure_info = mrs_get_power_failure_ctrl();
|
||
|
|
mrs_power_failure_rcv_report *power_failure_rcv_info = mrs_get_power_failure_report_info();
|
||
|
|
|
||
|
|
/* check frame */
|
||
|
|
if ((evt_frm->stru_size < sizeof(mrs_meter_event_info)) ||
|
||
|
|
(plc->payload_len != evt_frm->stru_size + evt_frm->data_len)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* processing for power down event */
|
||
|
|
if (evt_frm->func_code == MRS_EVENT_FUNC_MODUL_REPORT && evt_frm->dir == MRS_PLC_UP_FLG &&
|
||
|
|
power_failure_info->power_failure_report_enable == MRS_STA_DETECT_POWER_FAILURE_ENABLE) {
|
||
|
|
if (evt_frm->data_len < DATA_FIX_SIZE) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (plc->form_serial_number != uapi_mdm_get_form_serial_num() ||
|
||
|
|
power_failure_info->start_send_time >= power_failure_info->send_times ||
|
||
|
|
uapi_get_join_net_state() == TD_FALSE) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
mrs_power_failure_get_others_frame_data(evt_frm);
|
||
|
|
|
||
|
|
if (power_failure_rcv_info->device_power_failure == TD_FALSE &&
|
||
|
|
power_failure_info->is_ready_to_send_power_failure == TD_FALSE) {
|
||
|
|
mrs_handle_others_power_failure_frame();
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* download frame after cco reply ack: station processes recieved ack
|
||
|
|
* CNComments: CCO回复ack确认后,下行,站点处理接收到的ack */
|
||
|
|
if (evt_frm->func_code == MRS_EVNET_FUNC_ACK && evt_frm->dir == MRS_PLC_DN_FLG &&
|
||
|
|
power_failure_info->power_failure_report_enable == MRS_STA_DETECT_POWER_FAILURE_ENABLE) {
|
||
|
|
if (mrs_sta_handle_power_failue_ack(evt_frm->seq) == EXT_ERR_SUCCESS) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (evt_frm->seq != evt->seq || evt_frm->dir != MRS_PLC_DN_FLG) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (evt_frm->func_code == MRS_EVNET_FUNC_ACK) {
|
||
|
|
mrs_sta_event_ctx_reset();
|
||
|
|
mrs_sta_event_plc_ack_notify();
|
||
|
|
} else if (evt_frm->func_code == MRS_EVENT_FUNC_CCO_BUF_FULL) {
|
||
|
|
mrs_timer_start(MRS_TIMER_ID_STA_EVT_REPORT, MRS_STA_EVT_PLC_TIMEOUT_MAX, EXT_TIMER_TYPE_ONCE);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Register query EVENT_OUT notify */
|
||
|
|
td_void mrs_sta_event_register_query_notify(mrs_sta_evt_callback notify)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
evt->query_notify = notify;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Register PLC ACK notify */
|
||
|
|
td_void mrs_sta_event_register_plc_ack_notify(mrs_sta_evt_callback notify)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
evt->plc_ack_notify = notify;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Register EVENT_OUT trigger notify */
|
||
|
|
td_void mrs_sta_event_register_trigger_notify(mrs_sta_evt_callback notify)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
evt->trigger_notify = notify;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Query EVENT notify */
|
||
|
|
td_void mrs_sta_event_query_notify(td_void)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
if (evt->query_notify) {
|
||
|
|
evt->query_notify();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* PLC ACK notify */
|
||
|
|
td_void mrs_sta_event_plc_ack_notify(td_void)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
if (evt->plc_ack_notify) {
|
||
|
|
evt->plc_ack_notify();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* EVENT trigger notify */
|
||
|
|
td_void mrs_sta_event_trigger_notify(td_void)
|
||
|
|
{
|
||
|
|
mrs_sta_evt_ctx *evt = mrs_sta_get_evt_ctx();
|
||
|
|
if (evt->trigger_notify) {
|
||
|
|
evt->trigger_notify();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif /* defined(PRODUCT_CFG_PRODUCT_TYPE_STA) */
|
||
|
|
|