inwudriver-weibo/app/mrs/sta/mrs_sta_evt.c

410 lines
12 KiB
C
Raw Normal View History

/*
* 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: CCOack,,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) */