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

441 lines
15 KiB
C
Raw Permalink Normal View History

/*
* Copyright (c) CompanyNameMagicTag 2019-2020. All rights reserved.
* Description: MRS STA POWER FAILURE report.
*/
#include "mrs_common_power_failure.h"
#include "mrs_common_tools.h"
#include "mrs_sta_io.h"
#include "mrs_sta_power_failure.h"
#if defined(PRODUCT_CFG_PRODUCT_TYPE_STA)
/************************************************************
global variables
************************************************************/
mrs_power_failure_rcv_report g_rcv_report_info = { 0 };
mrs_power_failure_rcv_report *mrs_get_power_failure_report_info(td_void)
{
return &g_rcv_report_info;
}
/* Handling Local Power Outage Events */
td_u32 mrs_sta_handle_local_power_failure(td_void)
{
td_u32 ret;
td_u32 random_wait_send_time;
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();
power_failure_rcv_info->my_tei = uapi_get_my_tei();
power_failure_rcv_info->device_power_failure = TD_TRUE;
power_failure_rcv_info->device_pull_reset = TD_TRUE;
if (power_failure_info->power_failure_bitmap == TD_NULL) {
return EXT_ERR_FAILURE;
}
/* The power failure tei information is updated to the global bitmap. */
power_failure_info->power_failure_bitmap[power_failure_rcv_info->my_tei / BIT_SIZE] |= 1 <<
(power_failure_rcv_info->my_tei % BIT_SIZE);
random_wait_send_time = uapi_get_random_num32(power_failure_info->random_min_value,
power_failure_info->random_max_value);
ret = mrs_timer_start(MRS_TIMER_ID_STA_POWER_FAILURE, random_wait_send_time, EXT_TIMER_TYPE_ONCE);
return ret;
}
td_void mrs_sta_create_power_failure_frame_proc(td_void)
{
mrs_power_failure_ctrl_st *power_failure_info = mrs_get_power_failure_ctrl();
if (power_failure_info->power_failure_bitmap == TD_NULL) {
return;
}
if (mrs_data_is_all_zero(power_failure_info->power_failure_bitmap, POWER_FAILURE_BITMAP_LEN, 0) == TD_FALSE) {
mrs_sta_create_power_failure_frame(POWER_FAILURE);
}
}
td_u32 mrs_sta_set_power_failure_info(td_pbyte payload, td_u16 bitmap_len, EXT_CONST td_u8 *tei_point, td_u8 event_type)
{
mrs_meter_event_info *event_info = TD_NULL;
mrs_sta_evt_ctx *evt_ctx = mrs_sta_get_evt_ctx();
mrs_sta_srv_ctx *sta_srv_ctx = mrs_sta_get_srv_ctx();
mrs_power_failure_ctrl_st *power_failure_info = mrs_get_power_failure_ctrl();
if (evt_ctx == TD_NULL) {
return EXT_ERR_NO_INITILIZATION;
}
event_info = (mrs_meter_event_info *)payload;
event_info->stru_ver = MRS_PLC_PROTO_VERSION;
event_info->stru_size = sizeof(mrs_meter_event_info);
event_info->dir = MRS_PLC_UP_FLG;
event_info->prm = MRS_EVENT_PRM_HOST;
event_info->func_code = MRS_EVENT_FUNC_MODUL_REPORT;
event_info->data_len = DATA_FIX_SIZE + bitmap_len;
event_info->seq = ++evt_ctx->seq;
if (memcpy_s(event_info->meter, sizeof(event_info->meter), sta_srv_ctx->meter,
sizeof(sta_srv_ctx->meter)) != EXT_ERR_SUCCESS) {
return EXT_ERR_FAILURE;
}
power_failure_info->ack_seq = event_info->seq;
/* The STA proactively reports events (triggered by modules) and data is expanded. */
event_info->data[0] = event_type;
if (memcpy_s(&event_info->data[DATA_START_TEI_POSITION], sizeof(td_u8), tei_point,
sizeof(td_u8)) != EXT_ERR_SUCCESS) {
return EXT_ERR_FAILURE;
}
if (memcpy_s(&event_info->data[DATA_END_TEI_POSITION], sizeof(td_u8), tei_point + 1,
sizeof(td_u8)) != EXT_ERR_SUCCESS) {
return EXT_ERR_FAILURE;
}
mrs_sta_update_normal_bitmap(power_failure_info->power_failure_bitmap, &event_info->data[DATA_FIX_SIZE],
bitmap_len);
mrs_printf("[CREATE_PF_FRAME]: data_len= %d\n", event_info->data_len);
mrs_logbuf("[CREATE_PF_FRAME]: ", event_info->data, event_info->data_len);
return EXT_ERR_SUCCESS;
}
td_u32 mrs_sta_create_power_failure_frame(td_u8 event_type)
{
mrs_plc_frame_data power_frame = { 0 };
td_u16 payload_len;
td_pbyte payload;
td_u16 bitmap_len;
td_u16 bitmap_max_tei;
td_u16 bitmap_min_tei;
td_u8 *tei_point = TD_NULL;
mrs_power_failure_ctrl_st *power_failure_info = mrs_get_power_failure_ctrl();
mrs_printf("ENTER mrs_sta_create_power_failure_frame().\n");
if (power_failure_info->power_failure_bitmap == TD_NULL) {
return EXT_ERR_FAILURE;
}
bitmap_min_tei = mrs_calc_min_tei(power_failure_info->power_failure_bitmap);
bitmap_max_tei = mrs_calc_max_tei(power_failure_info->power_failure_bitmap);
bitmap_len = (bitmap_max_tei - bitmap_min_tei + BIT_SIZE) / BIT_SIZE;
tei_point = (td_u8 *)(&bitmap_min_tei);
payload_len = sizeof(mrs_meter_event_info) + DATA_FIX_SIZE + bitmap_len;
payload = mrs_malloc(payload_len);
if (payload == TD_NULL) {
return EXT_ERR_MALLOC_FAILUE;
}
if (memset_s(payload, payload_len, 0, payload_len) != EXT_ERR_SUCCESS) {
mrs_free(payload);
return EXT_ERR_FAILURE;
}
if (mrs_sta_set_power_failure_info(payload, bitmap_len, tei_point, event_type) != EXT_ERR_SUCCESS) {
mrs_free(payload);
return EXT_ERR_FAILURE;
}
power_frame.id = PLC_CMD_ID_EVT;
power_frame.payload_len = payload_len;
power_frame.payload = payload;
mrs_sta_power_failure_set_send_info(event_type, &power_frame);
mrs_free(payload);
return EXT_ERR_SUCCESS;
}
td_void mrs_sta_power_failure_set_send_info(td_u8 event_type, mrs_plc_frame_data *power_frame)
{
td_u32 index = 0;
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();
/* The module is not powered off and is transmitted in unicast mode. */
if (power_failure_rcv_info->device_power_failure == TD_FALSE) {
mrs_plc_frame_send(power_frame);
mrs_timer_start(MRS_TIMER_ID_STA_POWER_FAILURE_ACK, power_failure_info->send_interval, EXT_TIMER_TYPE_ONCE);
power_failure_info->wait_ack_flag = TD_TRUE;
power_failure_info->wait_ack_type = event_type;
return;
}
/* The module is powered off and broadcast (local broadcast or network-wide broadcast). */
power_frame->addr[index] = 0;
if (memset_s(power_frame->addr + 1, EXT_PLC_MAC_ADDR_LEN - 1, 0xFF, EXT_PLC_MAC_ADDR_LEN - 1) != EXT_ERR_SUCCESS) {
return;
}
if (mrs_sta_send_power_failure_frame(power_frame) != EXT_ERR_SUCCESS) {
return;
}
}
/* The timer for waiting for the ACK message expires. */
td_void mrs_sta_handle_wait_power_failure_ack(td_void)
{
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();
power_failure_info->send_report_times++;
/* The module is powered off. The ack is not processed. */
if (power_failure_rcv_info->device_power_failure == TD_TRUE) {
power_failure_info->wait_ack_flag = TD_FALSE;
return;
}
if (power_failure_info->wait_ack_flag == TD_FALSE
|| power_failure_info->send_report_times == (power_failure_info->send_times + STA_DEFAULT_SEND_CNT)) {
/* Clear some power outage information. */
mrs_sta_power_failure_info_erase(power_failure_info);
return;
}
/* Failed to wait for the ACK response and resend the message. */
if (mrs_sta_create_power_failure_frame(power_failure_info->wait_ack_type) != EXT_ERR_SUCCESS) {
return;
}
}
/* A power outage site sends a power outage report packet. */
td_u32 mrs_sta_send_power_failure_frame(EXT_CONST mrs_plc_frame_data *power_frame)
{
td_u32 ret;
mrs_power_failure_ctrl_st *power_failure_info = mrs_get_power_failure_ctrl();
if (power_frame == TD_NULL) {
return EXT_ERR_BAD_DATA;
}
ret = mrs_plc_frame_send(power_frame);
/* Wait interval after sending success (starting from 1) */
power_failure_info->start_send_time++;
if (power_failure_info->start_send_time <= power_failure_info->send_times) {
mrs_timer_start(MRS_TIMER_ID_STA_POWER_FAILURE, power_failure_info->send_interval, EXT_TIMER_TYPE_ONCE);
} else {
/* Clear some power outage information. */
mrs_sta_power_failure_info_erase(power_failure_info);
}
return ret;
}
td_void mrs_sta_power_failure_info_erase(mrs_power_failure_ctrl_st *power_failure_info)
{
mrs_power_failure_ctrl_st *power_failure_ctrl = power_failure_info;
power_failure_ctrl->ack_seq = 0;
power_failure_ctrl->wait_ack_flag = TD_FALSE;
power_failure_ctrl->ack_seq = 0;
power_failure_ctrl->is_ready_to_send_power_failure = TD_FALSE;
power_failure_ctrl->send_report_times = 0;
if (memset_s(power_failure_ctrl->power_failure_bitmap, POWER_FAILURE_BITMAP_LEN, 0,
POWER_FAILURE_BITMAP_LEN) != EXT_ERR_SUCCESS) {
return;
}
}
/* Processes power outage reporting frames of other modules. */
td_u32 mrs_handle_others_power_failure_frame(td_void)
{
td_u32 ret;
mrs_power_failure_ctrl_st *power_failure_info = mrs_get_power_failure_ctrl();
power_failure_info->is_ready_to_send_power_failure = TD_TRUE;
power_failure_info->start_send_time = 1;
/* Set the timer to wait for the 30s aggregation packet. After the timer expires, send the stop frame. */
ret = mrs_timer_start(MRS_TIMER_ID_STA_POWER_FAILURE, power_failure_info->converge_time * MRS_US_TO_S_MASK,
EXT_TIMER_TYPE_ONCE);
if (ret != EXT_ERR_SUCCESS) {
return ret;
}
return ret;
}
td_u32 mrs_sta_handle_power_failue_ack(td_u16 seq)
{
td_u32 ret = EXT_ERR_FAILURE;
mrs_power_failure_ctrl_st *power_failure_info = mrs_get_power_failure_ctrl();
if (power_failure_info->wait_ack_flag == TD_FALSE) {
return EXT_ERR_SKIP;
}
/* ACK clearance flag (through the sequence number) */
if (power_failure_info->ack_seq == seq) {
power_failure_info->wait_ack_flag = TD_FALSE;
power_failure_info->send_report_times = 0;
return EXT_ERR_SUCCESS;
}
return ret;
}
/* Convert to standard bitmap_out */
td_void mrs_sta_update_normal_bitmap(td_u8 *bitmap_in, td_u8 *bitmap_out, td_u16 bitmap_len)
{
td_u16 i;
td_u16 j;
td_u16 bitmap_max_tei;
td_u16 bitmap_min_tei;
bitmap_min_tei = mrs_calc_min_tei(bitmap_in);
bitmap_max_tei = mrs_calc_max_tei(bitmap_in);
for (i = bitmap_min_tei, j = 0; i <= bitmap_max_tei && j < bitmap_len * BIT_SIZE; i++, j++) {
/* Determine which tei of the minimum tei is powered off, and position 1 in the new buf. */
if (mrs_power_failure_bit_check(bitmap_in, i) == TD_TRUE) {
mrs_power_failure_bit_set(bitmap_out, j);
}
}
}
td_void mrs_sta_reset_handle(td_void)
{
/* Start the power outage detection. */
uapi_start_power_failure_check();
mrs_timer_start(MRS_TIMET_ID_PULL_RST_DELAY_TIMER, 300, EXT_TIMER_TYPE_ONCE); /* timeout: 300 */
}
td_void mrs_power_failure_pull_rst_handle(td_void)
{
if (uapi_get_power_failure() == TD_TRUE) {
return;
}
uapi_usr_reboot(EXT_SYS_REBOOT_CAUSE_USR0);
}
#if 1
power_failure_ctrl_st g_pwf_ctrl = { 0 };
td_void mrs_pwf_init(td_void)
{
/* Start the periodic power outage detection timer. */
mrs_timer_start(MRS_TIMER_ID_STA_PW_CHECK, 1000, EXT_TIMER_TYPE_PERIOD); /* timeout: 1000 */
/* Start the power outage detection. */
uapi_start_power_failure_check();
}
td_void mrs_pwf_check_main(td_void)
{
td_bool is_power_failure;
td_u8 next_pwf_state = 0;
power_failure_ctrl_st *pwf_ctrl = &g_pwf_ctrl;
if (pwf_ctrl->pwf_switch == TD_FALSE) {
return;
}
/* This check is not completed. */
if (uapi_is_check_finish() == TD_FALSE) {
return;
}
/* Obtain the result of the last power outage detection. */
is_power_failure = uapi_get_power_failure();
/* Start a new power outage detection. */
uapi_start_power_failure_check();
switch (pwf_ctrl->pwf_state) {
/* Self-check Status */
case PWF_SELF_CHECK_STATE:
next_pwf_state = mrs_pwf_self_check_state(is_power_failure);
break;
/* Power-on status */
case PWF_POWER_UP_STATE:
next_pwf_state = mrs_pwf_power_on_state(is_power_failure);
break;
/* Power-off status */
case PWF_POWER_FAILURE_STATE:
next_pwf_state = mrs_pwf_power_failure_state(is_power_failure);
break;
default:
break;
}
pwf_ctrl->pwf_state = next_pwf_state;
}
td_u8 mrs_pwf_self_check_state(td_bool is_power_failure)
{
/* The device is powered on and enters the power-on state. */
if (is_power_failure == TD_FALSE) {
return PWF_POWER_UP_STATE;
}
return PWF_SELF_CHECK_STATE;
}
td_u8 mrs_pwf_power_on_state(td_bool is_power_failure)
{
mrs_power_failure_ctrl_st *power_failure_info = mrs_get_power_failure_ctrl();
if (is_power_failure == TD_FALSE) {
power_failure_info->start_send_time = 0;
if (memset_s(&g_rcv_report_info, sizeof(mrs_power_failure_rcv_report), 0,
sizeof(mrs_power_failure_rcv_report)) != EXT_ERR_SUCCESS) {
return PWF_SELF_CHECK_STATE;
}
return PWF_POWER_UP_STATE;
}
/* Check whether the module is removed and inserted. */
if (uapi_get_power_failure_is_plug_module() == EXT_ERR_SUCCESS && uapi_get_join_net_state() == TD_TRUE) {
/* The module is in the meter and enters the power-off state. The power failure is reported. */
g_pwf_ctrl.pwf_power_failure_time = uapi_get_seconds();
uapi_set_power_failure_state(TD_TRUE);
mrs_sta_handle_local_power_failure();
return PWF_POWER_FAILURE_STATE;
} else {
/* The module is removed and the status is switched to the self-check state. */
return PWF_SELF_CHECK_STATE;
}
}
td_u8 mrs_pwf_power_failure_state(td_bool is_power_failure)
{
if (is_power_failure == TD_TRUE) {
/* When the power failure time exceeds a certain threshold, the service function is restored and the self-check
status is switched. */
if (uapi_get_seconds() - g_pwf_ctrl.pwf_power_failure_time > g_pwf_ctrl.power_failure_recover_thd) {
uapi_set_power_failure_state(TD_FALSE);
return PWF_SELF_CHECK_STATE;
}
return PWF_POWER_FAILURE_STATE;
}
/* After the power-on, services are restored, and the self-check status is switched. */
uapi_set_power_failure_state(TD_FALSE);
return PWF_SELF_CHECK_STATE;
}
#endif
#endif