Files
kunlun/app/smart_grid/sta/iot_sg_sta.c
2024-09-28 14:24:04 +08:00

8966 lines
281 KiB
C
Executable File

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
/* os_shim header files */
#include "os_types_api.h"
#include "os_event_api.h"
#include "os_timer_api.h"
#include "os_utils_api.h"
/* iot common header files */
#include "iot_app_api.h"
#include "iot_swc_api.h"
#include "iot_swc_msg_api.h"
#include "iot_swc_msg_sta_api.h"
#include "iot_module_api.h"
#include "iot_errno_api.h"
#include "iot_queue_api.h"
#include "iot_mem_pool_api.h"
#include "iot_dbglog_api.h"
#include "iot_task_api.h"
#include "iot_io_api.h"
#include "iot_bitmap_api.h"
#include "iot_pib_api.h"
#include "iot_uart_api.h"
#include "iot_rtc_api.h"
#include "iot_plc_api.h"
#include "iot_plc_sta_api.h"
#include "iot_oem_api.h"
#include "iot_system_api.h"
#include "iot_plc_led_api.h"
/* smart grid internal header files */
#include "iot_sg_fr.h"
#include "iot_sg.h"
#include "iot_sg_msg.h"
#include "proto_gw_app.h"
#include "proto_nw_app.h"
#include "proto_645.h"
#include "proto_645_vendor.h"
#include "proto_645_topo.h"
#include "proto_69845.h"
#include "proto_69845_vendor.h"
#include "iot_sg_sta_upgrade.h"
#include "iot_sg_flash.h"
#include "iot_sg_sta_flash.h"
#include "iot_sg_sta_drv_api.h"
#include "iot_sg_sta_tsfm.h"
#include "iot_sg_sta_topo.h"
#include "iot_sg_sta_gw.h"
#include "iot_sg_sta_gw_v28.h"
#include "iot_sg_sta_nw.h"
#include "iot_sg_sta_conn_less.h"
#include "iot_sg_sta_ext.h"
#include "iot_sg_sta_ext_comm.h"
#include "iot_sg_sta_ext_mf.h"
#include "iot_sg_ext.h"
#include "iot_sg_ext_sta.h"
#include "iot_sg_ext_sta_api.h"
#include "iot_sg_sta_ext_upgrade.h"
/* hardware drive header files */
#include "iot_gpio_api.h"
#include "iot_board_api.h"
#if (IOT_SMART_GRID_ENABLE && PLC_SUPPORT_STA_ROLE)
/* 69845 meter normal event report timeout for CHONGQING, uint is 1ms. */
#define IOT_SG_STA_69845_METER_EVENT_RPT_DUR_CQ (75 * 1000)
/* normal event report min timeout, uint is 1ms. */
#define IOT_SG_STA_EVENT_RPT_DUR_MIN (10 * 1000)
/* normal event report max timeout, uint is 1ms. */
#define IOT_SG_STA_EVENT_RPT_DUR_MAX (20 * 1000)
/* event repprt timeout, uint is 1ms. for TAIYUAN */
#define IOT_SG_STA_EVENT_RPT_DUR_TAIYUAN (30 * 1000)
/* when sta is power off, collect power off event messages published by
* neighbor nodes timeout, uint is 1ms.
*/
#define IOT_SG_STA_POWEROFF_COLLECT_DUR (2 * 1000)
/* when sta isn't power off, sta get a random between 0 and this time,
* uint is 1ms.
*/
#define IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR (1000)
/* when sta is power off, get a random value between 0 and this time
* to report for BJ, unit is 1ms
*/
#define IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_BJ (5000)
/* when sta is power off, get a random time to report for HENAN, unit is 1ms */
#define IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_HENAN (4000)
/* when sta is power off, get a random time to report for ANHUI, unit is 1ms */
#define IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_ANHUI (4500)
/* when sta is power off, get a random time to report for NW, unit is 1ms */
#define IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_NW (3000)
/* when sta is power off, get a random value between 0 and this time
* to report for SHANGHAI, unit is 1ms
*/
#define IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_SH (200)
/* power on event report min timeout, uint is 1ms. */
#define IOT_SG_STA_POWERON_RPT_DUR_MIN (10 * 1000)
/* power on event report max timeout, uint is 1ms. */
#define IOT_SG_STA_POWERON_RPT_DUR_MAX (15 * 1000)
/* power on event report timeout, uint is 1ms. for HENAN */
#define IOT_SG_STA_POWERON_RPT_DUR_HENAN (2 * 1000)
/* power on event report random timeout, uint is 1ms. for HENAN */
#define IOT_SG_STA_POWERON_RPT_RANDOM_HENAN (500)
/* power on event report min delay after sta enter the network, uint is 1ms. */
#define IOT_SG_STA_POWERON_RPT_MIN_DELAY (1000)
/* power on event report delay after sta enter the network, uint is 1ms.
* for HENAN
*/
#define IOT_SG_STA_POWERON_RPT_DELAY_HENAN (5000)
/* power on event report max delay after sta enter the network, uint is 1ms. */
#define IOT_SG_STA_POWERON_RPT_MAX_DELAY (60 * 1000)
/* power on event report max delay after FUJIAN sta enter the network,
* uint is 1ms.
*/
#define IOT_SG_STA_POWERON_RPT_MAX_DELAY_FJ (20 * 1000)
/* when sta is power off, count is the max of reporting power off message,
* for SHANGHAI.
*/
#define IOT_SG_STA_POWEROFF_RPT_CNT_MAX_SH (10)
/* when sta is power off, count is the max of reporting power off message. */
#define IOT_SG_STA_POWEROFF_RPT_CNT_MAX (20)
/* when sta is power off, count is the max of reporting power off message,
* for FUJIAN.
*/
#define IOT_SG_STA_POWEROFF_RPT_CNT_MAX_FJ (30)
/* when sta isn't power off, count is the max of forwarding power off message.
*/
#define IOT_SG_STA_POWEROFF_FWD_CNT_MAX (3)
/* when sta isn't power off, count is the max of forwarding power off message,
* for FUJIAN.
*/
#define IOT_SG_STA_POWEROFF_FWD_CNT_MAX_FJ (6)
/* when sta is power on, count is the max of reporting power on message. */
#define IOT_SG_STA_POWERON_RPT_CNT_MAX (5)
/* when sta is power on, count is the max of reporting power on message,
* for FUJIAN.
*/
#define IOT_SG_STA_POWERON_RPT_CNT_MAX_FJ (6)
/* when sta is power on, count is the max of reporting power on message,
* for HENAN.
*/
#define IOT_SG_STA_POWERON_RPT_CNT_MAX_HENAN (10)
/* sm done event report max numeber */
#define IOT_SG_STA_SM_DONE_EVT_RPT_CNT_MAX (10)
/* sm done event report min timeout, uint is 1ms. */
#define IOT_SG_STA_SM_DONE_EVT_RPT_DUR_MIN (10 * 1000)
/* sm done event report max timeout, uint is 1ms. */
#define IOT_SG_STA_SM_DONE_EVT_RPT_DUR_MAX (15 * 1000)
/* when sta is power off, count is the max of checking one pm power state. */
#define IOT_SG_STA_CHECK_PM_PD_CNT_MAX (2)
/* when sta is power off, count is the min of checking one pm power state. */
#define IOT_SG_STA_CHECK_PM_PD_CNT_MIN (1)
/* debug info timeout. unit is 1 minute */
#define IOT_SG_STA_DEBUG_INFO_DUR (20)
/* debug read meter time info interval time. unit is 1s */
#define IOT_SG_STA_READ_METER_TIME_INTERVAL (3600)
/* debug read meter time info interval time for USER_TYPE_TM. unit is 1s */
#define IOT_SG_STA_READ_METER_TIME_INTERVAL_TM (3600 * 24)
/* debug the first read meter time info delay. unit is 1s*/
#define IOT_SG_STA_READ_METER_TIME_DELAY (60)
/* debug fastly read meter time info delay. unit is 1s*/
#define IOT_SG_STA_READ_METER_TIME_FAST (10)
/* nodes is in neighbor state query interval time. unit is 1min */
#define IOT_SG_STA_NODE_IN_NEIG_QUERY_INTERVAL (3)
/* refresh timeout. unit is 1ms */
#define IOT_SG_STA_REFRESH_DUR (1000)
/* poll timeout. unit is 1s */
#define IOT_SG_STA_POLL_DUR (60)
/* the timout is that sta check whether one power meter under sta are power off.
* unit is 1ms.
*/
#define IOT_SG_STA_CHECK_PM_PD_DUR (1000)
/* STA-PIN OUTPUT time. unit is 1s, uint is 1ms. */
#define IOT_SG_STA_PIN_STA_OUTPUT_TIME (200)
/* if detect done multiple times without meter detected, use module address to
* join the network first. this value defined the time value. unit is 1 round.
*/
#define IOT_SG_STA_DETECT_CNT_BEFORE_JOIN 1
/* define the period of clear correct time count, uint is 1min. */
#define IOT_SG_STA_TM_CORRECT_CLEAR_CNT_PERIOD (12 * 60)
/* define uart mode */
#define IOT_SG_STA_UART_MODE_SEND (1)
#define IOT_SG_STA_UART_MODE_REC (2)
/* define uart send cnt */
#define IOT_SG_STA_UART_SEND_CNT (20)
/* define collector ii WDG reset time, uint is 1min */
#define IOT_SG_STA_COLLECTOR_WDG_RESET_TIME (120)
/* define qsxj WDG reset time, uint is 1min */
#define IOT_SG_STA_QSXJ_WDG_RESET_TIME (24 * 60)
/* define moudle pulled out check timeout restart time, uint is 1ms */
#define IOT_SG_STA_PULL_OUT_CHECK_RESTART_TIME (5 * 60 * 1000)
/* define moudle pulled out check wait time. unit is 1s */
#define IOT_SG_STA_PULL_OUT_CHECK_WAIT_TIME (30)
/* define sta software record mode duration, unit is 1s */
#define IOT_SG_STA_SOFT_RECOR_MODE_DUR (60)
/* define driver state counts max */
#define IOT_SG_STA_DRV_STATE_CNT_MAX (5)
/* define rtc delta time max interval, uint is 1s */
#define IOT_SG_STA_RTC_DELTA_MAX_INTERVAL (10)
/* define factory test time max, unit is 1ms */
#define IOT_SG_STA_FACTORY_TIME_MAX (60 * 1000)
/* production test detected valid time from power on, unit is 1ms */
#define IOT_SG_STA_PT_DETECT_VALID_TIME (1000 * 60 * 3)
static const uint8_t switch_band_mac[] = { 0xDC, 0xEE, 0xEB, 0xDC, 0xBB, 0xCE };
static uint32_t iot_sg_sta_software_record_uart_send(iot_pkt_t *pkt);
static const uint8_t poweroff_event_trig_msg[] = { 0x68, 0xDE, 0xDE, 0xDE, 0xDE,
0xDE, 0xDE, 0x68, 0x00, 0x01, 0xFE, 0x03, 0x16 };
static uint32_t pm_power_off_event_trig_check(uint8_t *data, uint32_t len)
{
uint32_t ret = ERR_INVAL;
proto_645_header_t *hdr_645;
hdr_645 = proto_645_format_check_ext(data, len, PROTO_645_DIR_MASTER);
if (!hdr_645) {
goto out;
}
len = hdr_645->len + sizeof(*hdr_645) + sizeof(proto_645_tailer_t);
if ((sizeof(poweroff_event_trig_msg) == len)
&& (os_mem_cmp((uint8_t *)hdr_645, poweroff_event_trig_msg,
sizeof(poweroff_event_trig_msg)) == 0)) {
ret = ERR_OK;
}
out:
return ret;
}
#if IOT_SWC_ENABLE
static void iot_sg_sta_swc_msg_handle(iot_pkt_t *pkt,
iot_swc_msg_header_t * swc_hdr)
{
iot_swc_msdu_recv_t *msdu;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
msdu = (iot_swc_msdu_recv_t*)(swc_hdr + 1);
iot_pkt_pull(pkt, sizeof(*swc_hdr) + sizeof(*msdu));
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
iot_sg_sta_gw_msg_handle(pkt, msdu->data);
} else {
iot_sg_sta_nw_msg_handle(pkt, msdu->data);
}
}
/* handle message from swc link. It always consumed the iot_pkt in msg. */
static void iot_sg_handle_swc_data(iot_sg_msg_t *msg)
{
uint8_t pkt_consumed = 0;
iot_swc_msdu_recv_t *msdu;
gw_app_header_t *gw_app_hdr;
iot_pkt_t *pkt;
iot_swc_msg_header_t *swc_hdr;
iot_swc_dev_state_chg_rpt_t *st_chg_rpt;
pkt = (iot_pkt_t *)msg->data;
swc_hdr = (iot_swc_msg_header_t *)iot_pkt_block_ptr(pkt,
IOT_PKT_BLOCK_DATA);
switch (swc_hdr->msg_id) {
case IOT_SWC_MSG_DEV_STATE_CHG_RPT:
{
st_chg_rpt = (iot_swc_dev_state_chg_rpt_t*)iot_pkt_data(pkt);
if (st_chg_rpt->connected) {
p_sg_glb->desc.sta->swc_link_ready = 1;
} else {
p_sg_glb->desc.sta->swc_link_ready = 0;
}
break;
}
case IOT_SWC_MSG_KEEP_ALIVE:
case IOT_SWC_MSG_CFG_SET_CONF:
{
break;
}
case IOT_SWC_MSG_MSDU_RECV:
{
iot_sg_sta_swc_msg_handle(pkt, swc_hdr);
pkt_consumed = 1;
break;
}
default:
iot_sg_printf("nosupp msg_id %d\n", swc_hdr->msg_id);
break;
}
if (pkt_consumed == 0 && pkt) {
iot_pkt_free(pkt);
}
}
uint32_t iot_sg_send_msdu(iot_pkt_t* msdu_pkt, uint32_t prefer_link)
{
uint32_t result = ERR_OK;
iot_plc_msdu_send_t *send;
if (msdu_pkt == NULL) {
return ERR_INVAL;
}
/* fix len field in iot_plc_msdu_send_t structure */
send = (iot_plc_msdu_send_t *)(iot_pkt_data(msdu_pkt) +
sizeof(iot_plc_msg_header_t));
send->len = (uint16_t)(iot_pkt_data_len(msdu_pkt) - sizeof(*send) -
sizeof(iot_plc_msg_header_t));
switch (prefer_link) {
case IOT_SG_LINK_TYPE_PLC:
{
if (p_sg_glb->plc_state.link_ready) {
iot_plc_send_msdu(p_sg_glb->plc_app_h, msdu_pkt);
} else if (p_sg_glb->desc.sta->swc_link_ready) {
/* send reply through swc link. */
iot_swc_send_plc_msdu(msdu_pkt);
} else {
result = ERR_NOT_READY;
iot_pkt_free(msdu_pkt);
}
break;
}
case IOT_SG_LINK_TYPE_SWC:
{
if (p_sg_glb->desc.sta->swc_link_ready) {
/* send reply through swc link. */
iot_swc_send_plc_msdu(msdu_pkt);
} else if (p_sg_glb->plc_state.link_ready) {
iot_plc_send_msdu(p_sg_glb->plc_app_h, msdu_pkt);
} else {
result = ERR_NOT_READY;
iot_pkt_free(msdu_pkt);
}
break;
}
case IOT_SG_LINK_TYPE_PLC_BRM:
{
iot_plc_send_msdu(p_sg_glb->brm_app_h, msdu_pkt);
break;
}
case IOT_SG_LINK_TYPE_PLC_CONN_LESS:
case IOT_SG_LINK_TYPE_PLC_CTRL:
{
iot_plc_send_msdu(p_sg_glb->plc_app_h, msdu_pkt);
break;
}
default:
IOT_ASSERT(0);
break;
}
if (result) {
iot_sg_printf("%s err link %lu\n", __FUNCTION__, prefer_link);
}
return result;
}
#else // IOT_SWC_ENABLE
static void iot_sg_handle_swc_data(iot_sg_msg_t *msg)
{
iot_pkt_t *pkt = (iot_pkt_t*)msg->data;
if (pkt) {
iot_pkt_free(pkt);
}
}
uint32_t iot_sg_send_msdu(iot_pkt_t* msdu_pkt, uint32_t prefer_link)
{
uint32_t result = ERR_OK;
iot_plc_msdu_send_t *send;
if (msdu_pkt == NULL) {
return ERR_INVAL;
}
/* fix len field in iot_plc_msdu_send_t structure */
send = (iot_plc_msdu_send_t *)(iot_pkt_data(msdu_pkt) +
sizeof(iot_plc_msg_header_t));
send->len = (uint16_t)(iot_pkt_data_len(msdu_pkt) - sizeof(*send) -
sizeof(iot_plc_msg_header_t));
if (prefer_link == IOT_SG_LINK_TYPE_PLC) {
if (p_sg_glb->plc_state.link_ready) {
iot_plc_send_msdu(p_sg_glb->plc_app_h, msdu_pkt);
} else {
result = ERR_NOT_READY;
iot_sg_printf("%s err\n", __FUNCTION__);
iot_pkt_free(msdu_pkt);
}
} else if (prefer_link == IOT_SG_LINK_TYPE_PLC_BRM) {
iot_plc_send_msdu(p_sg_glb->brm_app_h, msdu_pkt);
} else {
iot_plc_send_msdu(p_sg_glb->plc_app_h, msdu_pkt);
}
return result;
}
#endif
void iot_sg_sta_rtc_set(iot_time_tm_t *tm, uint8_t sys_flag)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!sys_flag && sta_glb->rtc_sync_flag) {
return;
}
sta_glb->time_flag = 1;
sta_glb->rtc_sync_flag = sys_flag;
iot_rtc_set(tm);
iot_sg_printf("%s %02d-%02d-%02d %02d:%02d:%02d rtc_sync_flag %lu\n",
__FUNCTION__, tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
tm->tm_min, tm->tm_sec, sta_glb->rtc_sync_flag);
}
uint32_t iot_sg_sta_rtc_get(iot_time_tm_t *tm, uint8_t sys_flag)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!sta_glb->time_flag || (sys_flag && !sta_glb->rtc_sync_flag)) {
return ERR_FAIL;
}
iot_rtc_get(tm);
return ERR_OK;
}
uint32_t iot_sg_sta_rtc_valid_check(uint8_t sys_flag)
{
uint32_t ret = ERR_FAIL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!sta_glb->time_flag) {
goto out;
}
if (sys_flag && !sta_glb->rtc_sync_flag) {
goto out;
}
ret = ERR_OK;
out:
return ret;
}
void iot_sg_sta_rtc_clear(uint8_t sys_flag)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sys_flag) {
sta_glb->rtc_sync_flag = 0;
} else {
sta_glb->rtc_sync_flag = 0;
sta_glb->time_flag = 0;
}
}
static uint8_t iot_sg_sta_rtc_recover_check()
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint8_t recover = 0, user_type = iot_sg_sta_get_user_type();
uint32_t dev_type = sta_glb->drv->get_device_type();
if (sta_glb->br2_enable) {
recover = 1;
} else if (dev_type == IOT_SG_STA_DEV_TYPE_POWER_METER ||
dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T2) {
if (user_type == USER_TYPE_STATE_GRID_XIAN ||
user_type == USER_TYPE_STATE_GRID_HEBEI ||
user_type == USER_TYPE_STATE_GRID_HUNAN ||
user_type == USER_TYPE_STATE_GRID_MENGDONG_LC ||
user_type == USER_TYPE_BRM_PEIWANG_DUAL_NET ||
user_type == USER_TYPE_SOUTHEN_POWER_GRID_GUANGDONG ||
user_type == USER_TYPE_SOUTHEN_POWER_GRID_SHENZHEN ||
user_type == USER_TYPE_SOUTHEN_POWER_GRID_HAINAN ||
sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
recover = 1;
}
} else if (dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T3) {
recover = 1;
}
return recover;
}
static uint32_t iot_sg_sta_pib_tm_delta_valid_check()
{
uint32_t ret = ERR_INVAL;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (!iot_mac_addr_valid(p_sg_glb->plc_state.addr)) {
goto out;
}
if (!iot_mac_addr_valid(sta_pib->pm_addr)) {
goto out;
}
if (!iot_mac_addr_cmp(p_sg_glb->plc_state.addr, sta_pib->pm_addr)) {
goto out;
}
ret = ERR_OK;
out:
return ret;
}
static void iot_sg_sta_rtc_recover_from_pib(iot_time_tm_t *tm)
{
uint8_t reason = 0, user_type = iot_sg_sta_get_user_type();
uint8_t soft_reason, reset_reason;
uint32_t delta_max = 0;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_time_tm_t rtc_tm = { 0 };
(void)soft_reason;
if (!iot_sg_sta_rtc_recover_check()) {
reason = 1;
goto out;
}
if (iot_sg_sta_rtc_valid_check(1) == ERR_OK) {
reason = 2;
goto out;
}
if (iot_sg_sta_pib_tm_delta_valid_check() != ERR_OK) {
reason = 3;
goto out;
}
reset_reason = (uint8_t)iot_board_get_boot_reason(&soft_reason);
if ((sta_glb->proto == IOT_SG_STA_APP_PROTO_NW)
&& ((sta_pib && sta_pib->power_off_flag)
|| (reset_reason == SYSTEM_RESET_PWR))) {
reason = 4;
goto out;
}
if (user_type == USER_TYPE_STATE_GRID_XIAN) {
delta_max = IOT_SG_STA_TM_DELTA_MAX_XIAN;
} else if (user_type == USER_TYPE_SOUTHEN_POWER_GRID_GUANGDONG) {
delta_max = IOT_SG_STA_TM_DELTA_MAX_GUANGDONG;
} else if (user_type == USER_TYPE_STATE_GRID_HEBEI) {
delta_max = IOT_SG_STA_TM_DELTA_MAX_HEBEI;
} else {
delta_max = IOT_SG_STA_TM_DELTA_MAX_XIAN;
}
if (IOT_ABS(sta_pib->tm_sta_delta) > delta_max) {
reason = 5;
goto out;
}
rtc_tm = *tm;
iot_rtc_delta_add(sta_pib->tm_sta_delta, &rtc_tm);
iot_sg_sta_rtc_set(&rtc_tm, 1);
out:
iot_sg_printf("%s reason %d\n", __FUNCTION__, reason);
return;
}
static void iot_sg_sta_rtc_delta_save_to_pib(iot_time_tm_t *tm)
{
int64_t rtc_delta;
iot_time_tm_t rtc_tm = { 0 };
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (!iot_sg_sta_rtc_recover_check()) {
goto out;
}
if (iot_sg_sta_rtc_get(&rtc_tm, 1) != ERR_OK) {
goto out;
}
rtc_delta = iot_rtc_delta_calc(tm, &rtc_tm);
if (iot_sg_sta_pib_tm_delta_valid_check() == ERR_OK) {
if (IOT_ABS(sta_pib->tm_sta_delta - rtc_delta) <
IOT_SG_STA_RTC_DELTA_MAX_INTERVAL) {
goto out;
}
}
iot_sg_sta_save_correct_tm_pib(rtc_delta, p_sg_glb->plc_state.addr);
out:
return;
}
uint32_t iot_sg_sta_rtc_get_m_t(iot_time_tm_t *tm)
{
uint32_t ret = ERR_FAIL;
int64_t delta;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (!sta_glb->time_flag) {
goto out;
}
iot_rtc_get(tm);
if (sta_glb->rtc_sync_flag) {
if (!iot_sg_sta_rtc_recover_check() || (sta_pib == NULL)) {
goto out;
}
delta = 0 - sta_pib->tm_sta_delta;
iot_rtc_delta_add(delta, tm);
}
ret = ERR_OK;
out:
return ret;
}
static void iot_sg_sta_uart_abnormal_led_en(uint8_t en)
{
uint8_t user_type = iot_sg_sta_get_user_type();
iot_sg_sta_drv_t *drv = p_sg_glb->desc.sta->drv;
if (user_type != USER_TYPE_STATE_GRID_ANHUI) {
goto out;
}
if (!drv || drv->get_device_type() != IOT_SG_STA_DEV_TYPE_POWER_METER) {
goto out;
}
if (en) {
/* uart communication abnormal */
iot_plc_led_request(IOT_PLC_LED_SEARCH_METER_END);
} else {
iot_plc_led_request(IOT_PLC_LED_SEARCH_METER_START);
}
out:
return;
}
static void iot_sg_sta_uart_check(uint8_t mode)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
switch (mode) {
case IOT_SG_STA_UART_MODE_SEND:
{
sta_glb->uart_state_info.send_cnt++;
if (sta_glb->uart_state_info.send_cnt > IOT_SG_STA_UART_SEND_CNT) {
sta_glb->uart_state_info.send_cnt = IOT_SG_STA_UART_SEND_CNT;
sta_glb->uart_state_info.curr_uart_state = 1;
iot_sg_sta_uart_abnormal_led_en(1);
}
break;
}
case IOT_SG_STA_UART_MODE_REC:
{
if (sta_glb->uart_state_info.curr_uart_state) {
sta_glb->uart_state_info.once_uart_state = 1;
iot_sg_sta_uart_abnormal_led_en(0);
}
sta_glb->uart_state_info.send_cnt = 0;
sta_glb->uart_state_info.curr_uart_state = 0;
break;
}
default:
break;
}
}
uint8_t iot_sg_sta_uart_state_get(void)
{
uint8_t state = IOT_SG_STA_UART_STATE_NORMAL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->uart_state_info.curr_uart_state) {
state = IOT_SG_STA_UART_STATE_ABNORMAL;
goto out;
}
if (sta_glb->uart_state_info.once_uart_state) {
state = IOT_SG_STA_UART_STATE_ONCE_ABNORMAL;
}
out:
return state;
}
uint8_t iot_sg_sta_get_proto_type(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
return sta_glb->proto;
}
void iot_sg_sta_get_tsfm_result(iot_sg_sta_tsfm_result_t *tsfm_result)
{
uint8_t tsfm_addr[IOT_MAC_ADDR_LEN];
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
iot_plc_tsfm_status_rpt_t *tsfm_status = &(sta_glb->tsfm_status);
if (iot_mac_addr_valid(sta_pib->tsfm_addr) &&
!iot_mac_is_bcast(sta_pib->tsfm_addr)) {
/* hardware tsfm address valid */
tsfm_result->hw_tsfm_done = 1;
iot_mac_addr_cpy(tsfm_addr, sta_pib->tsfm_addr);
iot_mac_addr_reverse(tsfm_addr);
if (!iot_mac_addr_valid(p_sg_glb->plc_state.cco_addr)) {
tsfm_result->hw_tsfm_result = IOT_SG_STA_TSFM_DETECT_RET_UNKNOWN;
} else if (iot_mac_addr_cmp(p_sg_glb->plc_state.cco_addr, tsfm_addr)) {
tsfm_result->hw_tsfm_result = IOT_SG_STA_TSFM_DETECT_RET_SAME;
} else {
tsfm_result->hw_tsfm_result = IOT_SG_STA_TSFM_DETECT_RET_DIFFERENT;
}
iot_mac_addr_cpy(tsfm_result->hw_tsfm_addr, tsfm_addr);
} else {
tsfm_result->hw_tsfm_done = 0;
tsfm_result->hw_tsfm_result = IOT_SG_STA_TSFM_DETECT_RET_UNKNOWN;
os_mem_set(tsfm_result->hw_tsfm_addr, 0, IOT_MAC_ADDR_LEN);
}
if (tsfm_status->status == IOT_PLC_TSFM_DETECT_DONE) {
tsfm_result->sw_tsfm_done = 1;
if (iot_mac_addr_cmp(tsfm_status->cco_addr, tsfm_status->tsfm_addr)
|| iot_mac_addr_cmp(tsfm_status->cco_addr,
tsfm_status->tsfm_cco_addr)) {
tsfm_result->sw_tsfm_result = IOT_SG_STA_TSFM_DETECT_RET_SAME;
} else {
tsfm_result->sw_tsfm_result = IOT_SG_STA_TSFM_DETECT_RET_DIFFERENT;
}
if (iot_mac_addr_valid(tsfm_status->tsfm_addr)
&& !iot_mac_is_bcast(tsfm_status->tsfm_addr)) {
iot_mac_addr_cpy(tsfm_result->sw_tsfm_addr, tsfm_status->tsfm_addr);
} else {
iot_mac_addr_cpy(tsfm_result->sw_tsfm_addr,
tsfm_status->tsfm_cco_addr);
}
} else {
tsfm_result->sw_tsfm_done = 0;
tsfm_result->sw_tsfm_result = IOT_SG_STA_TSFM_DETECT_RET_UNKNOWN;
os_mem_set(tsfm_result->sw_tsfm_addr, 0, IOT_MAC_ADDR_LEN);
}
}
void iot_sg_sta_set_hw_tsfm_addr(uint8_t *addr)
{
uint8_t tmp_addr[IOT_MAC_ADDR_LEN] = { 0 };
iot_sg_sta_tsfm_info_t info = { 0 };
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (iot_mac_addr_valid(sta_pib->tsfm_addr) &&
iot_mac_addr_cmp(sta_pib->tsfm_addr, addr) == 1) {
/* the existing ones are the same as the ones to be set, skipping
* and reducing unnecessary PIB writing.
*/
goto out;
}
if (iot_sg_sta_hw_tsfm_is_3p()) {
if (iot_mac_addr_valid(sta_pib->tsfm_addr)) {
iot_mac_addr_cpy(tmp_addr, sta_pib->tsfm_addr);
iot_mac_addr_reverse(tmp_addr);
iot_plc_set_whitelist(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, IOT_PLC_WL_DEL, 1, tmp_addr);
}
iot_mac_addr_cpy(tmp_addr, addr);
iot_mac_addr_reverse(tmp_addr);
iot_plc_set_whitelist(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, IOT_PLC_WL_ADD, 1, tmp_addr);
}
iot_mac_addr_cpy(info.cco_addr, addr);
iot_sg_sta_save_tsfm_info(&info);
out:
return;
}
static void iot_sg_sta_ext_time_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_INTERNAL;
msg->task_msg.id = IOT_SG_MSG_ID_INTERN_EXT_SM;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
uint8_t iot_sg_sta_645_proto_to_drv(uint8_t p_id)
{
uint8_t data_type = IOT_SG_STA_DATA_TYPE_TRANS;
switch (p_id) {
case PROTO_645_1997_ID:
{
data_type = IOT_SG_STA_DATA_TYPE_645_97;
break;
}
case PROTO_645_2007_ID:
{
data_type = IOT_SG_STA_DATA_TYPE_645_07;
break;
}
case PROTO_UNKNOWN_ID:
default:
{
break;
}
}
return data_type;
}
uint8_t iot_sg_sta_drv_to_645_proto(uint8_t type)
{
uint8_t p_id = PROTO_UNKNOWN_ID;
switch (type) {
case IOT_SG_STA_DATA_TYPE_645_97:
{
p_id = PROTO_645_1997_ID;
break;
}
case IOT_SG_STA_DATA_TYPE_645_07:
{
p_id = PROTO_645_2007_ID;
break;
}
default:
{
break;
}
}
return p_id;
}
/* debug printf timer time out function */
static void iot_sg_sta_refresh_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_STA_REFRESH;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
static void iot_sg_sta_power_off_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_POWER_OFF;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
static void iot_sg_sta_power_on_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_POWER_ON;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
static void iot_sg_sta_sm_done_chk_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_SM_DONE_CHK;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
static void iot_sg_sta_pinsta_high(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->sta_out_timer) {
os_stop_timer(sta_glb->sta_out_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_PIN_STA_OUTPUT);
iot_gpio_value_set(sta_glb->sta_out_gpio_num, 1);
os_start_timer(sta_glb->sta_out_timer, IOT_SG_STA_PIN_STA_OUTPUT_TIME);
}
}
static void iot_sg_sta_pinsta_low(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->sta_out_timer) {
iot_gpio_value_set(sta_glb->sta_out_gpio_num, 0);
}
}
static void iot_sg_sta_pinsta_time_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_PIN_STA_OUTPUT;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
iot_sg_sta_pinsta_low();
}
}
static void iot_sg_sta_print_log_to_flash()
{
uint8_t user_type = iot_sg_sta_get_user_type();
uint8_t i, j, year_h, year_l;
uint32_t mr_err_buf[3] = { 0 };
uint32_t drv_state_cnt_buf[IOT_SG_STA_DRV_STATE_CNT_MAX] = { 0 };
uint32_t ymd = 0, hms = 0, tmp;
iot_time_tm_t tm = { 0 };
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_mr_stats_t *mr_stats = &sta_glb->mr.mr_info;
uint8_t *err_cnt = mr_stats->mr_err_cnts;
BUILD_BUG_ON(IOT_ARRAY_CNT(mr_err_buf) > (IOT_SG_STA_MR_ERR_MAX >> 2));
os_mem_set(mr_err_buf, 0x0, sizeof(mr_err_buf));
for (i = 0, j = 0; i <= IOT_SG_STA_MR_ERR_MAX; i++) {
mr_err_buf[j] |= (err_cnt[i] << ((i % 4) << 3));
if ((i % 4) == 3) {
j++;
}
}
tmp = sta_glb->drv->drv_id;
tmp |= ((uint32_t)user_type) << 16;
tmp |= ((uint32_t)sta_glb->proto) << 24;
iot_sg_sta_rtc_get(&tm, 0);
year_h = (uint8_t)(tm.tm_year / 100);
year_l = (uint8_t)(tm.tm_year % 100);
ymd = (iot_byte_to_bcd(year_h) << 24)
| (iot_byte_to_bcd(year_l) << 16)
| (iot_byte_to_bcd((uint8_t)tm.tm_mon) << 8)
| iot_byte_to_bcd((uint8_t)tm.tm_mday);
hms = (iot_byte_to_bcd((uint8_t)tm.tm_hour) << 16)
| (iot_byte_to_bcd((uint8_t)tm.tm_min) << 8)
| iot_byte_to_bcd((uint8_t)tm.tm_sec);
iot_sg_printf("%s time YYYYMMDD %08x-HHMMSS %06x, "
"app_proto-user_type-drv_id %08x, rec corr "
"cnt %lu, drv send corr cnt %lu, mr_err_cnt %08x:%08x:%08x\n",
__FUNCTION__, ymd, hms, tmp, mr_stats->rec_correct_cnt,
mr_stats->drv_send_correct_cnt, mr_err_buf[0],
mr_err_buf[1], mr_err_buf[2]);
iot_sg_printf("%s sta mr stats - con_mr_cnt %lu, sus_cnt %lu;"
" rt_mr_cnt %lu, sus_cnt %lu; cctt_mr_cnt %lu, sus_cnt %lu;"
" bl_mr_cnt %lu; cache_mr_hit_cnt %lu; join_cnt = %d, "
"leave_cnt = %d\n", __FUNCTION__,
mr_stats->rec_valid_con_mr_cnt, mr_stats->con_mr_sus_cnt,
mr_stats->rec_valid_rt_mr_cnt, mr_stats->rt_mr_sus_cnt,
mr_stats->rec_valid_cctt_mr_cnt, mr_stats->cctt_mr_sus_cnt,
mr_stats->mr_bl_cnt, mr_stats->mr_cache_cnt, mr_stats->join_cnt,
mr_stats->leave_cnt);
if (sta_glb->drv->get_state_cnt) {
sta_glb->drv->get_state_cnt(drv_state_cnt_buf,
IOT_SG_STA_DRV_STATE_CNT_MAX);
iot_sg_printf("%s sta drv stats - drv id %lu, drv_state_cnt "
"%08X:%08X:%08X:%08X:%08X\n", __FUNCTION__,
sta_glb->drv->drv_id, drv_state_cnt_buf[0],
drv_state_cnt_buf[1], drv_state_cnt_buf[2],
drv_state_cnt_buf[3], drv_state_cnt_buf[4]);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_DRV_STATE_COUNT_ID, 6, sta_glb->drv->drv_id,
drv_state_cnt_buf[0], drv_state_cnt_buf[1],
drv_state_cnt_buf[2], drv_state_cnt_buf[3],
drv_state_cnt_buf[4]);
}
if (user_type == USER_TYPE_STATE_GRID_FUJIAN) {
iot_sg_printf("%s evt_rpt_fj mode %lu, type %lu, en_fj %lu\n",
__FUNCTION__, sta_glb->evt.fj_evt_rpt_mode,
sta_glb->evt.fj_evt_rpt_type, sta_glb->evt.fj_evt_rpt_en);
}
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_DUMP_STATUS_2_ID, 8, ymd, hms, tmp,
mr_stats->rec_correct_cnt, mr_stats->drv_send_correct_cnt,
mr_err_buf[0], mr_err_buf[1], mr_err_buf[2]);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_DUMP_STATUS_1_ID, 9,
mr_stats->rec_valid_con_mr_cnt, mr_stats->con_mr_sus_cnt,
mr_stats->rec_valid_rt_mr_cnt, mr_stats->rt_mr_sus_cnt,
mr_stats->rec_valid_cctt_mr_cnt, mr_stats->cctt_mr_sus_cnt,
mr_stats->mr_bl_cnt, mr_stats->mr_cache_cnt,
((mr_stats->join_cnt << 16) + mr_stats->leave_cnt));
}
static uint32_t iot_sg_sta_get_pm_addr(iot_pkt_t *pkt,
uint8_t link_type, uint8_t *addr)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if ((link_type == IOT_SG_LINK_TYPE_PLC_CONN_LESS)
|| (link_type == IOT_SG_LINK_TYPE_APP)
|| (link_type == IOT_SG_LINK_TYPE_CUS)
|| (link_type == IOT_SG_LINK_TYPE_PLC_BRM)) {
ret = iot_sg_sta_conn_less_get_pm_addr(pkt, addr);
} else {
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_get_pm_addr(pkt, addr);
} else {
ret = iot_sg_sta_nw_get_pm_addr(pkt, addr);
}
}
return ret;
}
static uint8_t iot_sg_sta_conn_fwd_msg_check(iot_pkt_t *pkt,
uint8_t link_type)
{
uint8_t conn_trans = 0;
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (link_type != IOT_SG_LINK_TYPE_PLC) {
goto out;
}
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_conn_fwd_msg_check(pkt);
} else {
ret = ERR_FAIL;
}
if (ret == ERR_OK) {
conn_trans = 1;
}
out:
return conn_trans;
}
static void iot_sg_sta_set_pm_addr()
{
uint8_t cnt = 0, idx = 0;
uint8_t *data = NULL, *data_ptr = NULL;
iot_pkt_t *pkt = NULL;
iot_sg_sta_node_desc_t *node;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
cnt = iot_sg_node_reg_get_node_cnt();
if (!cnt) {
goto set_addr;
}
pkt = iot_pkt_alloc(cnt * IOT_MAC_ADDR_LEN, IOT_SMART_GRID_MID);
if (!pkt) {
goto out;
}
data = iot_pkt_data(pkt);
data_ptr = data;
iot_pkt_put(pkt, cnt * IOT_MAC_ADDR_LEN);
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
node = sta_glb->node_list[idx];
if (iot_sg_sta_node_valid_check(node)) {
iot_mac_addr_cpy(data_ptr, node->entry.addr);
iot_mac_addr_reverse(data_ptr);
data_ptr += IOT_MAC_ADDR_LEN;
}
}
set_addr:
iot_plc_set_pm_addr(p_sg_glb->plc_app_h, sta_glb->last_addr_reqid,
data, cnt);
out:
if (pkt) {
iot_pkt_free(pkt);
}
}
/**
* @brief: sta set address list state
* @param addr_state: sta address list state
* 0 - no changed, 1 - changed, other values is invalid.
*/
static void iot_sg_sta_set_addr_list_state(uint8_t addr_state)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (addr_state) {
sta_glb->addr_list_change = 1;
sta_glb->last_addr_reqid++;
} else {
sta_glb->addr_list_change = 0;
}
}
static uint32_t iot_sg_sta_get_pm_addr_in_proto(iot_pkt_t *pkt,
uint8_t *addr)
{
uint8_t *data, *ser_addr;
uint32_t ret = ERR_FAIL, data_len;
proto_645_header_t *hdr_645;
proto_69845_frame_head_info_t *hdr_69845;
data = iot_pkt_data(pkt);
data_len = iot_pkt_data_len(pkt);
hdr_645 = proto_645_format_check(data, data_len,
PROTO_645_DIR_MASTER);
if (hdr_645) {
if (proto_645_pm_addr_valid(hdr_645->addr)) {
iot_mac_addr_cpy(addr, hdr_645->addr);
ret = ERR_OK;
}
} else {
hdr_69845 = proto_69845_sanity_check(data, (uint16_t)data_len);
if (hdr_69845) {
ser_addr = proto_69845_get_ser_addr(hdr_69845);
iot_mac_addr_cpy(addr, ser_addr);
ret = ERR_OK;
}
}
return ret;
}
void iot_sg_sta_get_fj_evt_cfg_info(iot_sg_sta_drv_fj_evt_rpt_cfg_t *evt_cfg)
{
iot_sg_sta_evt_global_t *evt = &p_sg_glb->desc.sta->evt;
evt_cfg->fj_evt_rpt_en = evt->fj_evt_rpt_en;
evt_cfg->fj_evt_rpt_mode = evt->fj_evt_rpt_mode;
evt_cfg->fj_evt_rpt_type = evt->fj_evt_rpt_type;
}
static void iot_sg_sta_event_rpt_seq_init()
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
sta_glb->evt.event_rpt_seq = (uint16_t)os_rand();
}
/* get next event report sequence number */
uint16_t iot_sg_sta_get_event_rpt_seq()
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
sta_glb->evt.event_rpt_seq++;
if (sta_glb->evt.event_rpt_seq == 0) {
sta_glb->evt.event_rpt_seq++;
}
return sta_glb->evt.event_rpt_seq;
}
/* check if pm event report sequence match */
bool_t iot_sg_sta_check_pm_event_rpt_seq(uint16_t seq)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
return (sta_glb->evt.pm_evt_rpt_seq == seq);
}
/* check if power on event report sequence match */
uint8_t iot_sg_sta_check_power_on_rpt_seq(uint16_t seq)
{
uint8_t is_same = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->evt.power_on_rpt_seq == seq) {
is_same = 1;
}
return is_same;
}
/* check if power off forward sequence match */
uint8_t iot_sg_sta_check_power_off_fwd_seq(uint16_t seq)
{
uint8_t is_same = 0, i;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_pd_addrs_ctrl_t *pd_addr_ctrl = &sta_glb->evt.pd_addr_ctrl;
iot_sg_sta_pd_addrs_buf_t *addrs_buf = pd_addr_ctrl->addrs_buf;
/* power off bitmap forward sequence */
if (sta_glb->evt.power_off_rpt_seq == seq) {
is_same = 1;
goto out;
}
/* power off address forward sequence */
for (i = 0; i < IOT_SG_STA_PD_ADDRS_BUF_CNT; i++) {
if (addrs_buf[i].pkt == NULL)
break;
if (addrs_buf[i].seq == seq) {
is_same = 1;
goto out;
}
}
out:
return is_same;
}
/* read data from persistent storage */
static uint32_t iot_sg_sta_load_pib_info(iot_sg_sta_global_t *sta_glb)
{
uint32_t ret = ERR_OK;
if (p_sg_glb->pib.sta.ro == NULL) {
/* The PIB file does not exist
* NODE: the default read-only and writable sections are always loaded
* successfully and unsuccessfully at the same.
*/
sta_glb->pib.ro = os_mem_malloc(IOT_SMART_GRID_MID,
sizeof(*sta_glb->pib.ro));
if (sta_glb->pib.ro == NULL) {
ret = ERR_NOMEM;
goto out;
}
sta_glb->pib.rw = os_mem_malloc(IOT_SMART_GRID_MID,
sizeof(*sta_glb->pib.rw));
if (sta_glb->pib.rw == NULL) {
os_mem_free(sta_glb->pib.ro);
ret = ERR_NOMEM;
goto out;
}
#if HW_PLATFORM == HW_PLATFORM_SIMU
extern uint8_t g_station_drv_id;
extern uint8_t g_station_ct2_drv_sm97_en;
extern uint8_t g_station_ct2_drv_virtual_disable;
extern uint8_t g_station_ct2_drv_collector_addr_en;
extern uint8_t g_station_flash_mode;
extern uint8_t g_station_esp_mode;
extern uint8_t g_station_meter_ext_en;
extern uint8_t g_enable_collector_i_check;
sta_glb->pib.ro->cfg.fr.ct2_sm97_en =
(g_station_ct2_drv_sm97_en != 0);
sta_glb->pib.ro->cfg.fr.ct2_virtual_disable =
(g_station_ct2_drv_virtual_disable != 0);
sta_glb->pib.ro->cfg.fr.ct2_collector_addr_en =
(g_station_ct2_drv_collector_addr_en != 0);
sta_glb->pib.ro->cfg.fr.en_ext_func =
(g_station_meter_ext_en != 0);
sta_glb->pib.ro->cfg.fr.pm_detect_mpde_sel =
(g_enable_collector_i_check != 0);
if (g_station_drv_id > IOT_SG_STA_DRV_ID_MAX) {
sta_glb->pib.ro->cfg.drv_id = IOT_SG_STA_DRV_ID_INVALID;
} else {
sta_glb->pib.ro->cfg.drv_id = g_station_drv_id;
}
#elif IOT_SMART_GRID_TEST_DRV_ENABLE
sta_glb->pib.ro->cfg.drv_id = IOT_SG_STA_DRV_ID_TEST;
sta_glb->pib.ro->cfg.fr.en_ext_func = 0;
#else
sta_glb->pib.ro->cfg.drv_id = IOT_SG_STA_DRV_ID_INVALID;
sta_glb->pib.ro->cfg.fr.ct2_sm97_en = 0;
sta_glb->pib.ro->cfg.fr.ct2_virtual_disable = 0;
sta_glb->pib.ro->cfg.fr.ct2_collector_addr_en = 0;
sta_glb->pib.ro->cfg.fr.en_ext_func = 0;
sta_glb->pib.ro->cfg.fr.pm_detect_mpde_sel = 0;
#endif
} else {
sta_glb->pib.ro = p_sg_glb->pib.sta.ro;
sta_glb->pib.rw = p_sg_glb->pib.sta.rw;
}
if (p_sg_glb->module_type == MODULE_TYPE_STA &&
sta_glb->pib.rw->sta.is_three_phase) {
p_sg_glb->module_type = MODULE_TYPE_3_PHASE_STA;
}
if ((p_sg_glb->module_type == MODULE_TYPE_STA
|| p_sg_glb->module_type == MODULE_TYPE_3_PHASE_STA)
&& iot_sg_sta_get_user_type() == USER_TYPE_FLX
&& sta_glb->pib.ro->cfg.drv_id == IOT_SG_STA_DRV_ID_INVALID) {
sta_glb->pib.ro->cfg.drv_id = IOT_SG_STA_DRV_ID_CT1;
}
out:
return ret;
}
void iot_sg_sta_unload_pib_info(iot_sg_sta_global_t *sta_glb)
{
if (p_sg_glb->pib.sta.ro == NULL) {
/* this means that the PIB file was initially not loaded
* successfully.
*/
if (sta_glb->pib.ro) {
os_mem_free(sta_glb->pib.ro);
sta_glb->pib.ro = NULL;
}
if (sta_glb->pib.rw) {
os_mem_free(sta_glb->pib.rw);
sta_glb->pib.rw = NULL;
}
}
}
/* get common configuration information for station */
iot_sg_sta_cmn_cfg_t *iot_sg_sta_get_cmn_cfg(void)
{
if (p_sg_glb->desc.sta->pib.ro != NULL) {
return &p_sg_glb->desc.sta->pib.ro->cfg;
}
return NULL;
}
uint8_t *iot_sg_sta_get_drv_pib(uint32_t *drv_len)
{
uint8_t *drv_pib = NULL;
if (p_sg_glb->desc.sta->pib.rw != NULL) {
drv_pib = p_sg_glb->desc.sta->pib.rw->drv;
(*drv_len) = sizeof(p_sg_glb->desc.sta->pib.rw->drv);
}
return drv_pib;
}
iot_sg_sta_app_info_t *iot_sg_sta_get_rw_pib(void)
{
iot_sg_sta_app_info_t *sta_pib = NULL;
if (p_sg_glb->desc.sta->pib.rw != NULL) {
sta_pib = &(p_sg_glb->desc.sta->pib.rw->sta);
}
return sta_pib;
}
static void iot_sg_sta_change_power_off_info_pib(uint8_t power_off_flag)
{
uint8_t ref;
uint8_t addr[IOT_MAC_ADDR_LEN] = { 0 };
uint16_t ticket;
iot_time_tm_t tm = { 0 };
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
uint32_t device = sta_glb->drv->get_device_type();
if (sta_pib == NULL) {
return;
}
if (power_off_flag != sta_pib->power_off_flag) {
iot_pib_acquire_app_commit_ref(&ref);
iot_sg_printf("%s flg %lu -> %lu \n", __FUNCTION__,
sta_pib->power_off_flag, power_off_flag);
sta_pib->power_off_flag = power_off_flag;
if (power_off_flag) {
if (iot_sg_sta_rtc_get(&tm, 0) == ERR_OK) {
sta_pib->power_off_year = tm.tm_year;
sta_pib->power_off_mon = tm.tm_mon;
sta_pib->power_off_day = tm.tm_mday;
sta_pib->power_off_hour = tm.tm_hour;
sta_pib->power_off_min = tm.tm_min;
sta_pib->power_off_sec = tm.tm_sec;
sta_pib->power_off_time_flag = 1;
}
iot_sg_sta_ext_fj_power_up_down_record_handle(
IOT_SG_STA_POWER_REC_TYPE_DOWN);
} else {
sta_pib->power_off_year = 0;
sta_pib->power_off_mon = 0;
sta_pib->power_off_day = 0;
sta_pib->power_off_hour = 0;
sta_pib->power_off_min = 0;
sta_pib->power_off_sec = 0;
sta_pib->power_off_time_flag = 0;
}
switch (device) {
case IOT_SG_STA_DEV_TYPE_POWER_METER:
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T1:
{
if (power_off_flag) {
sta_glb->drv->get_device_addr(addr);
if (iot_mac_addr_valid(addr)
&& sta_pib->pa_type != IOT_SG_STA_PA_ADDR_TYPE_TSFM) {
sta_pib->pa_type = IOT_SG_STA_PA_ADDR_TYPE_PO;
iot_mac_addr_cpy(sta_pib->parent_addr, addr);
}
} else {
if (sta_pib->pa_type == IOT_SG_STA_PA_ADDR_TYPE_PO) {
sta_pib->pa_type = IOT_SG_STA_PA_ADDR_TYPE_INVALID;
os_mem_set(sta_pib->parent_addr, 0, IOT_MAC_ADDR_LEN);
}
}
break;
}
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T3:
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T2:
default:
break;
}
iot_pib_release_app_commit_ref(&ref);
iot_pib_app_commit(&ticket);
}
}
/* get station device information */
void iot_sg_sta_get_dev_info(iot_sg_sta_dev_info_t *dev_info)
{
dev_info->reset_cnt = p_sg_glb->plc_state.reset_cnt;
iot_mac_addr_cpy(dev_info->dev_id, p_sg_glb->plc_state.dev_id);
}
/* get station plc information */
void iot_sg_sta_get_plc_info(iot_sg_sta_plc_info_t *plc_info)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (p_sg_glb->plc_state.link_ready) {
iot_mac_addr_cpy(plc_info->cco_mac, p_sg_glb->plc_state.cco_addr);
plc_info->snr = p_sg_glb->plc_state.snr;
} else {
/* off net state */
os_mem_set(plc_info->cco_mac, 0, IOT_MAC_ADDR_LEN);
plc_info->snr = 0;
}
iot_mac_addr_cpy(plc_info->sta_mac, p_sg_glb->plc_state.addr);
plc_info->net_state = p_sg_glb->plc_state.link_ready;
plc_info->app_data_fwd_cnt = sta_glb->tsfm_status.app_data_fwd_cnt;
plc_info->join_cnt = sta_glb->mr.mr_info.join_cnt;
}
uint32_t iot_sg_sta_parse_frame(uint8_t *data, uint16_t len)
{
uint8_t cnt = 0;
uint32_t reason = 0, ret = ERR_OK;
uint8_t *addr = NULL;
uint16_t frame_len;
uint16_t fe_cnt;
proto_645_header_t *hdr;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
again:
hdr = proto_645_format_check(data, len, PROTO_645_DIR_MASTER);
if (!hdr) {
if (cnt) {
sta_glb->mr.frame_cnt = cnt;
goto out;
} else {
reason = 1;
ret = ERR_INVAL;
goto drop;
}
}
fe_cnt = (uint16_t)((uint8_t*)hdr - data);
/* the meter address in each 645 message must be the same */
if (addr) {
if (!iot_mac_addr_cmp(addr, hdr->addr)) {
reason = 2;
ret = ERR_INVAL;
goto drop;
}
} else {
addr = hdr->addr;
}
sta_glb->mr.frame_data[cnt] = (uint8_t *)hdr;
frame_len = sizeof(*hdr) + hdr->len + sizeof(proto_645_tailer_t);
data = sta_glb->mr.frame_data[cnt] + frame_len;
sta_glb->mr.frame_len[cnt] = frame_len;
cnt++;
/* the number of 645 messages must not exceed the limit */
if (cnt >= IOT_SG_STA_MAX_FRAME_PER_READ) {
sta_glb->mr.frame_cnt = IOT_SG_STA_MAX_FRAME_PER_READ;
goto out;
}
len = len - frame_len - fe_cnt;
if (len)
goto again;
sta_glb->mr.frame_cnt = cnt;
goto out;
drop:
sta_glb->mr.frame_cnt = 0;
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_INFO, IOT_SG_STA_CON_MR_PARSE,
1, reason);
out:
return ret;
}
uint32_t iot_sg_sta_issue_frame(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_mr_stats_t *mr_stats = &sta_glb->mr.mr_info;
iot_sg_sta_drv_t *drv = sta_glb->drv;
iot_pkt_t *drv_pkt;
uint32_t ret = 0, tmp, timeout;
uint8_t index, addr[IOT_MAC_ADDR_LEN], is_in_mlist = false;
uint8_t *data, link_type;
iot_plc_msdu_recv_t *msdu;
data = iot_pkt_data(sta_glb->req.pkt);
msdu = (iot_plc_msdu_recv_t*)(data - sizeof(*msdu));
again:
index = sta_glb->mr.frame_idx;
if (index >= sta_glb->mr.frame_cnt) {
ret = ERR_OK;
goto out;
}
tmp = sta_glb->mr.frame_len[index];
drv_pkt = iot_pkt_alloc(tmp + drv->headroom, IOT_SMART_GRID_MID);
if (drv_pkt == NULL) {
/* continue with the next frame */
iot_sg_printf("%s no mem idx %lu\n", __FUNCTION__, index);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_WARN,
IOT_SG_STA_MR_ERR_ISSUE_NMEM_ID, 1, index);
iot_counter_inc(mr_stats->mr_err_cnts[IOT_SG_STA_MR_ERR_ISSUE_NMEM]);
sta_glb->mr.frame_idx++;
goto again;
}
iot_pkt_reserve(drv_pkt, drv->headroom);
os_mem_cpy(iot_pkt_put(drv_pkt, tmp), sta_glb->mr.frame_data[index],
tmp);
link_type = sta_glb->req.link_type;
if (link_type != IOT_SG_LINK_TYPE_APP
&& link_type != IOT_SG_LINK_TYPE_CUS) {
if (proto_645_handle_vendor_proto(iot_pkt_data(drv_pkt),
iot_pkt_data_len(drv_pkt), msdu->snr, msdu->rssi)) {
iot_pkt_free(drv_pkt);
ret = ERR_OK;
goto complete;
}
if (proto_69845_handle_vendor_proto(iot_pkt_data(drv_pkt),
iot_pkt_data_len(drv_pkt), msdu->snr, msdu->rssi)) {
iot_pkt_free(drv_pkt);
ret = ERR_OK;
goto complete;
}
ret = iot_sg_sta_ext_module_handle((uint8_t)sta_glb->mr.data_type,
drv_pkt);
if (ret == ERR_OK) {
iot_pkt_free(drv_pkt);
goto complete;
}
if (iot_sg_sta_correct_time(drv_pkt) == ERR_OK) {
/* if drv_pkt contain correct time message,
* transfer drv_pkt to driver through drv->correct_time
* function.
*/
ret = drv->correct_time(drv_pkt, 0);
if (ret == ERR_OK) {
iot_counter_inc(mr_stats->drv_send_correct_cnt);
if (!p_sg_glb->plc_state.cert_test_detected) {
iot_sg_sta_start_get_time();
}
}
ret = ERR_INVAL;
goto complete;
}
}
if (iot_sg_sta_get_pm_addr_in_proto(drv_pkt, addr) == ERR_OK) {
if (iot_sg_sta_node_find_by_addr(addr)) {
is_in_mlist = true;
}
}
if (sta_glb->drv->get_device_type() == IOT_SG_STA_DEV_TYPE_COLLECTOR_T3 &&
sta_glb->req.is_conn_fwd && sta_glb->mr.mr_timeout < 10000) {
/* in the CT3 mode, if the command is a conn-less branch identification
* command, the conn-less PLC message will be used for forwarding,
* and the timeout time should be fix to no less than 10s
*/
timeout = 10000;
} else {
timeout = sta_glb->mr.mr_timeout;
}
ret = drv->meter_read((uint8_t)sta_glb->mr.data_type, drv_pkt,
timeout, (uint32_t)sta_glb->mr.mr_interval,
sta_glb->mr.mr_baud);
complete:
if (ret == ERR_OK || ret == ERR_PENDING) {
ret = ERR_PENDING;
if (is_in_mlist) {
iot_sg_sta_uart_check(IOT_SG_STA_UART_MODE_SEND);
}
} else {
if (ret == ERR_BUSY) {
iot_sg_printf("%s drv busy idx %lu\n", __FUNCTION__,
index);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_WARN,
IOT_SG_STA_MR_ERR_DRV_BUSY_ID, 1, index);
iot_counter_inc(mr_stats->mr_err_cnts[IOT_SG_STA_MR_ERR_DRV_BUSY]);
}
sta_glb->mr.frame_idx++;
goto again;
}
out:
/* clear special meter read baud rate configuration after each read */
if (sta_glb->mr.mr_baud) {
sta_glb->mr.mr_baud = 0;
}
return ret;
}
/* device detect time out function */
static void iot_sg_sta_detect_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_DETECT;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
/* driver requested timer time out function */
static void iot_sg_sta_driver_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_STA_DRIVER;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
/* event report timer time out function */
static void iot_sg_sta_event_rpt_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_EVENT_RPT;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
/* read tsfm info time out function */
static void iot_sg_sta_read_tsfm_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_READ_TSFM;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
static void iot_sg_sta_scan_band_bitmap_init(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint8_t user_type = iot_sg_sta_get_user_type();
uint8_t fb_bitmap[IOT_PLC_BAND_BITMAP_SIZE] = { 0 };
/* default bitmap 0~3
* assign to mac band in customer range:
* PLC_LIB_FREQ_BAND_0 = 0, //2M to 12M
* PLC_LIB_FREQ_BAND_1 = 1, //2.4M to 5.6M
* PLC_LIB_FREQ_BAND_2 = 2, //700K to 3M
* PLC_LIB_FREQ_BAND_3 = 3, //1.7M to 3M
* PLC_LIB_FREQ_BAND_4 = 4, //5.6M to 12M
* PLC_LIB_FREQ_BAND_8 = 8, //5.8M to 9M
* PLC_LIB_FREQ_BAND_9 = 9, //4.9M to 24.4M
* PLC_LIB_FREQ_BAND_10 = 10,//28.3M to 34.5M
* PLC_LIB_FREQ_BAND_11 = 11,//4.9M to 12.2M
*/
if (user_type == USER_TYPE_BRM_PEIWANG) {
/* disable band 0 and band 3 support for efficiency */
fb_bitmap[PLC_LIB_FREQ_BAND_1 / 8] |= 1 << (PLC_LIB_FREQ_BAND_1 % 8);
fb_bitmap[PLC_LIB_FREQ_BAND_2 / 8] |= 1 << (PLC_LIB_FREQ_BAND_2 % 8);
fb_bitmap[PLC_LIB_FREQ_BAND_8 / 8] |= 1 << (PLC_LIB_FREQ_BAND_8 % 8);
} else {
fb_bitmap[PLC_LIB_FREQ_BAND_0 / 8] |= 1 << (PLC_LIB_FREQ_BAND_0 % 8);
fb_bitmap[PLC_LIB_FREQ_BAND_1 / 8] |= 1 << (PLC_LIB_FREQ_BAND_1 % 8);
fb_bitmap[PLC_LIB_FREQ_BAND_2 / 8] |= 1 << (PLC_LIB_FREQ_BAND_2 % 8);
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW ||
user_type == USER_TYPE_SOUTHEN_POWER_GRID_GUANGZHOU) {
fb_bitmap[PLC_LIB_FREQ_BAND_3 / 8] |= 1 << (PLC_LIB_FREQ_BAND_3 % 8);
}
if (iot_board_get_user_passcode()) {
fb_bitmap[PLC_LIB_FREQ_BAND_8 / 8] |= 1 << (PLC_LIB_FREQ_BAND_8 % 8);
}
}
iot_plc_set_scan_band_bitmap(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, fb_bitmap, IOT_PLC_BAND_BITMAP_SIZE);
}
/* collection tsfm feature time out function */
static void iot_sg_sta_tsfm_collection_func(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_TIMER;
msg->task_msg.id = IOT_SG_MSG_ID_TIMER_CF_TIMEOUT;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
/* trigger device detect */
static uint32_t iot_sg_sta_trigger_detect()
{
uint8_t i;
uint32_t ret = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->drv) {
/* if driver already appointed, just use the appointed driver for
* detect.
*/
ret = sta_glb->drv->init();
if (ret == ERR_OK) {
ret = sta_glb->drv->start_detect();
iot_sg_printf("%s start drv id %lu\n", __FUNCTION__,
sta_glb->drv->drv_id);
if (ret) {
sta_glb->drv->deinit();
}
} else {
IOT_ASSERT(0);
}
goto out;
}
/* start device detecting */
for (i = 0; i < IOT_SG_STA_DRV_TABLE_SIZE; i++) {
if (g_sta_drv_table[sta_glb->detect_idx]
&& (g_sta_drv_table[sta_glb->detect_idx]->drv_load_mode
== IOT_SG_STA_DRV_LOAD_MODE_DYNAMIC)) {
ret = g_sta_drv_table[sta_glb->detect_idx]->init();
if (ret == ERR_OK) {
ret = g_sta_drv_table[sta_glb->detect_idx]->start_detect();
iot_sg_printf("%s start drv id %lu\n", __FUNCTION__,
g_sta_drv_table[sta_glb->detect_idx]->drv_id);
if (ret == 0) {
break;
} else {
g_sta_drv_table[sta_glb->detect_idx]->deinit();
}
} else {
IOT_ASSERT(0);
}
}
sta_glb->detect_idx++;
if (sta_glb->detect_idx >= IOT_SG_STA_DRV_TABLE_SIZE) {
sta_glb->detect_round++;
sta_glb->detect_idx = 0;
}
}
if (i >= IOT_SG_STA_DRV_TABLE_SIZE) {
ret = ERR_NOSUPP;
} else {
os_start_timer(sta_glb->detect_timer,
g_sta_drv_table[sta_glb->detect_idx]->detect_time);
}
out:
return ret;
}
/* check device detect status */
static uint32_t iot_sg_sta_check_detect()
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->drv) {
ret = sta_glb->drv->stop_detect();
if (ret) {
sta_glb->detect_round++;
sta_glb->drv->deinit();
}
} else {
ret = g_sta_drv_table[sta_glb->detect_idx]->stop_detect();
iot_sg_printf("%s stop drv id %lu ret %lu\n", __FUNCTION__,
g_sta_drv_table[sta_glb->detect_idx]->drv_id, ret);
if (ret) {
g_sta_drv_table[sta_glb->detect_idx]->deinit();
if (ret == ERR_PENDING && !sta_glb->drv) {
sta_glb->drv = g_sta_drv_table[sta_glb->detect_idx];
sta_glb->detect_round++;
} else {
sta_glb->detect_idx++;
if (sta_glb->detect_idx >= IOT_SG_STA_DRV_TABLE_SIZE) {
sta_glb->detect_idx = 0;
sta_glb->detect_round++;
}
}
}
}
return ret;
}
void iot_sg_sta_bitmap_merge(uint8_t *bm, uint16_t first_tei,
uint16_t length, iot_sg_sta_power_off_bm_t *local_bm)
{
uint16_t tei, i;
uint16_t node_max = (length << 3);
for (i = 0; i < node_max; i++) {
tei = first_tei + i;
if (!GW_APP_EVENT_TEI_IS_VALID(tei))
break;
if (iot_bitmap_is_set(bm, (uint8_t)length, (i + 1))) {
if (!iot_bitmap_is_set(local_bm->map, sizeof(local_bm->map),
GW_APP_TEI_TO_BM(tei))) {
local_bm->updated = 1;
iot_bitmap_set(local_bm->map, sizeof(local_bm->map),
GW_APP_TEI_TO_BM(tei));
}
}
}
}
uint32_t iot_sg_sta_pd_addrs_merge(
iot_sg_sta_pd_addrs_info_t *pm, uint16_t cnt)
{
uint16_t pm_cnt, size;
uint8_t i, j, idx;
uint32_t update = 0;
iot_sg_sta_pd_addrs_info_t *pm_t;
iot_sg_sta_pd_addrs_ctrl_t *pd_addr_ctrl =
&p_sg_glb->desc.sta->evt.pd_addr_ctrl;
iot_sg_sta_pd_addrs_buf_t *addrs_buf = pd_addr_ctrl->addrs_buf;
pm_cnt = cnt;
/* compare with the collected power down info, remove duplicate. */
for (j = 0; j < cnt; j++) {
for (idx = 0; idx < IOT_SG_STA_PD_ADDRS_BUF_CNT; idx++) {
if (addrs_buf[idx].pkt == NULL) {
break;
}
pm_t = (iot_sg_sta_pd_addrs_info_t *)iot_pkt_data( \
addrs_buf[idx].pkt);
for (i = 0; i < addrs_buf[idx].pm_cnt; i++) {
if (iot_mac_addr_cmp(pm_t[i].mac, pm[j].mac)) {
os_mem_set(&pm[j], 0x0, sizeof(*pm));
pm_cnt--;
break;
}
}
}
}
if (!pm_cnt) {
/* if all the addr are repeated, they are ignored */
goto out;
}
for (idx = 0, j = 0; j < cnt;) {
if (!iot_mac_addr_valid(pm[j].mac)) {
j++;
continue;
}
if (addrs_buf[idx].pkt == NULL) {
addrs_buf[idx].pkt = iot_pkt_alloc(IOT_SG_STA_PD_ADDRS_BUF_SIZE,
IOT_SMART_GRID_MID);
if (addrs_buf[idx].pkt == NULL) {
iot_sg_printf("%s no pkt idx %lu\n", __FUNCTION__, idx);
goto out;
}
addrs_buf[idx].pm_cnt = 0;
} else {
size = (uint16_t)iot_pkt_data_len(addrs_buf[idx].pkt);
if ((size + sizeof(*pm)) > IOT_SG_STA_PD_ADDRS_BUF_SIZE) {
/* the current iot_pkt cache info is full */
idx++;
if (idx >= IOT_SG_STA_PD_ADDRS_BUF_CNT) {
iot_sg_printf("%s buf full\n", __FUNCTION__);
goto out;
}
continue;
}
}
pm_t = (iot_sg_sta_pd_addrs_info_t *)iot_pkt_tail(addrs_buf[idx].pkt);
iot_mac_addr_cpy(pm_t->mac, pm[j].mac);
pm_t->power_state = pm[j].power_state;
iot_pkt_put(addrs_buf[idx].pkt, sizeof(*pm));
addrs_buf[idx].pm_cnt++;
addrs_buf[idx].updated = 1;
pm_cnt--;
update = 1;
j++;
iot_sg_printf("%s addr %02x%02x%02x%02x%02x%02x state %lu idx %lu "
"cnt %lu\n", __FUNCTION__, pm_t->mac[5], pm_t->mac[4], pm_t->mac[3],
pm_t->mac[2], pm_t->mac[1], pm_t->mac[0], pm_t->power_state, idx,
addrs_buf[idx].pm_cnt);
}
out:
return update;
}
uint8_t iot_sg_sta_node_valid_check(iot_sg_sta_node_desc_t *node)
{
return (node && !node->obsolete);
}
uint8_t iot_sg_node_reg_get_node_cnt(void)
{
uint8_t idx, cnt = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
node = sta_glb->node_list[idx];
if (iot_sg_sta_node_valid_check(node)) {
cnt++;
}
}
return cnt;
}
void iot_sg_sta_node_reg_clear_all_obsolete(void)
{
uint8_t idx;
uint8_t *addr;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
/* clear all obsolete meters */
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx] != NULL) {
if (sta_glb->node_list[idx]->obsolete) {
addr = sta_glb->node_list[idx]->entry.addr;
iot_sg_sta_flash_meter_delete(addr);
iot_sg_sta_ext_meter_delete(sta_glb->node_list[idx]);
iot_addr_hash_table_remove(sta_glb->node_table,
&sta_glb->node_list[idx]->entry);
iot_addr_hash_table_free(sta_glb->node_table,
&sta_glb->node_list[idx]->entry);
sta_glb->node_list[idx] = NULL;
iot_sg_sta_set_addr_list_state(1);
}
}
}
}
static uint32_t iot_sg_sta_parse_mr_frame(uint8_t *hdr)
{
uint32_t ret = ERR_OK;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_parse_mr_frame(hdr);
} else {
ret = iot_sg_sta_nw_parse_mr_frame(hdr);
}
return ret;
}
static void iot_sg_sta_mr_counter_inc(uint8_t *hdr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
iot_sg_sta_gw_mr_counter_inc(hdr);
} else {
iot_sg_sta_nw_mr_counter_inc(hdr);
}
}
uint32_t iot_sg_sta_meter_read(iot_pkt_t *pkt, uint8_t *hdr)
{
uint32_t ret = ERR_OK, reason;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
/* clean up obsolete meter read status */
sta_glb->mr.read_ack = 0;
sta_glb->mr.retry_cnt = 0;
sta_glb->mr.frame_idx = 0;
sta_glb->mr.frame_cnt = 0;
sta_glb->mr.mr_baud = 0;
if (sta_glb->mr.read_rsp) {
IOT_ASSERT(0);
}
if (iot_sg_sta_parse_mr_frame(hdr)) {
reason = 1;
ret = ERR_INVAL;
goto drop;
}
/* trigger the first pending frame */
ret = iot_sg_sta_issue_frame();
if (ret == ERR_PENDING) {
sta_glb->mr.meter_read_on = 1;
iot_sg_sta_mr_counter_inc(hdr);
iot_sg_sta_pinsta_high();
} else if (ret) {
reason = 2;
goto drop;
}
goto out;
drop:
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_WARN,
IOT_SG_STA_HADNLE_METER_R_ID, 1, reason);
out:
if (sta_glb->mr.meter_read_on == 0) {
/* for pending case, the pkt will be freed in
* iot_sg_sta_meter_read_done_intern function.
*/
iot_pkt_free(pkt);
}
return ret;
}
static void iot_sg_sta_meter_read_done_intern(uint8_t data_type,
uint8_t done_src, iot_pkt_t *rsp_pkt)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint8_t link_type;
link_type = sta_glb->req.link_type;
if (rsp_pkt) {
iot_sg_sta_uart_check(IOT_SG_STA_UART_MODE_REC);
}
switch (link_type) {
case IOT_SG_LINK_TYPE_PLC_CONN_LESS:
case IOT_SG_LINK_TYPE_PLC_BRM:
case IOT_SG_LINK_TYPE_APP:
case IOT_SG_LINK_TYPE_CUS:
{
iot_sg_sta_conn_less_mr_done(data_type, done_src, rsp_pkt);
break;
}
case IOT_SG_LINK_TYPE_PLC:
case IOT_SG_LINK_TYPE_SWC:
case IOT_SG_LINK_TYPE_PLC_CTRL:
default:
{
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
iot_sg_sta_gw_mr_done_intern(data_type, done_src, rsp_pkt);
} else {
iot_sg_sta_nw_mr_done_intern(data_type, rsp_pkt);
}
iot_sg_sta_pinsta_high();
break;
}
}
}
/* send pending meter read response back to cco */
void iot_sg_sta_send_mr_rsp(uint16_t seq, uint8_t mr_type)
{
uint8_t *data;
uint16_t len;
iot_pkt_t *plc_pkt;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
IOT_ASSERT(sta_glb->mr.app_hdr && sta_glb->mr.read_rsp);
/* save the last meter reading information */
data = sta_glb->mr.app_hdr;
plc_pkt = sta_glb->mr.read_rsp;
len = (uint16_t)(iot_pkt_tail(plc_pkt) - data);
if (len <= IOT_SG_STA_LAST_RESPONSE_MAX_SIZE) {
if (sta_glb->mr.last_mr_data_pkt) {
iot_pkt_free(sta_glb->mr.last_mr_data_pkt);
sta_glb->mr.last_mr_data_pkt = NULL;
}
sta_glb->mr.last_mr_data_pkt = iot_pkt_alloc(len, IOT_SMART_GRID_MID);
if (sta_glb->mr.last_mr_data_pkt) {
sta_glb->mr.last_mr_seq = seq;
if (sta_glb->req.link_type == IOT_SG_LINK_TYPE_PLC_CTRL) {
sta_glb->mr.last_mr_valid = 0;
sta_glb->mr.last_crtl_mr_valid = 1;
} else {
sta_glb->mr.last_mr_valid = 1;
sta_glb->mr.last_mr_type = mr_type;
sta_glb->mr.last_crtl_mr_valid = 0;
}
sta_glb->mr.last_conn_less_mr_valid = 0;
sta_glb->mr.last_mr_ts = os_boot_time64();
os_mem_cpy(iot_pkt_put(sta_glb->mr.last_mr_data_pkt, len), data,
len);
}
}
iot_sg_send_msdu(plc_pkt, sta_glb->req.link_type);
sta_glb->mr.read_rsp = NULL;
sta_glb->mr.app_hdr = NULL;
}
void iot_sg_sta_start_get_time()
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->drv) {
sta_glb->drv->get_time();
}
}
void iot_sg_sta_drv_start_get_time()
{
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_DRV;
msg->task_msg.id = IOT_SG_MSG_ID_DRV_START_GET_TIME;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
void iot_sg_sta_cco_bl_invalid_time_set(uint32_t time)
{
p_sg_glb->desc.sta->cco_bl_invalid_time = time;
}
/**
* @brief iot_sg_sta_power_off_check() - check whether sta is power off or
* not.
* @retval: 1 -- sta is power off.
* @retval: 0 -- sta isn't power off.
*/
uint8_t iot_sg_sta_power_off_check(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->evt.power_off_rpt_status == IOT_SG_STA_POWEROFF_REPORT)
return 1;
else
return 0;
}
static void iot_sg_sta_power_on_report_stop(void);
static void iot_sg_sta_sm_done_evt_start(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_printf("%s ok\n", __FUNCTION__);
os_start_timer(sta_glb->sm_evt_chk_timer,
IOT_SG_STA_SM_DONE_EVT_RPT_DUR_MIN);
}
void iot_sg_sta_power_on_check_done(void)
{
uint8_t cnt = 0;
uint32_t idx;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if ((sta_glb->drv->get_device_type() != IOT_SG_STA_DEV_TYPE_COLLECTOR_T2
&& sta_glb->drv->get_device_type() != IOT_SG_STA_DEV_TYPE_COLLECTOR_T3)
|| iot_sg_sta_power_off_check()) {
return;
}
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_ZHEJIANG) {
sta_glb->evt.sm_done = 1;
iot_sg_sta_sm_done_evt_start();
}
if (!sta_pib->power_off_flag)
return;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx]) {
cnt++;
}
}
sta_glb->evt.pu_addr_ctrl.check_cnt = cnt;
sta_glb->evt.pu_addr_ctrl.complete = 1;
return;
}
static void iot_sg_sta_power_on_info_clear(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
sta_glb->evt.pu_addr_ctrl.complete = 0;
sta_glb->evt.pu_addr_ctrl.check_cnt = 0;
iot_sg_sta_node_reg_clear_all_obsolete();
}
static uint32_t iot_sg_sta_power_on_get_time(void)
{
uint32_t timeout = 0, timeout1, timeout2, timeout_max;
uint32_t boot_time = os_boot_time32();
iot_time_tm_t curr_tm = { 0 }, last_tm = {0};
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_FUJIAN) {
timeout_max = IOT_SG_STA_POWERON_RPT_MAX_DELAY_FJ;
} else {
timeout_max = IOT_SG_STA_POWERON_RPT_MAX_DELAY;
}
if (!sta_pib->power_off_time_flag || iot_sg_sta_rtc_get(&curr_tm, 0)) {
goto max;
}
last_tm.tm_year = sta_pib->power_off_year;
last_tm.tm_mon = sta_pib->power_off_mon;
last_tm.tm_mday = sta_pib->power_off_day;
last_tm.tm_hour = sta_pib->power_off_hour;
last_tm.tm_min = sta_pib->power_off_min;
last_tm.tm_sec = sta_pib->power_off_sec;
timeout1 = (uint32_t)iot_rtc_delta_calc(&last_tm, &curr_tm);
timeout2 = (timeout_max / 1000);
if (timeout1 < timeout2) {
timeout = (timeout2 - timeout1) * 1000;
} else {
timeout = IOT_SG_STA_POWERON_RPT_MIN_DELAY;
}
goto out;
max:
if (boot_time > timeout_max) {
timeout = IOT_SG_STA_POWERON_RPT_MIN_DELAY;
} else {
timeout = timeout_max - boot_time;
}
out:
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_HENAN) {
if (boot_time + timeout < IOT_SG_STA_POWERON_RPT_DELAY_HENAN) {
timeout = IOT_SG_STA_POWERON_RPT_DELAY_HENAN - timeout;
}
}
return timeout;
}
static uint32_t iot_sg_sta_power_on_valid_check(uint8_t *pm_changed)
{
uint8_t addr[IOT_MAC_ADDR_LEN] = { 0 };
uint32_t ret = ERR_FAIL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
uint32_t device = sta_glb->drv->get_device_type();
if (sta_glb->drv->drv_id == IOT_SG_STA_DRV_ID_HX_DLMS_PM) {
goto out;
}
if (sta_pib && sta_pib->power_off_flag
&& !p_sg_glb->plc_state.cert_test_detected) {
switch (device) {
case IOT_SG_STA_DEV_TYPE_POWER_METER:
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T1:
{
sta_glb->drv->get_device_addr(addr);
if (iot_mac_addr_valid(addr) &&
sta_pib->pa_type == IOT_SG_STA_PA_ADDR_TYPE_PO) {
if (!iot_mac_addr_cmp(sta_pib->parent_addr, addr)) {
if (pm_changed) {
*pm_changed = 1;
}
goto out;
}
}
break;
}
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T3:
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T2:
default:
break;
}
ret = ERR_OK;
}
out:
return ret;
}
static uint32_t iot_sg_sta_power_on_report_start(void)
{
uint32_t ret = ERR_FAIL, timeout;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint8_t pm_changed = 0;
if (iot_sg_sta_power_on_valid_check(&pm_changed) == ERR_OK) {
/* if cert test command ever undetected and sta ever powered off,
* sta start power on event report.
*/
sta_glb->evt.power_on_reporting = 1;
if (sta_glb->get_time_done) {
timeout = iot_sg_sta_power_on_get_time();
os_start_timer(sta_glb->power_on_timer, timeout);
iot_sg_printf("%s\n", __FUNCTION__);
} else {
/* if sta hasn't gotten the meter time, power on event report
* is pending.
*/
sta_glb->evt.power_on_rpt_pending = 1;
iot_sg_printf("%s delay\n", __FUNCTION__);
}
ret = ERR_OK;
} else {
if (pm_changed) {
iot_sg_sta_ext_fj_power_up_down_record_handle(
IOT_SG_STA_POWER_REC_TYPE_CLEAR);
}
iot_sg_sta_change_power_off_info_pib(0);
iot_sg_sta_power_on_info_clear();
}
return ret;
}
static void iot_sg_sta_power_on_report_stop(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
sta_glb->evt.power_on_rpt_seq = 0;
sta_glb->evt.power_on_rpt_cnt = 0;
sta_glb->evt.power_on_rpt_pending = 0;
sta_glb->evt.power_on_reporting = 0;
os_stop_timer(sta_glb->power_on_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_POWER_ON);
iot_sg_sta_power_on_info_clear();
iot_sg_printf("%s\n", __FUNCTION__);
}
void iot_sg_sta_power_on_ack_handle(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint8_t rpt_max_cnt;
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_FUJIAN) {
rpt_max_cnt = IOT_SG_STA_POWERON_RPT_CNT_MAX_FJ;
} else if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_HENAN) {
rpt_max_cnt = IOT_SG_STA_POWERON_RPT_CNT_MAX_HENAN;
} else {
rpt_max_cnt = IOT_SG_STA_POWERON_RPT_CNT_MAX;
}
if (sta_glb->evt.power_on_rpt_cnt < rpt_max_cnt) {
/* if sta receives power on event report ack from cco,
* it considers that the times of sending power on event is
* the max.
*/
sta_glb->evt.power_on_rpt_cnt = rpt_max_cnt;
}
}
static uint32_t iot_sg_sta_power_off_rpt_info_check()
{
uint8_t bm_update = 0, i;
uint32_t ret = ERR_OK;
iot_sg_sta_pd_bitmap_desc_t bitmap_info = {0};
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_pd_addrs_ctrl_t *pd_addr_ctrl = &sta_glb->evt.pd_addr_ctrl;
iot_sg_sta_pd_addrs_buf_t *addrs_buf = pd_addr_ctrl->addrs_buf;
if (iot_sg_sta_get_pd_bitmap_info(&bitmap_info, &bm_update) == ERR_OK) {
goto out;
}
for (i = 0; i < IOT_SG_STA_PD_ADDRS_BUF_CNT; i++) {
if (addrs_buf[i].pkt) {
goto out;
}
}
ret = ERR_NOT_EXIST;
out:
return ret;
}
void iot_sg_sta_power_off_fwd_ack_handle(uint16_t seq)
{
uint8_t bm_update = 0, i, j, rpt_info_check = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
iot_sg_sta_pd_bitmap_desc_t bitmap_info = {0};
iot_sg_sta_pd_addrs_ctrl_t *pd_addr_ctrl = &sta_glb->evt.pd_addr_ctrl;
iot_sg_sta_pd_addrs_buf_t *addrs_buf = pd_addr_ctrl->addrs_buf;
/* not handle power off node */
if (iot_sg_sta_power_off_check()) {
return;
}
if (sta_glb->evt.power_off_rpt_seq == seq) {
/* bitmap not updated, and receive ack from cco, stop bitmap forward */
iot_sg_sta_get_pd_bitmap_info(&bitmap_info, &bm_update);
if (!bm_update) {
rpt_info_check = 1;
/* clean bitmap infomation */
os_mem_set(&evt->power_off_bm, 0x00, sizeof(evt->power_off_bm));
}
} else {
for (i = 0; i < IOT_SG_STA_PD_ADDRS_BUF_CNT; i++) {
if (addrs_buf[i].pkt == NULL)
break;
/* addr not updated, and receive ack from cco, stop addr forward */
if (addrs_buf[i].seq == seq && !addrs_buf[i].updated) {
rpt_info_check = 1;
iot_pkt_free(addrs_buf[i].pkt);
os_mem_set(&addrs_buf[i], 0x00, sizeof(addrs_buf[i]));
for (j = i; j < IOT_SG_STA_PD_ADDRS_BUF_CNT - 1; j++) {
if (addrs_buf[j + 1].pkt == NULL)
break;
os_mem_cpy(&addrs_buf[j], &addrs_buf[j + 1],
sizeof(addrs_buf[j]));
os_mem_set(&addrs_buf[j + 1], 0x00,
sizeof(addrs_buf[j + 1]));
}
break;
}
}
}
if (rpt_info_check &&
iot_sg_sta_power_off_rpt_info_check() == ERR_NOT_EXIST) {
os_stop_timer(sta_glb->power_off_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_POWER_OFF);
/* power off report finish skip to iot_sg_sta_pd_evt_fwd_handle */
iot_sg_sta_power_off_func(sta_glb->power_off_timer, NULL);
}
}
static void iot_sg_sta_power_on_report_handle(void)
{
uint8_t rpt_max_cnt, flag_bcast = 0, user_type = iot_sg_sta_get_user_type();
uint32_t dur, device, ret = ERR_OK, complete = 0;
iot_sg_plc_state_t *plc_info = iot_sg_get_plc_state_info();
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_power_on_addrmap_desc_t *pu_ctrl =
&sta_glb->evt.pu_addr_ctrl;
device = sta_glb->drv->get_device_type();
if (user_type == USER_TYPE_STATE_GRID_FUJIAN) {
rpt_max_cnt = IOT_SG_STA_POWERON_RPT_CNT_MAX_FJ;
} else if (user_type == USER_TYPE_STATE_GRID_HENAN) {
rpt_max_cnt = IOT_SG_STA_POWERON_RPT_CNT_MAX_HENAN;
} else {
rpt_max_cnt = IOT_SG_STA_POWERON_RPT_CNT_MAX;
}
if (sta_glb->evt.power_on_rpt_cnt >= rpt_max_cnt) {
complete = 1;
goto out;
}
if (!GW_APP_EVENT_TEI_IS_VALID(plc_info->dev_tei)) {
dur = IOT_SG_STA_POWERON_RPT_DUR_MIN;
goto drop;
}
if ((device == IOT_SG_STA_DEV_TYPE_COLLECTOR_T2 ||
device == IOT_SG_STA_DEV_TYPE_COLLECTOR_T3)
&& !pu_ctrl->complete) {
dur = IOT_SG_STA_POWERON_RPT_DUR_MIN;
goto drop;
}
if (sta_glb->evt.power_on_rpt_cnt >= (rpt_max_cnt - 1)) {
flag_bcast = 1;
}
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_power_on_evt_send(flag_bcast);
} else {
ret = iot_sg_sta_nw_power_on_evt_send(flag_bcast);
}
if (ret == ERR_NOMEM) {
dur = IOT_SG_STA_POWERON_RPT_DUR_MIN;
goto drop;
} else if (ret) {
complete = 1;
iot_sg_printf("%s err %lu\n", __FUNCTION__, ret);
goto out;
}
/* clear power_off_flag */
iot_sg_sta_change_power_off_info_pib(0);
sta_glb->evt.power_on_rpt_cnt++;
if (user_type == USER_TYPE_STATE_GRID_HENAN) {
dur = os_rand() % IOT_SG_STA_POWERON_RPT_RANDOM_HENAN +
IOT_SG_STA_POWERON_RPT_DUR_HENAN;
} else {
dur = os_rand() % (IOT_SG_STA_POWERON_RPT_DUR_MAX - \
IOT_SG_STA_POWERON_RPT_DUR_MIN) + IOT_SG_STA_POWERON_RPT_DUR_MIN;
}
drop:
os_start_timer(sta_glb->power_on_timer, dur);
out:
if (complete) {
iot_sg_sta_power_on_info_clear();
sta_glb->evt.power_on_reporting = 0;
/* meter event report is enabled after
* power on event report is completed.
*/
sta_glb->evt.event_rpt_on = 1;
sta_glb->drv->enable_event_rpt();
if (user_type == USER_TYPE_STATE_GRID_HLJ) {
iot_sg_sta_start_get_time();
}
}
return;
}
void iot_sg_sta_sm_done_evt_stop(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_SM_DONE_CHK);
os_stop_timer(sta_glb->sm_evt_chk_timer);
sta_glb->evt.sm_done_rpt_cnt = 0;
sta_glb->evt.sm_done_evt_rpt_seq = 0;
}
uint8_t iot_sg_sta_sm_done_evt_check_seq(uint16_t seq)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->evt.sm_done_evt_rpt_seq == seq)
return 1;
return 0;
}
void iot_sg_sta_all_aa_sm_done(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
sta_glb->evt.aa_sm_done = 1;
}
void iot_sg_sta_sm_evt_rpt_done(void)
{
uint8_t idx;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
node = sta_glb->node_list[idx];
if (iot_sg_sta_node_valid_check(node) &&
node->sm_rpt_state == IOT_SG_STA_SM_EVT_REPORTING) {
node->sm_rpt_state = IOT_SG_STA_SM_EVT_REPORT_DONE;
}
}
}
static void iot_sg_node_reg_get_sm_rpt_node_clear(void)
{
uint8_t idx;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
node = sta_glb->node_list[idx];
if (iot_sg_sta_node_valid_check(node) &&
(node->sm_rpt_state == IOT_SG_STA_SM_EVT_REPORT_DONE ||
node->sm_rpt_state == IOT_SG_STA_SM_EVT_REPORTING)) {
node->sm_rpt_state = IOT_SG_STA_SM_EVT_REPORT_IDLE;
}
}
}
static uint8_t iot_sg_node_reg_get_sm_rpt_node_cnt(void)
{
uint8_t idx, cnt = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
node = sta_glb->node_list[idx];
if (iot_sg_sta_node_valid_check(node) &&
node->sm_rpt_state != IOT_SG_STA_SM_EVT_REPORT_DONE) {
cnt++;
}
}
return cnt;
}
static void iot_sg_sta_sm_done_report_handle(void)
{
uint8_t pm_rpt_cnt;
uint32_t dur, ret = ERR_OK, complete = 0;
iot_sg_plc_state_t *plc_info = iot_sg_get_plc_state_info();
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->evt.sm_done_rpt_cnt >=
IOT_SG_STA_SM_DONE_EVT_RPT_CNT_MAX) {
complete = 1;
goto out;
}
if (!GW_APP_EVENT_TEI_IS_VALID(plc_info->dev_tei)) {
/* wait for the device to joined the network, and then report */
dur = IOT_SG_STA_SM_DONE_EVT_RPT_DUR_MIN;
goto drop;
}
if (sta_glb->mr.mr_info.join_cnt == 1) {
if (!sta_glb->evt.sm_done && !sta_glb->evt.aa_sm_done) {
complete = 1;
goto out;
}
} else {
iot_sg_node_reg_get_sm_rpt_node_clear();
}
pm_rpt_cnt = iot_sg_node_reg_get_sm_rpt_node_cnt();
if (!pm_rpt_cnt) {
complete = 1;
goto out;
}
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_sm_done_evt_send(pm_rpt_cnt);
} else {
IOT_ASSERT(0);
}
if (ret) {
dur = IOT_SG_STA_SM_DONE_EVT_RPT_DUR_MIN;
goto drop;
}
sta_glb->evt.sm_done_rpt_cnt++;
dur = os_rand() % (IOT_SG_STA_SM_DONE_EVT_RPT_DUR_MAX -
IOT_SG_STA_SM_DONE_EVT_RPT_DUR_MIN) +
IOT_SG_STA_SM_DONE_EVT_RPT_DUR_MIN;
drop:
os_start_timer(sta_glb->sm_evt_chk_timer, dur);
out:
if (complete) {
iot_sg_sta_sm_done_evt_stop();
}
return;
}
static void iot_sg_sta_sm_done_evt_start_check(uint16_t join_cnt)
{
uint32_t device, need_rpt= 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
device = sta_glb->drv->get_device_type();
switch (device) {
case IOT_SG_STA_DEV_TYPE_POWER_METER:
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T2:
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_ZHEJIANG) {
if ((join_cnt != 1) && (sta_glb->evt.sm_done_rpt_cnt
|| sta_glb->node_reg.node_reg_on)) {
/* if sm done evt report is ongoing or sm is ongoing,
* stop report sm done evt.
*/
break;
}
need_rpt = 1;
}
default:
break;
}
if (need_rpt) {
iot_sg_sta_sm_done_evt_start();
}
}
static void iot_sg_sta_tm_init(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
sta_glb->sta_time_cnt = 0;
sta_glb->correct_time_cnt = 0;
sta_glb->pm_tm_tried = 0;
iot_sg_sta_rtc_clear(1);
}
static void iot_sg_sta_ct_rec_save(iot_sg_sta_drv_time_t *time)
{
iot_sg_sta_flash_fj_ct_rec_t ct_rec;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_FUJIAN &&
sta_glb->tm_soc == PROTO_645_FJ_MOD_TM_SOC_PM) {
ct_rec.ntb_delta = 0;
ct_rec.second = time->second;
ct_rec.minute = time->mintue;
ct_rec.hour = time->hour;
ct_rec.day = time->day;
ct_rec.month = time->month;
ct_rec.year = time->year;
iot_sg_sta_flash_fj_ct_rec_save(&ct_rec);
}
}
static iot_sg_sta_drv_time_t *iot_sg_sta_get_time_valid_check(
iot_sg_sta_drv_time_t *time)
{
iot_sg_sta_drv_time_t *tm = NULL;
if (time) {
if (time->year > 99) {
goto out;
}
if (!time->month || !time->day) {
goto out;
}
if (time->month == 1 || time->month == 3 || time->month == 5
|| time->month == 7 || time->month == 8 || time->month == 10
|| time->month == 12) {
if (time->day > 31) {
goto out;
}
} else if (time->month == 4 || time->month == 6 || time->month == 9
|| time->month == 11) {
if (time->day > 30) {
goto out;
}
} else if (time->month == 2) {
if (time->year % 4 == 0) {
if (time->day > 29) {
goto out;
}
} else {
if (time->day > 28) {
goto out;
}
}
} else {
goto out;
}
if (time->hour > 23) {
goto out;
}
if (time->mintue > 59) {
goto out;
}
if (time->second > 59) {
goto out;
}
tm = time;
}
out:
return tm;
}
void iot_sg_sta_get_time_done(iot_sg_sta_drv_time_t *time)
{
iot_time_tm_t tm = { 0 };
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
time = iot_sg_sta_get_time_valid_check(time);
sta_glb->get_time_done = 1;
if (time) {
iot_sg_printf("%s cur time %02d-%02d-%02d %02d:%02d:%02d\n",
__FUNCTION__, time->year, time->month, time->day, time->hour,
time->mintue, time->second);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_INFO_LVL_2,
IOT_SG_STA_DRV_PM_TIME_ID, 6, time->year, time->month,
time->day, time->hour, time->mintue, time->second);
tm.tm_year = time->year + 2000;
tm.tm_mon = time->month;
tm.tm_mday = time->day;
tm.tm_hour = time->hour;
tm.tm_min = time->mintue;
tm.tm_sec = time->second;
iot_sg_sta_rtc_set(&tm, 0);
iot_sg_sta_rtc_recover_from_pib(&tm);
iot_sg_sta_rtc_delta_save_to_pib(&tm);
iot_sg_sta_ct_rec_save(time);
iot_sg_sta_ext_auto_tm_handle(&tm);
iot_sg_sta_ext_fj_power_up_down_record_handle(
IOT_SG_STA_POWER_REC_TYPE_UP);
iot_sg_sta_ext_ai_ll_recover(&tm);
}
if (sta_glb->evt.power_on_rpt_pending) {
sta_glb->evt.power_on_rpt_pending = 0;
iot_sg_sta_power_on_report_start();
}
}
static void iot_sg_sta_power_off_rpt_start(void)
{
uint8_t user_type = iot_sg_sta_get_user_type();
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint32_t dur, ts;
sta_glb->evt.power_off_send_cnt = 0;
if (user_type == USER_TYPE_STATE_GRID_BJ) {
/* get a random time between 5s and 10s */
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_BJ +
IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_BJ;
} else if (user_type == USER_TYPE_STATE_GRID_SHANGHAI) {
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_SH;
} else if (user_type == USER_TYPE_STATE_GRID_FUJIAN) {
dur = sta_glb->evt.fj_pd_valid_time * 1000;
} else if (user_type == USER_TYPE_STATE_GRID_HENAN) {
/* get a random time between 4s and 5s */
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR +
IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_HENAN;
} else if (user_type == USER_TYPE_STATE_GRID_ANHUI) {
/* get a random time between 4.5s and 5.5s */
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR +
IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_ANHUI;
} else if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
/* get a random time between 3s and 4s */
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR +
IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR_NW;
} else {
/* get a random time between 0s and 1s */
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR;
}
os_start_timer(sta_glb->power_off_timer, dur);
ts = (uint32_t)(os_boot_time64() / 1000);
iot_sg_printf("%s ts %lus\n", __FUNCTION__, ts);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_POWER_OFF_START_ID, 1, ts);
}
static uint32_t iot_sg_sta_pd_check_pm_state(uint8_t delay_flag)
{
iot_sg_sta_node_desc_t *node;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_pd_addrs_ctrl_t *ctrl = &sta_glb->evt.pd_addr_ctrl;
uint32_t ret = ERR_OK, idx;
again:
idx = ctrl->check_index;
if (idx >= IOT_SG_STA_SEC_NODE_MAX) {
ret = ERR_NOT_EXIST;
goto out;
}
if (sta_glb->node_list[idx] == NULL) {
ctrl->check_index++;
goto again;
}
node = sta_glb->node_list[idx];
IOT_ASSERT(sta_glb->drv->pm_check);
ret = sta_glb->drv->pm_check(node->entry.addr, node->data_type,
IOT_SG_STA_CHECK_PM_PD_DUR, delay_flag);
IOT_ASSERT(ret == ERR_OK || ret == ERR_NOT_EXIST);
out:
return ret;
}
void iot_sg_sta_pull_out_check_done(uint8_t result)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!sta_glb->pull_out_start_ts) {
goto out;
}
switch (result) {
case IOT_SG_STA_PO_CHECK_NO:
{
if (sta_glb->pull_out_last_sn == sta_glb->pull_out_cur_sn) {
sta_glb->pull_out_start_ts = 0;
sta_glb->pull_out_cnt = 0;
}
break;
}
case IOT_SG_STA_PO_CHECK_YES:
{
iot_system_restart(IOT_SYS_RST_REASON_PM_REQ);
break;
}
case IOT_SG_STA_PO_CHECK_UNKNOWN:
default:
break;
}
out:
return;
}
void iot_sg_sta_pd_check_done(uint8_t exist, uint8_t *addr)
{
iot_sg_msg_t *msg;
uint8_t exist_flag = exist;
iot_sg_sta_node_desc_t *node;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_pd_addrs_ctrl_t *ctrl = &sta_glb->evt.pd_addr_ctrl;
node = sta_glb->node_list[ctrl->check_index];
if ((addr && !iot_mac_addr_cmp(addr, node->entry.addr)) || !addr) {
exist_flag = 0;
}
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_DRV;
msg->task_msg.id = IOT_SG_MSG_ID_DRV_CHECK_PM_DONE;
msg->data = NULL;
msg->data2 = exist_flag;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_HP);
} else {
IOT_ASSERT(0);
}
}
static uint32_t iot_sg_sta_pd_check_done_handle(uint32_t exist)
{
uint32_t ret, start = 0;
iot_sg_sta_node_desc_t *node;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_pd_addrs_ctrl_t *ctrl = &sta_glb->evt.pd_addr_ctrl;
if (!exist) {
ctrl->check_pm_cnt++;
if (ctrl->check_pm_cnt < ctrl->check_pm_cnt_max) {
goto re_check;
}
}
ctrl->check_pm_cnt = 0;
ctrl->check_cnt++;
if (ctrl->check_cnt == IOT_SG_STA_PD_CHECK_PM_NUM
&& !ctrl->started) {
ctrl->started = 1;
start = 1;
}
node = sta_glb->node_list[ctrl->check_index];
iot_mac_addr_cpy(ctrl->local[ctrl->check_cnt - 1].mac,
node->entry.addr);
ctrl->local[ctrl->check_cnt - 1].power_state = (uint8_t)exist;
ctrl->check_index++;
iot_sg_sta_pd_addrs_merge(ctrl->local, ctrl->check_cnt);
re_check:
ret = iot_sg_sta_pd_check_pm_state(0);
if (ret == ERR_NOT_EXIST && !ctrl->started) {
ctrl->started = 1;
start = 1;
}
return start;
}
uint8_t iot_sg_sta_nw_new_meter_check(void)
{
uint8_t user_type = iot_sg_sta_get_user_type();
return (user_type == USER_TYPE_SOUTHEN_NEW_POWER_GRID ||
user_type == USER_TYPE_SOUTHEN_POWER_GRID_GX_NW21 ||
user_type == USER_TYPE_SOUTHEN_POWER_GRID_GUIZHOU);
}
static uint32_t iot_sg_sta_pd_meter_evt_rpt_is_support(void)
{
uint8_t user_type = iot_sg_sta_get_user_type();
uint8_t addr[IOT_MAC_ADDR_LEN] = { 0 };
uint32_t ret = ERR_NOSUPP;
iot_sg_sta_drv_t *drv = p_sg_glb->desc.sta->drv;
iot_sg_sta_node_desc_t *node;
if (iot_sg_sta_nw_new_meter_check() ||
user_type == USER_TYPE_STATE_GRID_OVERSEAS_SX) {
ret = ERR_OK;
} else if (drv->get_device_type() == IOT_SG_STA_DEV_TYPE_POWER_METER) {
drv->get_device_addr(addr);
node = iot_sg_sta_node_find_by_addr(addr);
if (node) {
if (node->data_type == IOT_SG_STA_DATA_TYPE_69845) {
ret = ERR_OK;
}
}
}
return ret;
}
static void iot_sg_sta_power_off_meter_evt_handle(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (iot_sg_sta_pd_meter_evt_rpt_is_support() == ERR_OK) {
return;
}
sta_glb->drv->disable_event_rpt();
sta_glb->evt.event_rpt_on = 0;
}
static uint8_t iot_sg_sta_pd_check_max_get(void)
{
uint8_t idx, cnt = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx]) {
cnt++;
if (cnt > (IOT_SG_STA_PD_CHECK_PM_NUM / 2)) {
return IOT_SG_STA_CHECK_PM_PD_CNT_MIN;
}
}
}
return IOT_SG_STA_CHECK_PM_PD_CNT_MAX;
}
static void iot_sg_sta_power_off_init(int32_t message, uint32_t device)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_power_off_bm_t *bm = &sta_glb->evt.power_off_bm;
iot_sg_plc_state_t *plc_info = iot_sg_get_plc_state_info();
iot_sg_sta_pd_addrs_ctrl_t *ctrl = &sta_glb->evt.pd_addr_ctrl;
if (sta_glb->drv->drv_id == IOT_SG_STA_DRV_ID_TEST) {
/* if sta is a relay devices, stop power off event report */
goto out;
}
if (message != IOT_PLC_PM_MSG_POWER_COLLAPSED) {
goto out;
}
if (iot_sg_sta_power_off_check()) {
goto out;
}
/* if TEI of sta is invalid, stop power off event report */
if (!GW_APP_EVENT_TEI_IS_VALID(plc_info->dev_tei)) {
goto out;
}
iot_sg_sta_power_on_report_stop();
iot_sg_sta_sm_done_evt_stop();
iot_sg_sta_power_off_meter_evt_handle();
if (sta_glb->evt.power_off_rpt_status ==
IOT_SG_STA_POWEROFF_COLLECT) {
os_stop_timer(sta_glb->power_off_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_POWER_OFF);
}
sta_glb->evt.power_off_rpt_status = IOT_SG_STA_POWEROFF_REPORT;
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_OVERSEAS_SX) {
goto out;
}
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
iot_bitmap_set(bm->map, sizeof(bm->map),
GW_APP_TEI_TO_BM(plc_info->dev_tei));
iot_sg_sta_power_off_rpt_start();
} else {
switch (device) {
case IOT_SG_STA_DEV_TYPE_POWER_METER:
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T1:
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T3:
{
iot_bitmap_set(bm->map, sizeof(bm->map),
GW_APP_TEI_TO_BM(plc_info->dev_tei));
iot_sg_sta_power_off_rpt_start();
break;
}
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T2:
{
ctrl->check_pm_cnt_max = iot_sg_sta_pd_check_max_get();
ret = iot_sg_sta_pd_check_pm_state(1);
if (ret) {
/* start power off process, because there is
* no meter in the local device.
*/
iot_sg_sta_power_off_rpt_start();
}
break;
}
default:
IOT_ASSERT(0);
break;
}
}
iot_sg_printf("%s\n", __FUNCTION__);
out:
return;
}
static void iot_sg_sta_power_off_deinit(void)
{
uint32_t i;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_evt_global_t *event = &sta_glb->evt;
iot_sg_sta_pd_addrs_ctrl_t *pd_addr_ctrl = &event->pd_addr_ctrl;
iot_sg_sta_pd_addrs_buf_t *addrs_buf = pd_addr_ctrl->addrs_buf;
event->power_off_rpt_status = IOT_SG_STA_POWEROFF_IDLE;
os_stop_timer(sta_glb->power_off_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_POWER_OFF);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_DRV,
IOT_SG_MSG_ID_DRV_CHECK_PM_DONE);
for (i = 0; i < IOT_SG_STA_PD_ADDRS_BUF_CNT; i++) {
if (addrs_buf[i].pkt) {
iot_pkt_free(addrs_buf[i].pkt);
addrs_buf[i].pkt = NULL;
}
}
os_mem_set(pd_addr_ctrl, 0x0, sizeof(iot_sg_sta_pd_addrs_ctrl_t));
os_mem_set(&event->power_off_bm, 0x0, sizeof(iot_sg_sta_power_off_bm_t));
}
static void iot_sg_sta_power_msg_handle(int32_t message)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint32_t device;
if (!sta_glb->drv) {
return;
}
device = sta_glb->drv->get_device_type();
switch (message) {
case IOT_PLC_PM_MSG_POWER_COLLAPSED:
{
sta_glb->pull_out_start_ts = 0;
/* sta power off init */
iot_sg_sta_power_off_init(message, device);
break;
}
case IOT_PLC_PM_MSG_MODULE_PULL_OUT:
{
if (device != IOT_SG_STA_DEV_TYPE_POWER_METER ||
iot_sg_sta_power_off_check()) {
break;
}
sta_glb->pull_out_cur_sn++;
if (sta_glb->pull_out_start_ts) {
break;
}
sta_glb->pull_out_start_ts = os_boot_time32();
if (!sta_glb->pull_out_start_ts) {
sta_glb->pull_out_start_ts++;
}
sta_glb->pull_out_cnt = 0;
break;
}
case IOT_PLC_PM_MSG_POWER_RECOVERED:
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_FUJIAN) {
iot_sg_sta_ext_fj_power_up_down_record_handle(
IOT_SG_STA_POWER_REC_TYPE_UP);
/* Delay for a while and wait for the write flash complete */
os_delay(5000);
iot_system_restart(IOT_SYS_RST_REASON_POWER_UP_AGAIN);
} else if (!sta_glb->evt.power_on_reporting) {
/* If power on event is reporting, ignore this message */
iot_sg_sta_power_off_deinit();
if (device == IOT_SG_STA_DEV_TYPE_COLLECTOR_T2 ||
device == IOT_SG_STA_DEV_TYPE_COLLECTOR_T3) {
iot_system_restart(IOT_SYS_RST_REASON_POWER_UP_AGAIN);
} else {
iot_sg_sta_power_on_report_start();
}
}
break;
case IOT_PLC_PM_MSG_PHASE_COLLAPSED:
default:
break;
}
}
uint32_t iot_sg_sta_get_pd_bitmap_info(
iot_sg_sta_pd_bitmap_desc_t *bitmap, uint8_t *update)
{
uint32_t ret = ERR_OK;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_power_off_bm_t *local_power_off_bm = \
&sta_glb->evt.power_off_bm;
if (!iot_bitmap_ffs(local_power_off_bm->map,
sizeof(local_power_off_bm->map))) {
return ERR_FAIL;
}
bitmap->first_tei = GW_APP_BM_TO_TEI(iot_bitmap_ffs(local_power_off_bm->map,
sizeof(local_power_off_bm->map)));
bitmap->last_tei = GW_APP_BM_TO_TEI(iot_bitmap_fls(local_power_off_bm->map,
sizeof(local_power_off_bm->map)));
IOT_ASSERT(GW_APP_EVENT_TEI_IS_VALID(bitmap->first_tei)
&& GW_APP_EVENT_TEI_IS_VALID(bitmap->first_tei));
bitmap->length = (((bitmap->last_tei - bitmap->first_tei) >> 3) + 1);
*update = local_power_off_bm->updated;
return ret;
}
static uint32_t iot_sg_sta_pd_evt_rpt_addrs(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
return (iot_sg_sta_gw_pd_evt_addrs_send(
IOT_PLC_MSG_TYPE_BCAST_1HOP_PW_OFF));
} else {
return (iot_sg_sta_nw_pd_evt_addrs_send(
IOT_PLC_MSG_TYPE_BCAST_1HOP_PW_OFF));
}
}
static uint32_t iot_sg_sta_pd_evt_rpt_bm(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
return (iot_sg_sta_gw_pd_evt_bm_send(
IOT_PLC_MSG_TYPE_BCAST_1HOP_PW_OFF));
} else {
return (iot_sg_sta_nw_pd_evt_bm_send(
IOT_PLC_MSG_TYPE_BCAST_1HOP_PW_OFF));;
}
}
static void iot_sg_sta_pd_evt_rpt_handle(void)
{
uint8_t rpt_max_cnt, user_type = iot_sg_sta_get_user_type();
uint32_t dur = IOT_SG_STA_POWEROFF_COLLECT_DUR, ret, ts;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
/* set power_off_flag */
iot_sg_sta_change_power_off_info_pib(1);
ret = iot_sg_sta_pd_evt_rpt_bm();
if (ret && ret != ERR_NOT_EXIST) {
/* other errors, stop this report, wait for some random time,
* try again.
*/
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR;
goto again;
}
ret = iot_sg_sta_pd_evt_rpt_addrs();
if (ret && ret != ERR_NOT_EXIST) {
/* Other errors, stop this report, wait for some random time,
* try again.
*/
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR;;
goto again;
}
evt->power_off_send_cnt++;
ts = (uint32_t)(os_boot_time64() / 1000);
iot_sg_printf("%s cnt %lu, ts %lus\n", __FUNCTION__,
evt->power_off_send_cnt, ts);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_POWER_OFF_SEND_ID, 2, evt->power_off_send_cnt, ts);
if (user_type == USER_TYPE_STATE_GRID_SHANGHAI) {
rpt_max_cnt = IOT_SG_STA_POWEROFF_RPT_CNT_MAX_SH;
} else if (user_type == USER_TYPE_STATE_GRID_FUJIAN) {
/* for fujian protocol, report time is 2s * 30 = 60s */
rpt_max_cnt = IOT_SG_STA_POWEROFF_RPT_CNT_MAX_FJ;
} else {
rpt_max_cnt = IOT_SG_STA_POWEROFF_RPT_CNT_MAX;
}
if (evt->power_off_send_cnt >= rpt_max_cnt) {
iot_sg_printf("%s done\n", __FUNCTION__);
goto out;
}
again:
os_start_timer(sta_glb->power_off_timer, dur);
out:
return;
}
static uint32_t iot_sg_sta_pd_evt_fwd_addrs(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
return (iot_sg_sta_gw_pd_evt_addrs_send(
IOT_PLC_MSG_TYPE_UNICAST));
} else {
return (iot_sg_sta_nw_pd_evt_addrs_send(
IOT_PLC_MSG_TYPE_UNICAST));
}
}
static uint32_t iot_sg_sta_pd_evt_fwd_bm(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
return (iot_sg_sta_gw_pd_evt_bm_send(
IOT_PLC_MSG_TYPE_UNICAST));
} else {
return (iot_sg_sta_nw_pd_evt_bm_send(
IOT_PLC_MSG_TYPE_UNICAST));
}
}
static void iot_sg_sta_pd_evt_fwd_handle(void)
{
uint8_t rpt_max_cnt, user_type = iot_sg_sta_get_user_type();
uint8_t i, bm_no_exist = 0, addr_no_exist = 0;
uint32_t ret = ERR_OK, dur;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
iot_sg_sta_pd_addrs_ctrl_t *pd_addr_ctrl = &evt->pd_addr_ctrl;
iot_sg_sta_pd_addrs_buf_t *addrs_buf = pd_addr_ctrl->addrs_buf;
if (user_type == USER_TYPE_STATE_GRID_SHANGHAI) {
dur = IOT_SG_STA_EVENT_RPT_DUR_MIN;
} else {
dur = IOT_SG_STA_POWEROFF_COLLECT_DUR;
}
ret = iot_sg_sta_pd_evt_fwd_bm();
if (ret == ERR_NOT_EXIST) {
bm_no_exist = 1;
}
if (ret && ret != ERR_NOT_EXIST) {
/* other errors, stop this report, wait for some random time,
* try again.
*/
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR;
goto again;
}
ret = iot_sg_sta_pd_evt_fwd_addrs();
if (ret == ERR_NOT_EXIST) {
addr_no_exist = 1;
}
if (ret && ret != ERR_NOT_EXIST) {
/* other errors, stop this report, wait for some random time,
* try again.
*/
dur = os_rand() % IOT_SG_STA_POWEROFF_RANDOM_RPT_DUR;
goto again;
}
if (user_type == USER_TYPE_STATE_GRID_FUJIAN) {
rpt_max_cnt = IOT_SG_STA_POWEROFF_FWD_CNT_MAX_FJ;
} else {
rpt_max_cnt = IOT_SG_STA_POWEROFF_FWD_CNT_MAX;
}
if (bm_no_exist && addr_no_exist) {
evt->power_off_send_cnt = rpt_max_cnt;
}
evt->power_off_send_cnt++;
if (evt->power_off_send_cnt >= rpt_max_cnt) {
iot_sg_printf("%s done\n", __FUNCTION__);
evt->power_off_send_cnt = 0;
evt->power_off_rpt_status = IOT_SG_STA_POWEROFF_IDLE;
os_mem_set(&evt->power_off_bm, 0x0, sizeof(evt->power_off_bm));
for (i = 0; i < IOT_SG_STA_PD_ADDRS_BUF_CNT; i++) {
if (addrs_buf[i].pkt)
iot_pkt_free(addrs_buf[i].pkt);
}
os_mem_set(addrs_buf, 0x0, sizeof(pd_addr_ctrl->addrs_buf));
goto out;
}
again:
os_start_timer(sta_glb->power_off_timer, dur);
out:
return;
}
uint32_t iot_sg_sta_mr_cache_check(uint16_t seq,
uint8_t *src_addr, uint8_t link_type, uint8_t mr_type)
{
uint8_t *data;
uint32_t len;
uint32_t ret = ERR_OK;
uint64_t elapse_t, cur_t;
iot_pkt_t *new_pkt;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->req.link_type != IOT_SG_LINK_TYPE_PLC_CTRL &&
sta_glb->mr.last_mr_valid && sta_glb->mr.last_mr_seq == seq
&& sta_glb->mr.last_mr_data_pkt
&& sta_glb->mr.last_mr_type == mr_type) {
/* if the sequence number is equal to the number of the last
* successful meter reading, send the latest successful meter
* reading data to CCO.
*/
cur_t = os_boot_time64();
elapse_t = cur_t - sta_glb->mr.last_mr_ts;
if (elapse_t <= IOT_SG_STA_LAST_MR_CACHE_LIFE) {
data = iot_pkt_data(sta_glb->mr.last_mr_data_pkt);
len = iot_pkt_data_len(sta_glb->mr.last_mr_data_pkt);
new_pkt = iot_plc_alloc_msdu(p_sg_glb->plc_app_h,
IOT_PLC_MSG_TYPE_UNICAST, IOT_PLC_ACK_TYPE_NONE, src_addr,
p_sg_glb->plc_state.addr, GW_APP_PRIO_METER_READ,
(uint16_t)len, IOT_PLC_LOCAL_RETRY_CNT);
if (!new_pkt) {
goto out;
}
os_mem_cpy(iot_pkt_tail(new_pkt), data, len);
iot_pkt_put(new_pkt, len);
iot_sg_send_msdu(new_pkt, link_type);
ret = ERR_EXIST;
}
goto out;
}
if (sta_glb->req.link_type == IOT_SG_LINK_TYPE_PLC_CTRL &&
sta_glb->mr.last_crtl_mr_valid && sta_glb->mr.last_mr_seq == seq
&& sta_glb->mr.last_mr_data_pkt) {
cur_t = os_boot_time64();
elapse_t = cur_t - sta_glb->mr.last_mr_ts;
if (elapse_t <= IOT_SG_STA_LAST_MR_CACHE_LIFE) {
data = iot_pkt_data(sta_glb->mr.last_mr_data_pkt);
len = iot_pkt_data_len(sta_glb->mr.last_mr_data_pkt);
new_pkt = iot_plc_alloc_ctrl_proto_msdu(p_sg_glb->plc_app_h,
src_addr, p_sg_glb->plc_state.addr, GW_APP_PRIO_METER_READ,
(uint16_t)len, IOT_PLC_MAX_RETRY_CNT);
if (!new_pkt) {
goto out;
}
os_mem_cpy(iot_pkt_tail(new_pkt), data, len);
iot_pkt_put(new_pkt, len);
iot_sg_send_msdu(new_pkt, link_type);
ret = ERR_EXIST;
}
}
out:
return ret;
}
static void iot_sg_sta_id_to_src_id(proto_conn_less_mr_t *req, uint8_t id)
{
req->src_id = id & 0x07;
req->src_id_ext = !!(id >> 3);
}
static uint8_t iot_sg_sta_src_id_to_id(proto_conn_less_mr_t *req)
{
uint8_t id = (uint8_t)req->src_id_ext;
id = (id << 3) | (uint8_t)req->src_id;
return id;
}
uint8_t iot_sg_sta_app_mr_cmp(uint8_t *dst_hdr, uint8_t *src_hdr)
{
uint8_t is_same = 0, src_id, dst_id;
proto_conn_less_hdr_t *src_head, *dst_head;
proto_conn_less_mr_t *src_req, *dst_req;
dst_head = (proto_conn_less_hdr_t*)dst_hdr;
src_head = (proto_conn_less_hdr_t*)src_hdr;
if (src_head->id != dst_head->id) {
goto out;
}
switch (dst_head->id) {
case CONN_LESS_APP_ID_METER_R:
{
dst_req = (proto_conn_less_mr_t*)(dst_head + 1);
src_req = (proto_conn_less_mr_t*)(src_head + 1);
src_id = iot_sg_sta_src_id_to_id(src_req);
dst_id = iot_sg_sta_src_id_to_id(dst_req);
if (src_id == dst_id) {
is_same = 1;
}
break;
}
case CONN_LESS_APP_ID_CORRECT_TIME:
{
is_same = 1;
break;
}
default:
break;
}
out:
return is_same;
}
uint32_t iot_sg_sta_add_mr_req(uint8_t id, uint8_t *mac, uint16_t seq,
uint8_t proto_type, uint8_t *data, uint16_t data_len, uint16_t timeout)
{
uint32_t size, ret = ERR_OK;
iot_pkt_t *pkt = NULL;
iot_plc_msdu_recv_t *msdu;
proto_conn_less_hdr_t *hdr;
proto_conn_less_mr_t *req;
size = sizeof(*msdu) + sizeof(*hdr) + sizeof(*req) + data_len;
pkt = iot_pkt_alloc(size, IOT_SMART_GRID_MID);
if (pkt == NULL) {
ret = ERR_NOMEM;
goto out;
}
msdu = (iot_plc_msdu_recv_t*)iot_pkt_data(pkt);
iot_mac_addr_cpy(msdu->dst, mac);
os_mem_set(msdu->src, 0, IOT_MAC_ADDR_LEN);
msdu->len = sizeof(*hdr) + sizeof(*req) + data_len;
iot_pkt_reserve(pkt, sizeof(*msdu));
size -= sizeof(*msdu);
hdr = (proto_conn_less_hdr_t*)iot_pkt_data(pkt);
hdr->port = CONN_LESS_APP_PORT;
hdr->id = CONN_LESS_APP_ID_METER_R;
req = (proto_conn_less_mr_t*)(hdr + 1);
iot_sg_sta_id_to_src_id(req, id);
req->data_type = proto_type;
req->mr_timeout = timeout;
req->data_len = data_len;
req->dir = CONN_LESS_APP_DIR_MASTER;
req->seq = seq;
os_mem_cpy(req->data, data, data_len);
iot_pkt_put(pkt, size);
ret = iot_sg_sta_queue_app_other(pkt, IOT_SG_LINK_TYPE_APP);
out:
return ret;
}
uint32_t iot_sg_sta_add_corr_req(uint8_t *data, uint16_t data_len)
{
uint8_t addr[IOT_MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint32_t size, ret = ERR_OK;
iot_pkt_t *pkt = NULL;
iot_plc_msdu_recv_t *msdu;
proto_conn_less_hdr_t *hdr;
proto_conn_less_correct_time_t *req;
size = sizeof(*msdu) + sizeof(*hdr) + sizeof(*req) + data_len;
pkt = iot_pkt_alloc(size, IOT_SMART_GRID_MID);
if (pkt == NULL) {
ret = ERR_NOMEM;
goto out;
}
msdu = (iot_plc_msdu_recv_t*)iot_pkt_data(pkt);
iot_mac_addr_cpy(msdu->dst, addr);
os_mem_set(msdu->src, 0, IOT_MAC_ADDR_LEN);
msdu->len = sizeof(*hdr) + sizeof(*req) + data_len;
iot_pkt_reserve(pkt, sizeof(*msdu));
size -= sizeof(*msdu);
hdr = (proto_conn_less_hdr_t*)iot_pkt_data(pkt);
hdr->port = CONN_LESS_APP_PORT;
hdr->id = CONN_LESS_APP_ID_CORRECT_TIME;
req = (proto_conn_less_correct_time_t*)(hdr + 1);
req->len = data_len;
os_mem_cpy(req->data, data, data_len);
iot_pkt_put(pkt, size);
ret = iot_sg_sta_queue_app_other(pkt, IOT_SG_LINK_TYPE_APP);
out:
return ret;
}
void iot_sg_sta_handle_mr_resp(uint8_t data_type, uint8_t *data,
uint16_t len)
{
uint8_t *resp_data = data, id;
uint16_t resp_len = len;
proto_conn_less_hdr_t *hdr;
proto_conn_less_mr_t *req;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
hdr = (proto_conn_less_hdr_t*)sta_glb->req.hdr;
req = (proto_conn_less_mr_t*)(hdr + 1);
id = iot_sg_sta_src_id_to_id(req);
switch (id) {
case IOT_SG_STA_MR_SRC_ID_COLLECT_FEATURE:
{
iot_sg_sta_tsfm_collect_feature_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_EXT_READ:
{
iot_sg_ext_read_data_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_EXT_CLCT_TASK:
{
iot_sg_sta_ext_clct_task_data_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_SCORE:
{
iot_sg_ext_score_data_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_DATA_CLCT:
{
iot_sg_ext_data_clct_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_DATA_FREEZE:
{
iot_sg_ext_data_freeze_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_NW_LC:
{
iot_sg_sta_ext_nw_lc_data_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_NLI_DETECT:
{
iot_sg_sta_ext_nli_read_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_EXT_AI_TOPO:
{
iot_sg_sta_ext_ai_topo_data_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
}
case IOT_SG_STA_MR_SRC_ID_EXT_AI_LL:
{
iot_sg_sta_ext_ai_ll_data_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_EXT_GW_CLCT:
{
iot_sg_sta_ext_gw_data_clct_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_EXT_EC:
{
iot_sg_sta_ext_ec_data_handle(req->seq, data_type, resp_data, resp_len,
req->data, (uint16_t)req->data_len);
break;
}
case IOT_SG_STA_MR_SRC_ID_EXT_UPGRADE:
{
iot_sg_sta_upgrade_ext_handle(req->seq, data_type,
resp_data, resp_len, req->data, (uint16_t)req->data_len);
break;
}
default:
break;
}
}
static uint8_t iot_sg_sta_cus_mr_cmp(uint8_t *dst_hdr, uint8_t *src_hdr)
{
uint8_t is_same = 0;
proto_conn_less_hdr_t *src_head, *dst_head;
proto_conn_less_mr_t *src_req, *dst_req;
dst_head = (proto_conn_less_hdr_t*)dst_hdr;
src_head = (proto_conn_less_hdr_t*)src_hdr;
if (src_head->id != dst_head->id) {
goto out;
}
switch (dst_head->id) {
case CONN_LESS_APP_ID_METER_R:
{
dst_req = (proto_conn_less_mr_t*)(dst_head + 1);
src_req = (proto_conn_less_mr_t*)(src_head + 1);
if (src_req->seq == dst_req->seq) {
is_same = 1;
}
break;
}
default:
break;
}
out:
return is_same;
}
uint32_t iot_sg_sta_add_cus_mr_req(iot_pkt_t *pkt, uint16_t seq,
uint8_t proto_type, uint16_t timeout, uint8_t flag_head)
{
uint16_t data_len = (uint16_t)iot_pkt_data_len(pkt);
uint32_t size, ret;
iot_plc_msdu_recv_t *msdu;
proto_conn_less_hdr_t *hdr;
proto_conn_less_mr_t *req;
size = sizeof(*msdu) + sizeof(*hdr) + sizeof(*req);
msdu = (iot_plc_msdu_recv_t*)iot_pkt_push(pkt, size);
iot_pkt_pull(pkt, sizeof(*msdu));
os_mem_set(msdu->dst, 0, IOT_MAC_ADDR_LEN);
os_mem_set(msdu->src, 0, IOT_MAC_ADDR_LEN);
msdu->len = sizeof(*hdr) + sizeof(*req) + data_len;
hdr = (proto_conn_less_hdr_t*)iot_pkt_data(pkt);
hdr->port = CONN_LESS_APP_PORT;
hdr->id = CONN_LESS_APP_ID_METER_R;
req = (proto_conn_less_mr_t*)(hdr + 1);
req->src_id = 0;
req->src_id_ext = flag_head;
req->data_type = proto_type;
req->mr_timeout = timeout;
req->data_len = data_len;
req->dir = CONN_LESS_APP_DIR_MASTER;
req->seq = seq;
ret = iot_sg_sta_queue_app_other(pkt, IOT_SG_LINK_TYPE_CUS);
iot_sg_printf("%s ret %lu, data type %lu, seq %lu, timeout %lu "
"flag_head %lu, len %lu\n", __FUNCTION__, ret, proto_type, seq,
timeout, flag_head, data_len);
return ret;
}
void iot_sg_sta_handle_cus_mr_resp(iot_pkt_t *pkt)
{
uint16_t len = 0;
uint32_t ret;
iot_pkt_t *resp_pkt;
proto_conn_less_hdr_t *hdr;
proto_conn_less_mr_t *req;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
hdr = (proto_conn_less_hdr_t*)sta_glb->req.hdr;
req = (proto_conn_less_mr_t*)(hdr + 1);
if (pkt == NULL) {
resp_pkt = iot_pkt_alloc(IOT_SG_EXT_HEADROOM, IOT_SMART_GRID_MID);
if (resp_pkt == NULL) {
iot_sg_printf("%s err no pkt\n", __FUNCTION__);
return;
}
iot_pkt_reserve(resp_pkt, IOT_SG_EXT_HEADROOM);
} else {
resp_pkt = pkt;
len = (uint16_t)iot_pkt_data_len(pkt);
}
ret = iot_sg_ext_sta_mr_resp(req->data_type, req->seq, resp_pkt);
iot_sg_printf("%s ret %lu, data type %lu, seq %lu, data len %lu\n",
__FUNCTION__, ret, req->data_type, req->seq, len);
}
static uint8_t iot_sg_sta_mr_get_flag_head(uint8_t *data,
uint8_t link_type)
{
uint8_t flag_head = 0;
proto_conn_less_hdr_t *hdr;
proto_conn_less_mr_t *req;
if (link_type == IOT_SG_LINK_TYPE_CUS) {
hdr = (proto_conn_less_hdr_t*)data;
req = (proto_conn_less_mr_t*)(hdr + 1);
if (hdr->port != CONN_LESS_APP_PORT
|| hdr->id != CONN_LESS_APP_ID_METER_R) {
goto out;
}
flag_head = (uint8_t)req->src_id_ext;
}
out:
return flag_head;
}
static uint32_t iot_sg_sta_handle_app_other(iot_pkt_t *pkt)
{
uint32_t ret = ERR_OK;
uint8_t link_type;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
link_type = sta_glb->req.link_type;
switch (link_type) {
case IOT_SG_LINK_TYPE_APP:
case IOT_SG_LINK_TYPE_PLC_CONN_LESS:
case IOT_SG_LINK_TYPE_PLC_BRM:
case IOT_SG_LINK_TYPE_CUS:
{
ret = iot_sg_sta_handle_conn_less(pkt);
break;
}
case IOT_SG_LINK_TYPE_PLC:
case IOT_SG_LINK_TYPE_SWC:
case IOT_SG_LINK_TYPE_PLC_CTRL:
default:
{
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_handle_app_other(pkt);
} else {
ret = iot_sg_sta_nw_handle_app_other(pkt);
}
}
}
return ret;
}
void iot_sg_sta_start_next_app_other(void)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_req_queue_t *queue = &sta_glb->queue;
iot_sg_sta_req_entry_t *req_entry;
iot_list_head_t *pos, *head;
uint8_t prio;
again:
if (sta_glb->req.pkt) {
/* free current request if any */
iot_pkt_free(sta_glb->req.pkt);
os_mem_set(&sta_glb->req, 0x0, sizeof(sta_glb->req));
}
for (prio = IOT_SG_STA_REQ_QUEUE_HP;
prio <= IOT_SG_STA_REQ_QUEUE_MP; prio++) {
head = &queue->head[prio];
if (!iot_list_empty(head) && !(queue->cnt[prio] % 2)) {
handle:
pos = head->next;
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t, link);
sta_glb->req = req_entry->req;
iot_list_del(pos);
iot_mem_pool_free(queue->q_pool, req_entry);
ret = iot_sg_sta_handle_app_other(sta_glb->req.pkt);
if (ret != ERR_PENDING) {
/* request pkt was freed if result is not pending */
os_mem_set(&sta_glb->req, 0x0, sizeof(sta_glb->req));
goto again;
}
queue->cnt[prio]++;
goto out;
}
}
for (prio = IOT_SG_STA_REQ_QUEUE_HP;
prio <= IOT_SG_STA_REQ_QUEUE_LP; prio++) {
head = &queue->head[prio];
if (!iot_list_empty(head)) {
goto handle;
}
}
out:
return;
}
static uint32_t iot_sg_sta_queue_app_cache_check(iot_pkt_t *pkt,
uint8_t link_type)
{
uint32_t ret = ERR_OK;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
switch (link_type) {
case IOT_SG_LINK_TYPE_PLC_CONN_LESS:
case IOT_SG_LINK_TYPE_PLC_BRM:
{
ret = iot_sg_sta_conn_less_queue_cache_check(pkt, link_type);
break;
}
case IOT_SG_LINK_TYPE_APP:
case IOT_SG_LINK_TYPE_CUS:
{
break;
}
case IOT_SG_LINK_TYPE_PLC:
case IOT_SG_LINK_TYPE_SWC:
case IOT_SG_LINK_TYPE_PLC_CTRL:
default:
{
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_queue_app_cache_check(pkt, link_type);
} else {
ret = iot_sg_sta_nw_queue_app_cache_check(pkt, link_type);
}
}
}
return ret;
}
/**
* @brief check if packet for node in black list
* @param pkt: the iot_pkt with application protocol data in it
* @retval: ERR_OK -- not in black list
* @retval: ERR_EXIST -- in black list
*/
static uint32_t iot_sg_sta_queue_app_bl_check(uint8_t *addr, uint8_t link_type)
{
uint32_t ret = ERR_OK;
if (link_type == IOT_SG_LINK_TYPE_PLC_BRM ||
link_type == IOT_SG_LINK_TYPE_PLC_CTRL ||
link_type == IOT_SG_LINK_TYPE_APP ||
link_type == IOT_SG_LINK_TYPE_CUS ||
!addr || !iot_mac_addr_valid(addr)) {
goto out;
}
if (iot_sg_sta_is_bl_node(addr)) {
ret = ERR_EXIST;
}
out:
return ret;
}
static uint32_t iot_sg_sta_queue_app_duplicate_check(iot_pkt_t *pkt,
uint8_t link_type)
{
uint32_t ret = ERR_OK;
uint8_t *hdr, is_same = 0, is_from_cco = 0;
iot_list_head_t *pos, *head;
iot_sg_sta_req_entry_t *req_entry;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_req_queue_t *queue = &sta_glb->queue;
uint8_t prio;
hdr = iot_pkt_data(pkt);
if (link_type == IOT_SG_LINK_TYPE_PLC ||
link_type == IOT_SG_LINK_TYPE_SWC) {
is_from_cco = 1;
}
if (!sta_glb->req.hdr || !sta_glb->req.pkt)
goto queue;
if (is_from_cco) {
if (!(sta_glb->req.link_type == IOT_SG_LINK_TYPE_PLC ||
sta_glb->req.link_type == IOT_SG_LINK_TYPE_SWC))
goto queue;
} else {
if (sta_glb->req.link_type != link_type)
goto queue;
}
switch (link_type) {
case IOT_SG_LINK_TYPE_PLC:
case IOT_SG_LINK_TYPE_SWC:
case IOT_SG_LINK_TYPE_PLC_CTRL:
{
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
is_same = iot_sg_sta_gw_sn_cmp(sta_glb->req.hdr, hdr);
} else {
is_same = iot_sg_sta_nw_sn_cmp(sta_glb->req.hdr, hdr);
}
break;
}
case IOT_SG_LINK_TYPE_PLC_CONN_LESS:
case IOT_SG_LINK_TYPE_PLC_BRM:
{
is_same = iot_sg_sta_conn_less_sn_cmp(sta_glb->req.hdr, hdr);
break;
}
case IOT_SG_LINK_TYPE_CUS:
{
is_same = iot_sg_sta_cus_mr_cmp(sta_glb->req.hdr, hdr);
break;
}
case IOT_SG_LINK_TYPE_APP:
{
is_same = iot_sg_sta_app_mr_cmp(sta_glb->req.hdr, hdr);
break;
}
default:
IOT_ASSERT(0);
break;
}
if (is_same) {
ret = ERR_EXIST;
goto out;
}
queue:
for (prio = IOT_SG_STA_REQ_QUEUE_HP;
prio <= IOT_SG_STA_REQ_QUEUE_LP; prio++) {
head = &queue->head[prio];
iot_list_for_each(pos, head) {
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t, link);
IOT_ASSERT(req_entry->req.pkt && req_entry->req.hdr);
if (is_from_cco) {
if (!(req_entry->req.link_type == IOT_SG_LINK_TYPE_PLC ||
req_entry->req.link_type == IOT_SG_LINK_TYPE_SWC))
continue;
} else {
if (req_entry->req.link_type != link_type)
continue;
}
switch (link_type) {
case IOT_SG_LINK_TYPE_PLC:
case IOT_SG_LINK_TYPE_SWC:
case IOT_SG_LINK_TYPE_PLC_CTRL:
{
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
is_same = iot_sg_sta_gw_sn_cmp(req_entry->req.hdr, hdr);
} else {
is_same = iot_sg_sta_nw_sn_cmp(req_entry->req.hdr, hdr);
}
break;
}
case IOT_SG_LINK_TYPE_PLC_CONN_LESS:
case IOT_SG_LINK_TYPE_PLC_BRM:
{
is_same = iot_sg_sta_conn_less_sn_cmp(req_entry->req.hdr, hdr);
break;
}
case IOT_SG_LINK_TYPE_APP:
{
is_same = iot_sg_sta_app_mr_cmp(req_entry->req.hdr, hdr);
break;
}
case IOT_SG_LINK_TYPE_CUS:
{
is_same = iot_sg_sta_cus_mr_cmp(sta_glb->req.hdr, hdr);
break;
}
default:
IOT_ASSERT(0);
break;
}
if (is_same) {
ret = ERR_EXIST;
break;
}
}
}
out:
return ret;
}
iot_sg_sta_node_desc_t *iot_sg_sta_node_find_by_addr(uint8_t *addr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node = NULL;
node = (iot_sg_sta_node_desc_t *)iot_addr_hash_table_find(
sta_glb->node_table, addr);
return node;
}
uint8_t iot_sg_sta_node_addr_check(uint8_t *addr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (iot_addr_hash_table_find(sta_glb->node_table, addr)) {
return ERR_OK;
} else {
return ERR_NOT_EXIST;
}
}
static uint32_t iot_sg_sta_sec_check(uint8_t *data,
uint32_t total_len, bool_t *is_mr_pkt, uint8_t link_type)
{
uint32_t ret = ERR_OK;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
switch (link_type) {
case IOT_SG_LINK_TYPE_PLC_CONN_LESS:
case IOT_SG_LINK_TYPE_PLC_BRM:
{
ret = iot_sg_sta_conn_less_sec_check(data, total_len);
break;
}
case IOT_SG_LINK_TYPE_APP:
case IOT_SG_LINK_TYPE_CUS:
{
break;
}
case IOT_SG_LINK_TYPE_PLC:
case IOT_SG_LINK_TYPE_SWC:
case IOT_SG_LINK_TYPE_PLC_CTRL:
default:
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_sec_check(data, total_len, is_mr_pkt);
} else {
ret = iot_sg_sta_nw_sec_check(data, total_len, is_mr_pkt);
}
break;
}
return ret;
}
static void iot_sg_sta_queue_app_drop(uint8_t link_type,
uint8_t *hdr, uint8_t reason)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
switch (link_type) {
case IOT_SG_LINK_TYPE_PLC_CONN_LESS:
case IOT_SG_LINK_TYPE_PLC_BRM:
{
break;
}
case IOT_SG_LINK_TYPE_APP:
case IOT_SG_LINK_TYPE_CUS:
{
break;
}
case IOT_SG_LINK_TYPE_PLC:
case IOT_SG_LINK_TYPE_SWC:
case IOT_SG_LINK_TYPE_PLC_CTRL:
default:
{
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
iot_sg_sta_gw_queue_app_drop(hdr, reason);
} else {
iot_sg_sta_nw_queue_app_drop(hdr, reason);
}
break;
}
}
}
void iot_sg_sta_queue_app_del_by_type(uint8_t link_type)
{
uint8_t prio;
iot_list_head_t *pos = NULL, *n = NULL;
iot_sg_sta_req_entry_t *req_entry;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_req_queue_t *queue = &sta_glb->queue;
for (prio = IOT_SG_STA_REQ_QUEUE_HP;
prio <= IOT_SG_STA_REQ_QUEUE_LP; prio++) {
iot_list_for_each_safe(pos, n, &queue->head[prio]) {
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t, link);
IOT_ASSERT(req_entry->req.pkt && req_entry->req.hdr);
if (req_entry->req.link_type == link_type) {
iot_list_del(pos);
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t, link);
iot_sg_sta_queue_app_drop(req_entry->req.link_type,
req_entry->req.hdr, 7);
iot_pkt_free(req_entry->req.pkt);
iot_mem_pool_free(queue->q_pool, req_entry);
}
}
}
}
void iot_sg_sta_queue_app_del_by_src(uint8_t src_id)
{
uint8_t prio, id;
iot_list_head_t *pos = NULL, *n = NULL;
proto_conn_less_hdr_t *head;
proto_conn_less_mr_t *req;
iot_sg_sta_req_entry_t *req_entry;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_req_queue_t *queue = &sta_glb->queue;
for (prio = IOT_SG_STA_REQ_QUEUE_HP;
prio <= IOT_SG_STA_REQ_QUEUE_LP; prio++) {
iot_list_for_each_safe(pos, n, &queue->head[prio]) {
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t, link);
IOT_ASSERT(req_entry->req.pkt && req_entry->req.hdr);
if (req_entry->req.link_type == IOT_SG_LINK_TYPE_APP) {
head = (proto_conn_less_hdr_t*)req_entry->req.hdr;
if (head->id == CONN_LESS_APP_ID_METER_R) {
req = (proto_conn_less_mr_t*)(head + 1);
id = iot_sg_sta_src_id_to_id(req);
if (id == src_id) {
iot_list_del(pos);
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t,
link);
iot_sg_sta_queue_app_drop(req_entry->req.link_type,
req_entry->req.hdr, 7);
iot_pkt_free(req_entry->req.pkt);
iot_mem_pool_free(queue->q_pool, req_entry);
}
}
}
}
}
}
static uint32_t iot_sg_sta_correct_time_req_check(uint8_t *data, uint32_t len)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_correct_time_req_check(data, len);
} else {
ret = iot_sg_sta_nw_correct_time_req_check(data, len);
}
return ret;
}
static iot_list_head_t *iot_sg_sta_queue_last_corr_req_find()
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_req_queue_t *queue = &sta_glb->queue;
iot_list_head_t *pos, *temp, *last_corr_req = NULL;
iot_sg_sta_req_entry_t *req_entry;
iot_list_for_each_safe(pos, temp, &queue->head[IOT_SG_STA_REQ_QUEUE_HP]) {
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t, link);
if (req_entry->req.is_corr_time) {
last_corr_req = pos;
} else {
break;
}
}
return last_corr_req;
}
uint32_t iot_sg_sta_queue_app_other(iot_pkt_t *pkt, uint8_t link_type)
{
uint8_t reason = 0, *data, addr[IOT_MAC_ADDR_LEN] = { 0 };
uint8_t dev_addr[IOT_MAC_ADDR_LEN];
uint32_t total_len, ret = ERR_OK;
bool_t is_in_mlist = true, is_mr_pkt = false;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_req_queue_t *queue = &sta_glb->queue;
iot_sg_sta_req_entry_t *req_entry;
iot_sg_sta_node_desc_t *node;
iot_list_head_t *pos, *add_pos, *last_corr_req;
iot_plc_msdu_recv_t *msdu;
data = iot_pkt_data(pkt);
total_len = iot_pkt_data_len(pkt);
msdu = (iot_plc_msdu_recv_t *)(data - sizeof(*msdu));
/* do security check */
if (iot_sg_sta_sec_check(data, total_len, &is_mr_pkt, link_type)) {
reason = 1;
goto drop;
}
/* determine whether the pkt already exists in the queue */
if (iot_sg_sta_queue_app_duplicate_check(pkt, link_type) == ERR_EXIST) {
/* the pkt exist in queue, let's drop the pkt */
reason = 2;
goto drop;
}
iot_sg_sta_get_pm_addr(pkt, link_type, addr);
/* determine whether the pkt is for a node in black list */
if (iot_sg_sta_queue_app_bl_check(addr, link_type) == ERR_EXIST) {
reason = 3;
iot_counter_inc(sta_glb->mr.mr_info.mr_bl_cnt);
goto drop;
}
/* determine whether we have cached data for the duplicated request */
if (iot_sg_sta_queue_app_cache_check(pkt, link_type) == ERR_EXIST) {
iot_counter_inc(sta_glb->mr.mr_info.mr_cache_cnt);
reason = 4;
goto drop;
}
if (is_mr_pkt && iot_mac_is_bcast(msdu->dst)
&& iot_mac_addr_valid(addr)) {
node = iot_sg_sta_node_find_by_addr(addr);
sta_glb->drv->get_device_addr(dev_addr);
if (node == NULL && !iot_mac_addr_cmp(dev_addr, addr)) {
if (sta_glb->mr.addr_filter_en) {
reason = 5;
goto drop;
}
is_in_mlist = false;
}
}
req_entry = iot_mem_pool_alloc(queue->q_pool);
if (req_entry == NULL) {
/* req queue is full, let's drop the oldest pending request */
if (is_in_mlist) {
/* known request */
if (!iot_list_empty(&queue->head[IOT_SG_STA_REQ_QUEUE_LP])) {
/* precedence drop unknown request */
pos = queue->head[IOT_SG_STA_REQ_QUEUE_LP].next;
} else if (!iot_list_empty(&queue->head[IOT_SG_STA_REQ_QUEUE_HP])) {
pos = queue->head[IOT_SG_STA_REQ_QUEUE_HP].next;
} else {
reason = 6;
goto drop;
}
} else {
/* unknown request */
if (!iot_list_empty(&queue->head[IOT_SG_STA_REQ_QUEUE_LP])) {
pos = queue->head[IOT_SG_STA_REQ_QUEUE_LP].next;
} else {
/* the queue is full, and all request are known. */
reason = 7;
goto drop;
}
}
iot_list_del(pos);
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t, link);
iot_sg_sta_queue_app_drop(req_entry->req.link_type,
req_entry->req.hdr, 8);
iot_pkt_free(req_entry->req.pkt);
}
if (link_type == IOT_SG_LINK_TYPE_APP) {
add_pos = &queue->head[IOT_SG_STA_REQ_QUEUE_MP];
} else {
add_pos = &queue->head[((is_in_mlist) ? IOT_SG_STA_REQ_QUEUE_HP : \
IOT_SG_STA_REQ_QUEUE_LP)];
}
req_entry->req.pkt = pkt;
req_entry->req.hdr = data;
req_entry->req.link_type = link_type;
req_entry->req.is_conn_fwd = iot_sg_sta_conn_fwd_msg_check(pkt, link_type);
iot_mac_addr_cpy(req_entry->req.pm_addr, addr);
if (iot_sg_sta_correct_time_req_check(data, total_len) == ERR_OK) {
last_corr_req = iot_sg_sta_queue_last_corr_req_find();
if (last_corr_req) {
add_pos = last_corr_req;
} else {
add_pos = &queue->head[IOT_SG_STA_REQ_QUEUE_HP];
}
req_entry->req.is_corr_time = 1;
iot_list_add(&req_entry->link, add_pos);
} else {
req_entry->req.is_corr_time = 0;
if (iot_sg_sta_mr_get_flag_head(data, link_type)) {
iot_list_add(&req_entry->link, add_pos);
} else {
iot_list_add_prev(&req_entry->link, add_pos);
}
}
if (sta_glb->req.pkt == NULL) {
iot_sg_sta_start_next_app_other();
}
goto out;
drop:
ret = ERR_FAIL;
iot_sg_sta_queue_app_drop(link_type, data, reason);
iot_pkt_free(pkt);
out:
return ret;
}
void iot_sg_sta_stop_detect_timer()
{
os_stop_timer(p_sg_glb->desc.sta->detect_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_DETECT);
}
void iot_sg_sta_drv_detect_done(void)
{
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_DRV;
msg->task_msg.id = IOT_SG_MSG_ID_DRV_DETECT_DONE;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
void iot_sg_sta_drv_private_call_req(uint32_t data,
iot_pkt_t *pkt)
{
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_DRV;
msg->task_msg.id = IOT_SG_MSG_ID_DRV_PRIVATE_CALL_REQ;
msg->data = pkt;
msg->data2 = data;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
if (pkt) {
iot_pkt_free(pkt);
}
}
}
void iot_sg_sta_drv_private_call_req_cancel(void)
{
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_DRV,
IOT_SG_MSG_ID_DRV_PRIVATE_CALL_REQ);
}
uint8_t iot_sg_sta_to_plc_dev_type(uint8_t dev_type)
{
uint8_t plc_dev_type;
switch (dev_type) {
case IOT_SG_STA_DEV_TYPE_POWER_METER:
plc_dev_type = IOT_PLC_DEV_TYPE_POWER_METER;
if (p_sg_glb->module_type == MODULE_TYPE_3_PHASE_STA) {
plc_dev_type = IOT_PLC_DEV_TYPE_POWER_METER_3P;
}
break;
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T1:
plc_dev_type = IOT_PLC_DEV_TYPE_COLLECTOR_1;
break;
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T2:
plc_dev_type = IOT_PLC_DEV_TYPE_COLLECTOR_2;
break;
case IOT_SG_STA_DEV_TYPE_COLLECTOR_T3:
if (iot_oem_get_board_id() == 30) {
plc_dev_type = IOT_PLC_DEV_TYPE_BRK_MONITOR;
} else if (!iot_sg_sta_hw_tsfm_is_3p()) {
plc_dev_type = IOT_PLC_DEV_TYPE_SWITCH_MONITOR;
} else {
plc_dev_type = IOT_PLC_DEV_TYPE_TSFM_MONITOR;
}
break;
default:
IOT_ASSERT(0);
plc_dev_type = IOT_PLC_DEV_TYPE_INVAL;
break;
}
return plc_dev_type;
}
static uint8_t iot_sg_sta_to_plc_addr_type(uint8_t addr_type)
{
uint8_t plc_addr_type;
switch (addr_type) {
case IOT_SG_STA_DRV_ADDR_TYPE_COLLECTOR:
{
plc_addr_type = IOT_PLC_MAC_ADDR_TYPE_COLLECTOR;
break;
}
case IOT_SG_STA_DRV_ADDR_TYPE_REPEATER:
{
plc_addr_type = IOT_PLC_MAC_ADDR_TYPE_MODULE;
break;
}
case IOT_SG_STA_DRV_ADDR_TYPE_METER:
case IOT_SG_STA_DRV_ADDR_TYPE_DEFAULT:
case IOT_SG_STA_DRV_ADDR_TYPE_FOLLOW:
default:
{
plc_addr_type = IOT_PLC_MAC_ADDR_TYPE_METER;
break;
}
}
return plc_addr_type;
}
static void iot_sg_sta_drv_detect_round_check(void)
{
uint8_t dev_type;
iot_plc_cfg_set_req_t cfg;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->detect_round != IOT_SG_STA_DETECT_CNT_BEFORE_JOIN)
return;
if (!sta_glb->pib.ro->cfg.fr.allow_use_module_addr)
return;
if (sta_glb->drv) {
dev_type = (uint8_t)sta_glb->drv->get_device_type();
} else {
dev_type = IOT_SG_STA_DEV_TYPE_POWER_METER;
}
dev_type = iot_sg_sta_to_plc_dev_type(dev_type);
iot_sg_printf("%s round %lu dev_type %lu\n", __FUNCTION__,
sta_glb->detect_round, dev_type);
os_mem_set(&cfg, 0, sizeof(cfg));
cfg.dev_type_valid = 1;
cfg.dev_type = dev_type;
cfg.reset = 1;
iot_plc_set_cfg(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT,
&cfg);
iot_swc_set_cfg(IOT_SWC_API_REQ_ID_DEFAULT, NULL, dev_type, 1);
}
/**
* @brief: sta set join certification to pib.
* @param join_check: sta join certification state: 0 - disabled, 1 - enable.
* other values is invalid.
*/
static void iot_sg_sta_set_join_check_state_to_pib(uint8_t join_check)
{
uint8_t ref;
uint16_t ticket;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (sta_pib == NULL) {
return;
}
if (join_check != sta_pib->join_check) {
iot_pib_acquire_app_commit_ref(&ref);
iot_sg_printf("%s flg %lu -> %lu\n", __FUNCTION__, sta_pib->join_check,
join_check);
sta_pib->join_check = !!join_check;
iot_pib_release_app_commit_ref(&ref);
iot_pib_app_commit(&ticket);
}
}
void iot_sg_sta_set_join_check_state(uint8_t join_check)
{
iot_plc_cfg_set_req_t cfg;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (sta_pib->join_check != join_check) {
os_mem_set(&cfg, 0, sizeof(cfg));
cfg.join_check = !!join_check;
cfg.join_check_valid = 1;
iot_plc_set_cfg(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT, &cfg);
iot_sg_sta_set_join_check_state_to_pib(join_check);
}
}
static void iot_sg_sta_node_ext_func_enable(void)
{
uint8_t idx;
iot_sg_sta_node_desc_t *node = NULL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
(void)node;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx] != NULL &&
!sta_glb->node_list[idx]->obsolete) {
node = sta_glb->node_list[idx];
iot_sg_sta_ext_meter_add(node);
}
}
}
void iot_sg_sta_br2_record_init(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->br2_enable && !sta_glb->br2_record_init) {
/* flash_cfg_init priority over tsfm_record_init */
if (iot_sg_sta_flash_tsfm_record_init() == ERR_OK) {
iot_sg_sta_hw_tsfm_topo_record_init();
sta_glb->br2_record_init = 1;
}
}
}
void iot_sg_sta_repeater_flw_addr_set(uint8_t *flw_addr)
{
iot_plc_cfg_set_req_t cfg;
os_mem_set(&cfg, 0, sizeof(cfg));
cfg.addr_valid = 1;
cfg.addr_type = IOT_PLC_MAC_ADDR_TYPE_METER;
iot_mac_addr_cpy(cfg.addr, flw_addr);
iot_mac_addr_reverse(cfg.addr);
cfg.dev_type_valid = 1;
cfg.dev_type = IOT_PLC_DEV_TYPE_REPEATER;
cfg.reset = 1;
iot_plc_set_cfg(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT, &cfg);
}
static void iot_sg_sta_drv_detect_done_handle(void)
{
iot_plc_cfg_set_req_t cfg;
uint8_t dev_type, addr[IOT_MAC_ADDR_LEN], addr_type;
uint8_t user_type = iot_sg_sta_get_user_type();
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
iot_sg_ext_dev_info_t dev_info = { 0 };
if (!sta_glb->drv) {
sta_glb->drv = g_sta_drv_table[sta_glb->detect_idx];
}
sta_glb->drv->get_login_addr(addr);
sta_glb->addr_type = IOT_SG_STA_DRV_ADDR_TYPE_DEFAULT;
if (iot_mac_addr_valid(addr)) {
iot_mac_addr_cpy(dev_info.addr, addr);
dev_type = (uint8_t)sta_glb->drv->get_device_type();
if (iot_sg_sta_ext_init()) {
iot_sg_printf("ext func init fail\n");
} else {
iot_sg_sta_node_ext_func_enable();
}
/* If it is a valid meter address, use the meter address to log in */
iot_mac_addr_reverse(addr);
dev_type = iot_sg_sta_to_plc_dev_type(dev_type);
if (sta_glb->drv->get_login_type) {
addr_type = (uint8_t)sta_glb->drv->get_login_type();
sta_glb->addr_type = addr_type;
if (addr_type == IOT_SG_STA_DRV_ADDR_TYPE_REPEATER
|| addr_type == IOT_SG_STA_DRV_ADDR_TYPE_FOLLOW) {
dev_type = IOT_PLC_DEV_TYPE_REPEATER;
}
addr_type = iot_sg_sta_to_plc_addr_type(addr_type);
} else {
addr_type = IOT_PLC_MAC_ADDR_TYPE_METER;
}
iot_sg_ext_dev_info_sync_to_cusapp(&dev_info);
} else {
/* if it is not a valid meter address, it is logged in
* iot as a repeater device type.
*/
dev_type = IOT_PLC_DEV_TYPE_REPEATER;
addr_type = IOT_PLC_MAC_ADDR_TYPE_MODULE;
}
os_mem_set(&cfg, 0, sizeof(cfg));
cfg.addr_valid = 1;
cfg.addr_type = addr_type;
iot_mac_addr_cpy(cfg.addr, addr);
cfg.dev_type_valid = 1;
cfg.dev_type = dev_type;
cfg.reset = 1;
if (user_type == USER_TYPE_STATE_GRID_HUNAN &&
sta_pib && sta_pib->join_check) {
cfg.join_check = sta_pib->join_check;
cfg.join_check_valid = 1;
} else if (user_type == USER_TYPE_STATE_GRID_FUJIAN) {
iot_sg_sta_flash_cfg_init();
iot_sg_sta_fj_tm_cfg_init();
iot_sg_sta_fj_evt_rpt_init();
iot_sg_sta_fj_pd_cfg_init();
} else if (user_type == USER_TYPE_STATE_GRID_HLJ ||
user_type == USER_TYPE_STATE_GRID_GANSU) {
iot_sg_sta_ext_auto_tm_init(addr);
} else if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
iot_sg_sta_flash_cfg_init();
if (user_type == USER_TYPE_SOUTHEN_POWER_GRID_SHENZHEN) {
iot_sg_sta_ext_auto_tm_init(addr);
}
}
iot_sg_sta_br2_record_init();
iot_plc_set_blacklist(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT,
IOT_PLC_BL_ENABLE, 0, NULL);
iot_plc_set_cfg(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT, &cfg);
iot_swc_set_cfg(IOT_SWC_API_REQ_ID_DEFAULT, addr, dev_type, 1);
if (sta_glb->drv->dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T2) {
iot_plc_wdg_set(p_sg_glb->plc_app_h, 1,
IOT_SG_STA_COLLECTOR_WDG_RESET_TIME);
} else if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_OVERSEAS_SX) {
iot_plc_wdg_set(p_sg_glb->plc_app_h, 1, IOT_SG_STA_QSXJ_WDG_RESET_TIME);
}
return;
}
static void iot_sg_sta_bl_node_check_callback(iot_addr_hash_entry_t *entry,
void* param)
{
uint32_t *curr_ts;
iot_sg_sta_node_bl_desc_t *node;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
node = (iot_sg_sta_node_bl_desc_t *)entry;
curr_ts = (uint32_t *)param;
if (node->rm_ts <= *curr_ts) {
iot_addr_hash_table_remove(sta_glb->node_bl_table,
entry);
iot_addr_hash_table_free(sta_glb->node_bl_table,
entry);
}
}
/* refresh black list */
static void iot_sg_sta_refresh_bl()
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint32_t curr_ts;
curr_ts = (uint32_t)(os_boot_time64() / 1000);
iot_addr_hash_table_loop(sta_glb->node_bl_table,
iot_sg_sta_bl_node_check_callback, &curr_ts);
}
static void iot_sg_sta_add_nid_to_nid_list(uint32_t nid,
iot_sg_sta_invalid_addr_entry_t *entry_s)
{
if (entry_s->nid_cnt < IOT_SG_STA_JOINING_NID_LIST_MAX_NUM) {
entry_s->nid_list[entry_s->nid_cnt].nid = nid;
entry_s->nid_list[entry_s->nid_cnt].join_cnt = 1;
entry_s->nid_cnt++;
} else {
iot_sg_printf("%s nid cnt max\n", __FUNCTION__);
}
}
static void iot_sg_sta_update_nid_info_to_nid_list(uint32_t nid,
iot_sg_sta_invalid_addr_entry_t *entry_s)
{
uint8_t nid_cnt, i = 0, new = 1;
uint32_t cur_ts;
if (entry_s->invalid_mac) {
return;
}
for (nid_cnt = 0; nid_cnt < IOT_SG_STA_JOINING_NID_LIST_MAX_NUM;
nid_cnt++) {
if (nid == entry_s->nid_list[nid_cnt].nid) {
entry_s->nid_list[nid_cnt].join_cnt++;
new = 0;
}
if (entry_s->nid_list[nid_cnt].join_cnt >=
IOT_SG_STA_INVALID_MAC_RPT_CNT) {
i++;
}
}
cur_ts = (uint32_t)(os_boot_time64() / 1000);
if (new) {
iot_sg_sta_add_nid_to_nid_list(nid, entry_s);
entry_s->rm_ts = cur_ts + IOT_SG_STA_VALID_ADDR_DUR;
} else if (i == entry_s->nid_cnt) {
entry_s->invalid_mac = 1;
entry_s->rm_ts = cur_ts + IOT_SG_STA_INVALID_ADDR_DUR;
}
}
static void iot_sg_sta_invalid_mac_add(uint8_t *addr, uint32_t nid)
{
uint8_t i;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_invalid_addr_entry_t *entry_s =
sta_glb->invalid_addr_list;
iot_sg_sta_invalid_addr_entry_t *free = NULL, *old = NULL, *place;
for (i = 0; i < IOT_SG_STA_INVALID_ADDR_LIST_SIZE; i++) {
if (iot_mac_addr_valid(entry_s[i].addr)) {
if (!old) {
old = &entry_s[i];
} else if (old->rm_ts > entry_s[i].rm_ts) {
old = &entry_s[i];
}
if (iot_mac_addr_cmp(addr, entry_s[i].addr)) {
iot_sg_sta_update_nid_info_to_nid_list(nid, &entry_s[i]);
return;
}
} else {
if (!free) {
free = &entry_s[i];
}
}
}
if (free)
place = free;
else
place = old;
os_mem_set(place, 0x0, sizeof(*place));
iot_mac_addr_cpy(place->addr, addr);
iot_sg_sta_update_nid_info_to_nid_list(nid, place);
}
static uint8_t iot_sg_sta_is_invalid_mac(uint8_t *addr)
{
uint8_t i;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_invalid_addr_entry_t *entry_s =
sta_glb->invalid_addr_list;
for (i = 0; i < IOT_SG_STA_INVALID_ADDR_LIST_SIZE; i++) {
if (iot_mac_addr_cmp(addr, entry_s[i].addr)) {
if (entry_s[i].invalid_mac) {
return 1;
} else {
break;
}
}
}
return 0;
}
static uint32_t iot_sg_sta_find_valid_mac(uint8_t *addr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
uint32_t idx;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx] != NULL) {
node = sta_glb->node_list[idx];
if (!iot_sg_sta_is_invalid_mac(node->entry.addr)
&& !node->obsolete) {
iot_mac_addr_cpy(addr, node->entry.addr);
return ERR_OK;
}
}
}
return ERR_NOT_EXIST;
}
static void iot_sg_sta_invalid_addr_refresh(void)
{
uint32_t cur_ts;
uint8_t i;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_invalid_addr_entry_t *entry_s =
sta_glb->invalid_addr_list;
cur_ts = (uint32_t)(os_boot_time64() / 1000);
for (i = 0; i < IOT_SG_STA_INVALID_ADDR_LIST_SIZE; i++) {
if (iot_mac_addr_valid(entry_s[i].addr)) {
if (entry_s[i].rm_ts <= cur_ts) {
os_mem_set(&entry_s[i], 0x0, sizeof(*entry_s));
}
}
}
}
/* check if the minutes of current time is the multiple of 15
* 1 - is the multiple of 15
* 0 - otherwise
*/
static uint32_t iot_sg_sta_15min_integer_check(void)
{
uint32_t result;
iot_time_tm_t curr_tm;
if (iot_sg_sta_rtc_get(&curr_tm, 0)) {
result = 0;
goto out;
}
if (curr_tm.tm_min % 15 == 0) {
result = 1;
} else {
result = 0;
}
out:
return result;
}
static void iot_sg_sta_get_pm_time(void)
{
uint8_t user_type = iot_sg_sta_get_user_type();
uint32_t time = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (user_type == USER_TYPE_SOUTHEN_POWER_GRID_GX ||
user_type == USER_TYPE_BRM_PEIWANG ||
user_type == USER_TYPE_BRM_PEIWANG_DUAL_NET) {
if (!p_sg_glb->plc_state.cert_test_detected) {
/* if cert test command isn't ever detected, app start get time*/
sta_glb->time_cnt++;
if (sta_glb->get_time_done) {
time = IOT_SG_STA_READ_METER_TIME_INTERVAL;
} else {
time = IOT_SG_STA_READ_METER_TIME_FAST;
/* first read meter not need delay */
if (sta_glb->pm_tm_tried == 0) {
sta_glb->pm_tm_tried = 1;
time = 0;
}
}
if (sta_glb->time_cnt >= time) {
iot_sg_sta_start_get_time();
sta_glb->time_cnt = 0;
}
}
} else if (user_type == USER_TYPE_STATE_GRID_FUJIAN) {
if (!p_sg_glb->plc_state.cert_test_detected) {
/* if cert test command isn't ever detected, app start get time */
sta_glb->time_cnt++;
if (sta_glb->get_time_done) {
if (sta_glb->tm_soc == PROTO_645_FJ_MOD_TM_SOC_PM) {
time = sta_glb->ct_dur * 60;
} else {
time = IOT_SG_STA_READ_METER_TIME_INTERVAL;
}
} else {
time = IOT_SG_STA_READ_METER_TIME_DELAY;
}
if (sta_glb->time_cnt >= time
&& !iot_sg_sta_15min_integer_check()) {
iot_sg_sta_start_get_time();
sta_glb->time_cnt = 0;
}
}
} else {
if (!p_sg_glb->plc_state.cert_test_detected) {
/* if cert test command isn't ever detected, app start get time */
sta_glb->time_cnt++;
if (sta_glb->get_time_done) {
if (user_type == USER_TYPE_TM) {
time = IOT_SG_STA_READ_METER_TIME_INTERVAL_TM;
} else {
time = IOT_SG_STA_READ_METER_TIME_INTERVAL;
}
} else {
time = IOT_SG_STA_READ_METER_TIME_DELAY;
}
if (sta_glb->time_cnt >= time) {
iot_sg_sta_start_get_time();
sta_glb->time_cnt = 0;
}
}
}
}
#if IOT_BSRM_MODE == IOT_BSRM_MODE_CUS_APP
static void iot_sg_sta_query_neig_resp_from_sta (
iot_plc_neighbor_dev_rpt_t *rpt)
{
uint16_t i;
uint8_t addr[IOT_MAC_ADDR_LEN];
iot_sg_sta_node_desc_t *node;
if (!rpt) {
return;
}
for (i = 0; i < rpt->cnt; i++) {
iot_mac_addr_cpy(addr, rpt->node[i].addr);
iot_mac_addr_reverse(addr);
node = iot_sg_sta_node_find_by_addr(addr);
if (node) {
node->is_neighbor = 1;
}
}
}
static void iot_sg_sta_node_in_neig_state_query(void)
{
uint16_t len;
uint8_t link_ready = p_sg_glb->plc_state.link_ready;
uint8_t i, cnt = 0, addr[IOT_MAC_ADDR_LEN], *data = NULL;
iot_pkt_t *pkt = NULL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
sta_glb->neighbor_cnt++;
if (sta_glb->neighbor_cnt >= IOT_SG_STA_NODE_IN_NEIG_QUERY_INTERVAL) {
sta_glb->neighbor_cnt = 0;
if (link_ready) {
len = IOT_MAC_ADDR_LEN * IOT_SG_STA_SEC_NODE_MAX;
pkt = iot_pkt_alloc(len, IOT_SMART_GRID_MID);
if (!pkt) {
return;
}
data = iot_pkt_put(pkt, len);
}
for (i = 0; i < IOT_SG_STA_SEC_NODE_MAX; i++) {
if (sta_glb->node_list[i]) {
if (link_ready) {
iot_mac_addr_cpy(addr, sta_glb->node_list[i]->entry.addr);
iot_mac_addr_reverse(addr);
iot_mac_addr_cpy(data + (cnt * IOT_MAC_ADDR_LEN), addr);
cnt++;
}
sta_glb->node_list[i]->is_neighbor = 0;
}
}
if (link_ready) {
iot_plc_query_neighbor_by_mac(p_sg_glb->plc_app_h,
IOT_SG_STA_QUERY_NEIG_NODE_FROM_STA, data, cnt);
}
}
if (pkt) {
iot_pkt_free(pkt);
}
}
static uint32_t iot_sg_sta_node_in_neig_uart_query_handle(
proto_645_header_t *hdr_645)
{
uint32_t ret = ERR_FAIL;
uint8_t i, len, login_addr[IOT_MAC_ADDR_LEN];
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
proto_645_ext_node_in_neig_resp_t *node_resp;
iot_pkt_t *pkt_buff = NULL, *pkt = NULL;
if (!hdr_645) {
goto out;
}
if (hdr_645->control.dir != PROTO_645_DIR_MASTER) {
goto nack;
}
len = sizeof(*node_resp) + (sizeof(proto_645_ext_node_in_neig_info_t) *
IOT_SG_STA_SEC_NODE_MAX);
pkt_buff = iot_pkt_alloc(len, IOT_SMART_GRID_MID);
if (!pkt_buff) {
goto out;
}
node_resp = (proto_645_ext_node_in_neig_resp_t *)
iot_pkt_put(pkt_buff, sizeof(*node_resp));
for (i = 0; i < IOT_SG_STA_SEC_NODE_MAX; i++) {
if (sta_glb->node_list[i]) {
iot_mac_addr_cpy(node_resp->node_info[node_resp->node_num].addr,
sta_glb->node_list[i]->entry.addr);
node_resp->node_info[node_resp->node_num].is_neighbor =
sta_glb->node_list[i]->is_neighbor;
node_resp->node_num++;
iot_pkt_put(pkt_buff, sizeof(proto_645_ext_node_in_neig_info_t));
}
}
iot_mac_addr_cpy(login_addr, p_sg_glb->plc_state.addr);
iot_mac_addr_reverse(login_addr);
pkt = proto_645_build_msg(login_addr, iot_pkt_data(pkt_buff),
(uint8_t)iot_pkt_data_len(pkt_buff), PROTO_645_2007_EXT_DI_NODE_IN_NEIG,
PROTO_645_DIR_SLAVE, PROTO_645_ACK_NORMAL, PROTO_645_2007_FN_READ_DATA,
PROTO_645_2007_ID, PROTO_645_FOLLOW_INVALID);
goto out;
nack:
pkt = proto_645_2007_build_nack_msg(PROTO_645_2007_ERR_OTHER, hdr_645->addr,
PROTO_645_2007_FN_READ_DATA);
out:
if (pkt) {
iot_sg_sta_send_uart(pkt);
ret = ERR_OK;
}
if (pkt_buff) {
iot_pkt_free(pkt_buff);
}
return ret;
}
#else /* IOT_BSRM_MODE == IOT_BSRM_MODE_CUS_APP */
static void iot_sg_sta_query_neig_resp_from_sta (
iot_plc_neighbor_dev_rpt_t *rpt)
{
(void)rpt;
}
static void iot_sg_sta_node_in_neig_state_query(void)
{
}
static uint32_t iot_sg_sta_node_in_neig_uart_query_handle(
proto_645_header_t *hdr_645)
{
(void)hdr_645;
return ERR_NOSUPP;
}
#endif /* IOT_BSRM_MODE == IOT_BSRM_MODE_CUS_APP */
static void iot_sg_sta_query_neig_resp_from_plc(
iot_plc_neighbor_dev_rpt_t *rpt)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!sta_glb->plc_query.neig_info_query_on) {
return;
}
if (rpt == NULL) {
goto next;
}
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
iot_sg_sta_nw_neighbor_info_resp(rpt,
sta_glb->plc_query.flag_broadcast);
} else {
iot_sg_sta_gw_tsfm_neighbor_snr_info_resp(rpt);
}
next:
sta_glb->plc_query.neig_info_query_on = 0;
sta_glb->plc_query.neig_info_timeout = 0;
sta_glb->plc_query.flag_broadcast = 0;
iot_sg_sta_start_next_app_other();
}
static void iot_sg_sta_plc_query_neig_timeout(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->plc_query.neig_info_query_on) {
if (sta_glb->plc_query.neig_info_timeout) {
sta_glb->plc_query.neig_info_timeout--;
} else {
iot_sg_sta_query_neig_resp_from_plc(NULL);
}
}
}
static void iot_sg_sta_pull_out_check(void)
{
uint32_t delta = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!sta_glb->pull_out_start_ts) {
goto out;
}
sta_glb->pull_out_cnt++;
if (sta_glb->pull_out_cnt > IOT_SG_STA_PULL_OUT_CHECK_WAIT_TIME) {
sta_glb->pull_out_cnt = 0;
delta = os_boot_time32() - sta_glb->pull_out_start_ts;
if (delta >= IOT_SG_STA_PULL_OUT_CHECK_RESTART_TIME) {
iot_system_restart(IOT_SYS_RST_REASON_PM_REQ);
} else {
if (sta_glb->drv && sta_glb->drv->pull_out_check) {
sta_glb->pull_out_last_sn = sta_glb->pull_out_cur_sn;
sta_glb->drv->pull_out_check();
}
}
}
out:
return;
}
static void iot_sg_sta_refresh_cco_bl()
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint8_t i;
if (!sta_glb->cco_bl_invalid_time) {
goto out;
}
for (i = 0; i < IOT_SG_STA_BLACK_LIST_MAX_CNT; i++) {
if (!iot_mac_addr_valid(sta_glb->cco_bl[i].addr)) {
continue;
}
if (sta_glb->cco_bl[i].invalid_tm_cnt) {
sta_glb->cco_bl[i].invalid_tm_cnt--;
continue;
}
sta_glb->cco_bl_update_flag = 1;
iot_sg_printf("%s del %02x%02x%02x%02x%02x%02x\n", __FUNCTION__,
sta_glb->cco_bl[i].addr[0], sta_glb->cco_bl[i].addr[1],
sta_glb->cco_bl[i].addr[2], sta_glb->cco_bl[i].addr[3],
sta_glb->cco_bl[i].addr[4], sta_glb->cco_bl[i].addr[5]);
iot_plc_set_blacklist(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT,
IOT_PLC_BL_DEL, 1, sta_glb->cco_bl[i].addr);
os_mem_set(sta_glb->cco_bl[i].addr, 0x0, IOT_MAC_ADDR_LEN);
}
out:
return;
}
static uint8_t iot_sg_sta_node_query_finish_check(void)
{
uint8_t ret = ERR_FAIL;
uint32_t interval;
uint64_t curr_ts;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!sta_glb->node_reg.node_reg_on) {
if (p_sg_glb->plc_state.link_ready
&& sta_glb->node_reg.last_node_reg_ts) {
curr_ts = os_boot_time64();
interval = (uint32_t)((curr_ts -
sta_glb->node_reg.last_node_reg_ts) / (60 * 1000));
if (interval >= IOT_SG_STA_LAST_NODE_REG_RESULT_INTERVAL) {
ret = ERR_OK;
}
} else {
ret = ERR_OK;
}
}
return ret;
}
static void iot_sg_sta_login_addr_check(void)
{
uint8_t addr[IOT_MAC_ADDR_LEN];
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_mac_addr_cpy(addr, p_sg_glb->plc_state.addr);
iot_mac_addr_reverse(addr);
if ((sta_glb->addr_type == IOT_SG_STA_DRV_ADDR_TYPE_METER)
&& iot_mac_addr_valid(addr)
&& (iot_sg_sta_node_addr_check(addr) == ERR_NOT_EXIST)
&& iot_sg_sta_node_query_finish_check() == ERR_OK) {
iot_sg_printf("%s fail, sys restart\n", __FUNCTION__);
os_delay(100);
iot_system_restart(IOT_SYS_RST_REASON_APP_REQ);
}
}
static void iot_sg_sta_refresh_timeout_handle(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint32_t dev_type = sta_glb->drv->get_device_type();
iot_sg_sta_ext_ai_topo_func();
iot_sg_sta_ext_ai_ll_func();
iot_sg_sta_pull_out_check();
iot_sg_sta_get_pm_time();
iot_sg_sta_tsfm_repeat();
iot_sg_sta_plc_query_neig_timeout();
iot_sg_sta_ext_fj_freeze_refresh();
iot_sg_sta_ext_auto_tm_update();
iot_sg_sta_ext_nli_rpt_refresh();
iot_sg_sta_ext_mf_refresh();
iot_sg_sta_ext_gw_rpt_unit_timeout_hande();
iot_sg_ext_ec_refresh_func();
if (sta_glb->soft_record_state) {
sta_glb->soft_record_cnt++;
if (sta_glb->soft_record_cnt >= IOT_SG_STA_SOFT_RECOR_MODE_DUR) {
sta_glb->soft_record_state = 0;
sta_glb->soft_record_cnt = 0;
iot_sg_printf("soft_record_state %d\n", sta_glb->soft_record_state);
}
}
if ((dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T1 ||
dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T2) &&
(sta_glb->poll_cnt & 0x02) && sta_glb->addr_list_change) {
iot_sg_sta_set_pm_addr();
}
if (sta_glb->poll_cnt < IOT_SG_STA_POLL_DUR) {
sta_glb->poll_cnt++;
return;
}
iot_sg_sta_login_addr_check();
sta_glb->poll_cnt = 0;
iot_sg_sta_refresh_bl();
iot_sg_sta_invalid_addr_refresh();
sta_glb->debug_cnt++;
if (sta_glb->debug_cnt >= IOT_SG_STA_DEBUG_INFO_DUR) {
iot_sg_sta_print_log_to_flash();
iot_sg_sta_tsfm_topo_bitmap_dump();
sta_glb->debug_cnt = 0;
}
iot_sg_sta_node_in_neig_state_query();
if (p_sg_glb->plc_state.link_ready) {
iot_plc_query_neighbor_dev(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, p_sg_glb->plc_state.pco_tei, 1,
IOT_PLC_QUERY_TOPO_START_AS_TEI);
}
sta_glb->sta_time_cnt++;
if (sta_glb->sta_time_cnt >= IOT_SG_STA_TM_CORRECT_CLEAR_CNT_PERIOD) {
sta_glb->correct_time_cnt = 0;
sta_glb->sta_time_cnt = 0;
}
iot_plc_query_tsfm_status(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT);
iot_sg_sta_refresh_cco_bl();
}
void iot_sg_module_report_reset_status(uint8_t is_timeout)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
if (evt->event_rpt_on) {
drv->enable_event_rpt();
}
if (!is_timeout) {
evt->retry_cnt = 0;
}
evt->rpt_type = IOT_SG_STA_RPT_METER_NORMAL_EVT;
}
void iot_sg_sta_module_report_re_enable()
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
iot_sg_sta_evt_global_t *evt_glb = &sta_glb->evt;
/* Only when event report is enabled and the current report type
* is normal(instead of phase, score and clock), need to re-enable
* report to update the report parameters, reason as bellow:
* 1. if event report is not enabled, need not set paramter immediately,
* because it will be set when enable event report;
* 2. if report type is not normal(it is phase, score or clock),
* disable_event_rpt() has been called before, and enable_event_rpt()
* will be called as report type reset to normal.
*/
if (evt_glb->event_rpt_on &&
evt_glb->rpt_type == IOT_SG_STA_RPT_METER_NORMAL_EVT) {
drv->disable_event_rpt();
drv->enable_event_rpt();
iot_sg_printf("%s re-enable event report\n", __FUNCTION__);
}
}
static uint32_t iot_sg_sta_report_event_dur_get(uint8_t *addr, uint8_t rpt_type)
{
uint32_t dur;
uint8_t user_type = iot_sg_sta_get_user_type();
iot_sg_sta_node_desc_t *node;
dur = (os_rand() % (IOT_SG_STA_EVENT_RPT_DUR_MAX - \
IOT_SG_STA_EVENT_RPT_DUR_MIN)) + IOT_SG_STA_POWERON_RPT_DUR_MIN;
if (rpt_type != IOT_SG_STA_RPT_METER_NORMAL_EVT) {
goto out;
}
node = iot_sg_sta_node_find_by_addr(addr);
if (!node) {
goto out;
}
if (user_type == USER_TYPE_STATE_GRID_CQ &&
node->data_type == IOT_SG_STA_DATA_TYPE_69845) {
dur = IOT_SG_STA_69845_METER_EVENT_RPT_DUR_CQ;
} else if (user_type == USER_TYPE_STATE_GRID_TAIYUAN) {
dur = IOT_SG_STA_EVENT_RPT_DUR_TAIYUAN;
goto out;
}
out:
return dur;
}
uint32_t iot_sg_sta_report_event_with_type(uint8_t *addr,
uint8_t *data_ptr, uint32_t len, uint8_t new_evt, uint8_t rpt_type)
{
uint8_t reason = 0;
uint32_t ret = ERR_OK, dur;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->evt.event_rpt_pending) {
reason = 1;
ret = ERR_BUSY;
goto out;
}
if (sta_glb->evt.pt_detected && !p_sg_glb->plc_state.cert_test_detected) {
if (os_boot_time32() < IOT_SG_STA_PT_DETECT_VALID_TIME) {
reason = 2;
ret = ERR_BUSY;
goto out;
} else {
sta_glb->evt.pt_detected = 0;
}
}
if (sta_glb->evt.event_rpt_on == 0) {
reason = 3;
ret = ERR_FAIL;
goto out;
}
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_event_send(addr, data_ptr, len,
new_evt, rpt_type);
} else {
ret = iot_sg_sta_nw_event_send(addr, data_ptr, len, new_evt, rpt_type);
}
if (ret) {
reason = 4;
goto out;
}
sta_glb->evt.rpt_type = rpt_type;
sta_glb->evt.event_rpt_pending = 1;
dur = iot_sg_sta_report_event_dur_get(addr, rpt_type);
os_start_timer(sta_glb->event_rpt_timer, dur);
out:
iot_sg_printf("%s result %lu reason %lu\n", __FUNCTION__, ret, reason);
return ret;
}
void iot_sg_sta_clock_skew_report(uint8_t new_evt, int64_t interval)
{
uint32_t ret;
uint8_t length, addr[IOT_MAC_ADDR_LEN];
iot_pkt_t *pkt = NULL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
iot_time_tm_t time = { 0 };
proto_645_07_clock_skew_t *clock_skew;
proto_645_header_t *hdr = NULL;
if (evt->retry_cnt >= 3) {
iot_sg_printf("%s retry end, cnt %d", __FUNCTION__, evt->retry_cnt);
iot_sg_module_report_reset_status(0);
goto out;
}
if (interval == 0) {
goto out;
}
length = sizeof(proto_645_header_t) + sizeof(proto_645_tailer_t) +
sizeof(*clock_skew);
pkt = iot_pkt_alloc(length, IOT_SMART_GRID_MID);
if (!pkt) {
goto out;
}
sta_glb->drv->get_login_addr(addr);
hdr = (proto_645_header_t *)iot_pkt_data(pkt);
proto_645_header_init(hdr, addr, PROTO_645_2007_FN_CLOCK_SKEW,
PROTO_645_DIR_SLAVE, PROTO_645_ACK_NORMAL, PROTO_645_FOLLOW_INVALID);
hdr->len = sizeof(*clock_skew);
clock_skew = (proto_645_07_clock_skew_t *)hdr->data;
if (interval > 0) {
clock_skew->mode = PROTO_645_CS_MODE_METER_BELOW_CCTT;
} else {
clock_skew->mode = PROTO_645_CS_MODE_METER_ABOVE_CCTT;
}
time.tm_year = 2000;
time.tm_mon = 1;
time.tm_mday = 1;
iot_rtc_delta_add(IOT_ABS(interval), &time);
clock_skew->time.year = iot_byte_to_bcd((uint8_t)(time.tm_year - 2000));
clock_skew->time.month = iot_byte_to_bcd(time.tm_mon - 1);
clock_skew->time.day = iot_byte_to_bcd(time.tm_mday - 1);
clock_skew->time.hour = iot_byte_to_bcd(time.tm_hour);
clock_skew->time.minute = iot_byte_to_bcd(time.tm_min);
clock_skew->time.second = iot_byte_to_bcd(time.tm_sec);
proto_645_add33_handle(hdr->data, hdr->len);
/* fill in 645 tailer */
proto_645_tail_init(hdr);
iot_pkt_put(pkt, length);
ret = iot_sg_sta_report_event_with_type(addr, (uint8_t *)hdr, length,
new_evt, IOT_SG_STA_RPT_MODULE_CLOCK_EVT);
if (ret == ERR_OK) {
sta_glb->drv->disable_event_rpt();
evt->clock_interval = interval;
evt->retry_cnt++;
}
out:
if (pkt) {
iot_pkt_free(pkt);
}
return;
}
static void iot_sg_sta_report_phase_event(uint8_t phase_info, uint8_t new_evt)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_phase_seq_status_cache_info_t cache_phase;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
iot_sg_sta_drv_t *drv = sta_glb->drv;
uint32_t length;
uint32_t ret = ERR_OK;
if (!iot_sg_sta_phase_rpt_enable_check()) {
evt->retry_cnt = 3;
}
if (evt->retry_cnt >= 3) {
iot_sg_printf("%s retry max\n", __FUNCTION__);
iot_sg_module_report_reset_status(0);
goto out;
}
length = sizeof(cache_phase);
cache_phase.evt_type = GW_APP_EVENT_TYPE_PHASE_SEQUENCE;
drv->get_login_addr(cache_phase.pm_addr);
if (phase_info == 0) {
cache_phase.phase_seq_status =
GW_APP_PHASE_SEQ_STAUS_NORMAL;
} else {
cache_phase.phase_seq_status =
GW_APP_PHASE_SEQ_STAUS_ABNORMAL;
}
ret = iot_sg_sta_report_event_with_type(cache_phase.pm_addr,
(uint8_t *)&cache_phase, length, new_evt,
IOT_SG_STA_RPT_MODULE_PHASE_EVT);
if (ret == ERR_OK) {
drv->disable_event_rpt();
evt->retry_cnt++;
}
out:
return;
}
static void iot_sg_sta_phase_event_func_handle(uint8_t fn)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
switch (fn) {
case IOT_SG_STA_EVENT_RPT_OK:
{
evt->his_abn_ps = evt->abn_ps;
/* phase event report success, report status reset */
}
case IOT_SG_STA_EVENT_RPT_DISABLED:
{
iot_sg_module_report_reset_status(0);
break;
}
case IOT_SG_STA_EVENT_RPT_BUF_FULL:
case IOT_SG_STA_EVENT_RPT_TIMEOUT:
{
iot_sg_module_report_reset_status(1);
iot_sg_sta_report_phase_event(evt->abn_ps, 0);
break;
}
default:
IOT_ASSERT(0);
}
}
static void iot_sg_sta_clock_event_func_handle(uint8_t fn)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
switch (fn) {
case IOT_SG_STA_EVENT_RPT_OK:
case IOT_SG_STA_EVENT_RPT_DISABLED:
{
sta_glb->evt.clock_interval = 0;
iot_sg_module_report_reset_status(0);
break;
}
case IOT_SG_STA_EVENT_RPT_BUF_FULL:
case IOT_SG_STA_EVENT_RPT_TIMEOUT:
{
iot_sg_module_report_reset_status(1);
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_HLJ) {
iot_sg_sta_ext_clock_skew_report_hlj(0, sta_glb->evt.clock_interval);
} else if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_HUNAN) {
iot_sg_sta_ext_clock_skew_report_hn(0, sta_glb->evt.clock_interval);
}
break;
}
default:
IOT_ASSERT(0);
}
}
static void iot_sg_sta_event_func_handle(uint8_t fn)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
switch (evt->rpt_type) {
case IOT_SG_STA_RPT_METER_NORMAL_EVT:
{
drv->event_rpt_ack(fn);
break;
}
case IOT_SG_STA_RPT_MODULE_PHASE_EVT:
{
iot_sg_sta_phase_event_func_handle(fn);
break;
}
case IOT_SG_STA_RPT_MODULE_SCORE_EVT:
{
iot_sg_sta_nw_score_event_func_handle(fn);
break;
}
case IOT_SG_STA_RPT_MODULE_CLOCK_EVT:
{
iot_sg_sta_clock_event_func_handle(fn);
break;
}
default:
break;
}
}
uint32_t iot_sg_sta_event_ack_handle(uint8_t fn)
{
uint32_t ret = ERR_OK;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
switch (fn) {
case IOT_SG_STA_EVENT_RPT_ENABLED:
{
if (sta_glb->evt.event_rpt_on == 0) {
sta_glb->evt.event_rpt_on = 1;
drv->enable_event_rpt();
}
break;
}
case IOT_SG_STA_EVENT_RPT_DISABLED:
{
if (sta_glb->evt.event_rpt_on) {
if (sta_glb->evt.event_rpt_pending) {
os_stop_timer(sta_glb->event_rpt_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_EVENT_RPT);
sta_glb->evt.event_rpt_pending = 0;
iot_sg_sta_event_func_handle(fn);
}
sta_glb->evt.event_rpt_on = 0;
drv->disable_event_rpt();
}
break;
}
case IOT_SG_STA_EVENT_RPT_OK:
case IOT_SG_STA_EVENT_RPT_BUF_FULL:
{
if (sta_glb->evt.event_rpt_pending) {
os_stop_timer(sta_glb->event_rpt_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_EVENT_RPT);
sta_glb->evt.event_rpt_pending = 0;
iot_sg_sta_event_func_handle(fn);
}
break;
}
case IOT_SG_STA_EVENT_RPT_TIMEOUT:
{
if (sta_glb->evt.event_rpt_pending) {
sta_glb->evt.event_rpt_pending = 0;
iot_sg_sta_event_func_handle(fn);
}
break;
}
default:
ret = ERR_NOSUPP;
break;
}
return ret;
}
void iot_sg_sta_handle_msdu_msg(iot_pkt_t *pkt, iot_plc_msdu_recv_t *msdu)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_pkt_set_data(pkt, msdu->data);
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
iot_sg_sta_gw_msg_handle(pkt, msdu->data);
} else {
iot_sg_sta_nw_msg_handle(pkt, msdu->data);
}
}
static void iot_sg_sta_conn_less_msg_handle(iot_pkt_t *pkt,
uint8_t link_type)
{
iot_pkt_pull(pkt, sizeof(iot_plc_msg_header_t)
+ sizeof(iot_plc_msdu_recv_t));
iot_sg_sta_queue_app_other(pkt, link_type);
return;
}
static void iot_sg_sta_ctrl_proto_msg_handle(iot_pkt_t *pkt)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
iot_sg_sta_gw_ctrl_proto_msg_handle(pkt);
} else {
iot_sg_sta_nw_ctrl_proto_msg_handle(pkt);
}
}
static void iot_sg_sta_save_three_phase_info()
{
uint8_t ref;
uint16_t ticket;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (!sta_pib->is_three_phase) {
iot_pib_acquire_app_commit_ref(&ref);
sta_pib->is_three_phase = 1;
iot_pib_release_app_commit_ref(&ref);
iot_pib_app_commit(&ticket);
}
}
static void iot_sg_sta_tsfm_status_rpt(iot_pkt_t *pkt)
{
uint8_t abn_ps = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
iot_plc_tsfm_status_rpt_t *rpt;
rpt = (iot_plc_tsfm_status_rpt_t *)(iot_pkt_data(pkt) +
sizeof(iot_plc_msg_header_t));
os_mem_cpy(&sta_glb->tsfm_status, rpt, sizeof(*rpt));
if (p_sg_glb->module_type == MODULE_TYPE_STA && IOT_SMART_GRID_3P_CHECK &&
(rpt->phy_phase_2_valid || rpt->phy_phase_3_valid)) {
/* number of data two phase or three phase is greater than zero
* module type is three-phase.
*/
iot_sg_sta_save_three_phase_info();
p_sg_glb->module_type = MODULE_TYPE_3_PHASE_STA;
}
if (drv && (drv->dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T3) &&
(IOT_BRM_DEVADP_ENABLE == 0)) {
if (!rpt->phy_phase_1_valid || !rpt->phy_phase_2_valid
|| !rpt->phy_phase_3_valid) {
abn_ps |= 0x01;
}
if (rpt->opposite_3p) {
abn_ps |= 0x04;
}
/* when abn_ps change phase event report,
* abn_ps is 0 normal others are abnormal.
*/
if ((evt->his_zc_status_sn != rpt->zc_status_sn ||
evt->his_abn_ps != abn_ps) && !evt->event_rpt_pending) {
iot_sg_printf("%s abn sn %lu\n", __FUNCTION__, abn_ps);
evt->his_zc_status_sn = sta_glb->tsfm_status.zc_status_sn;
evt->abn_ps = abn_ps;
iot_sg_sta_report_phase_event(evt->abn_ps, 1);
}
}
iot_pkt_free(pkt);
}
static void iot_sg_sta_zc_clct_rpt_handle(uint8_t seq,
iot_plc_zc_collect_rpt_t *rpt)
{
uint32_t reason;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_tsfm_collect_info_t *collect = &sta_glb->tsfm_collect_info;
if (collect->feature_type != GW_APP_TSFM_FEATURE_PERIOD) {
reason = 1;
goto drop;
}
if (collect->seq != seq) {
reason = 2;
goto drop;
}
if (rpt->result != ERR_OK) {
reason = 3;
iot_sg_sta_tsfm_collect_stop();
goto drop;
}
if (collect->data) {
iot_pkt_free(collect->data);
}
collect->data = iot_pkt_alloc(rpt->len, IOT_SMART_GRID_MID);
if (collect->data == NULL) {
reason = 4;
goto drop;
}
iot_pkt_put(collect->data, rpt->len);
os_mem_cpy(iot_pkt_data(collect->data), rpt->data, rpt->len);
collect->collected_cnt = (uint8_t)rpt->clct_cnt;
collect->clct_type = rpt->clct_type;
goto out;
drop:
iot_sg_printf("%s seq %lu err %lu\n", __FUNCTION__, seq, reason);
out:
return;
}
static void iot_sg_sta_neighbor_dev_rpt_handle(
iot_plc_neighbor_dev_rpt_t *rpt, uint16_t req_id)
{
iot_sg_plc_state_t *plc_state = &p_sg_glb->plc_state;
switch (req_id) {
case IOT_SG_STA_QUERY_NEIG_NODE_FROM_PLC:
{
iot_sg_sta_query_neig_resp_from_plc(rpt);
break;
}
case IOT_SG_STA_QUERY_NEIG_NODE_FROM_STA:
{
iot_sg_sta_query_neig_resp_from_sta(rpt);
break;
}
default:
if (rpt->cnt && plc_state->link_ready) {
plc_state->snr = rpt->node[0].snr;
}
break;
}
return;
}
static void iot_sg_sta_meter_read_id_info_handle(uint8_t id_type, uint8_t *addr)
{
iot_pkt_t *pkt;
iot_sg_plc_state_t *plc_state = &p_sg_glb->plc_state;
if (id_type != PROTO_645_2007_EXT_NW_VER_ID) {
iot_mac_addr_cpy(addr, plc_state->addr);
iot_mac_addr_reverse(addr);
}
pkt = proto_645_vendor_build_id_info(addr, id_type);
if (pkt) {
iot_sg_sta_software_record_uart_send(pkt);
}
}
static void iot_sg_sta_meter_read_band_switch_handle()
{
iot_pkt_t *pkt;
pkt = proto_645_build_band_switch_rsp(switch_band_mac);
if (pkt) {
iot_sg_sta_send_uart(pkt);
}
}
static void iot_sg_sta_meter_br_test_handle(proto_645_header_t *hdr)
{
iot_pkt_t *pkt;
proto_645_sub33_handle(hdr->data, hdr->len);
pkt = proto_645_vendor_handle_br_test_req(hdr,
PROTO_645_2007_EXT_DI_BR_TEST);
if (pkt) {
iot_sg_sta_send_uart(pkt);
}
}
static uint32_t iot_sg_sta_software_record_uart_send(iot_pkt_t *pkt)
{
iot_sg_data_print("<--sr uart send--", iot_pkt_data(pkt),
iot_pkt_data_len(pkt));
#if IOT_SG_EXT_SDK_ENABLE
uint8_t arg = 0;
IOT_SG_EXT_UART_FULL_FRAME_SET(arg);
return iot_sg_ext_send_to_cusapp(pkt, arg);
#else
return iot_uart_send(p_sg_glb->uart_h, pkt, NULL);
#endif
}
#if IOT_GW_APP_ENABLE
static void iot_sg_sta_software_record_handle(proto_645_header_t *hdr_645,
uint32_t di)
{
uint8_t check_code[IOT_SG_SHA1_CHECK_CODE_LEN];
uint32_t check_addr, check_code_ret;
iot_pkt_t *pkt = NULL;
proto_645_07_ext_sha1_check_code_req_t *check_code_req;
if (!hdr_645) {
goto out;
}
switch (di) {
case PROTO_645_2007_EXT_HUNAN_BASIC_INFO_READ:
case PROTO_645_2007_EXT_BJ_BASIC_INFO_READ:
{
pkt = proto_645_vendor_build_basic_info(hdr_645->addr, di);
break;
}
case PROTO_645_2007_EXT_HUNAN_CHECK_CODE_READ:
case PROTO_645_2007_EXT_BJ_CHECK_CODE_READ:
{
if ((hdr_645->len - PROTO_645_2007_DI_LEN) <
sizeof(*check_code_req)) {
goto nack;
}
proto_645_sub33_handle(hdr_645->data, hdr_645->len);
check_code_req = (proto_645_07_ext_sha1_check_code_req_t *)(
hdr_645->data + PROTO_645_2007_DI_LEN);
check_addr = iot_bytes_to_uint32(check_code_req->check_addr, 0);
check_code_ret = iot_sg_get_fw_sha1_value(check_code,
IOT_SG_SHA1_CHECK_CODE_LEN, check_addr, check_code_req->check_len);
if (check_code_ret == ERR_OK) {
pkt = proto_645_vendor_build_check_code(check_code,
sizeof(check_code), hdr_645->addr, di);
} else if (check_code_ret == ERR_NOMEM) {
goto out;
} else {
goto nack;
}
break;
}
default:
goto nack;
}
goto out;
nack:
pkt = proto_645_2007_build_nack_msg(PROTO_645_2007_ERR_OTHER,
hdr_645->addr, PROTO_645_2007_FN_READ_DATA);
out:
if (pkt) {
iot_sg_sta_software_record_uart_send(pkt);
}
return;
}
#endif
#if (IOT_SMART_GRID_ZH_FTM_CMD_ENABLE)
static uint32_t iot_sg_sta_write_mac_info_handle(proto_645_header_t *hdr_645)
{
iot_pkt_t *pkt;
uint32_t ret = ERR_FAIL;
uint8_t mac[IOT_MAC_ADDR_LEN];
uint8_t user_type = iot_sg_sta_get_user_type();
uint16_t vendor_id = iot_sg_get_vendor_id();
proto_645_ext_mac_and_ver_info_t *mac_and_ver;
if (!IOT_SG_STA_VENDOR_ID_IS_ZH(vendor_id) ||
(user_type != USER_TYPE_STATE_GRID_MENGXI)) {
goto out;
}
if (hdr_645->len < sizeof(*mac_and_ver) + PROTO_645_2007_DI_LEN) {
goto out;
}
mac_and_ver = (proto_645_ext_mac_and_ver_info_t *)(hdr_645->data +
PROTO_645_2007_DI_LEN);
iot_oem_get_module_mac(mac);
if (!iot_mac_addr_cmp(mac, mac_and_ver->mac)) {
iot_oem_set_module_mac(mac_and_ver->mac);
}
pkt = proto_645_vendor_build_mac_and_ver_info(hdr_645->addr,
PROTO_645_2007_FN_WRITE_DATA);
if (pkt) {
iot_sg_sta_send_uart(pkt);
ret = ERR_OK;
}
out:
return ret;
}
#else /* IOT_SMART_GRID_ZH_FTM_CMD_ENABLE */
static uint32_t iot_sg_sta_write_mac_info_handle(proto_645_header_t *hdr_645)
{
(void)hdr_645;
return ERR_NOSUPP;
}
#endif /* IOT_SMART_GRID_ZH_FTM_CMD_ENABLE */
static void iot_sg_sta_write_passcode_handle(proto_645_header_t *hdr_645)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_plc_cfg_set_req_t cfg;
proto_645_ext_write_passcode_dl_t *passcode_dl;
iot_pkt_t *pkt = NULL;
if (!hdr_645) {
goto out;
}
if (hdr_645->control.dir != PROTO_645_DIR_MASTER) {
goto nack;
}
if (hdr_645->len - PROTO_645_2007_DI_LEN < sizeof(*passcode_dl)) {
goto nack;
}
pkt = proto_645_2007_build_w_rsp(hdr_645->addr);
proto_645_sub33_handle(hdr_645->data, hdr_645->len);
passcode_dl = (proto_645_ext_write_passcode_dl_t *)(hdr_645->data +
PROTO_645_2007_DI_LEN);
if (sta_glb->passcode != passcode_dl->passcode) {
os_mem_set(&cfg, 0, sizeof(cfg));
cfg.passcode_valid = 1;
cfg.passcode = passcode_dl->passcode;
cfg.reset = 1;
sta_glb->passcode = passcode_dl->passcode;
iot_plc_set_cfg(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT, &cfg);
}
goto out;
nack:
pkt = proto_645_2007_build_nack_msg(PROTO_645_2007_ERR_OTHER, hdr_645->addr,
PROTO_645_2007_FN_WRITE_DATA);
out:
if (pkt) {
iot_sg_sta_software_record_uart_send(pkt);
}
return;
}
static void iot_sg_sta_read_passcode_handle(proto_645_header_t *hdr_645)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_pkt_t *pkt = NULL;
if (!hdr_645) {
goto out;
}
if (hdr_645->control.dir != PROTO_645_DIR_MASTER) {
goto nack;
}
pkt = proto_645_2007_build_mr_rsp(hdr_645->addr,
PROTO_645_2007_EXT_PASSCODE_REQ, (uint8_t *)&sta_glb->passcode,
sizeof(sta_glb->passcode), 0);
goto out;
nack:
pkt = proto_645_2007_build_nack_msg(PROTO_645_2007_ERR_OTHER, hdr_645->addr,
PROTO_645_2007_FN_READ_DATA);
out:
if (pkt) {
iot_sg_sta_software_record_uart_send(pkt);
}
return;
}
static void iot_sg_sta_ftm_uart_command_handle(proto_645_header_t *hdr_645)
{
uint8_t *command, switch_to_ftm = 0;
iot_pkt_t *pkt = NULL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!hdr_645) {
goto out;
}
if (hdr_645->control.dir != PROTO_645_DIR_MASTER) {
goto nack;
}
if (hdr_645->len - PROTO_645_2007_DI_LEN < sizeof(*command)) {
goto nack;
}
proto_645_sub33_handle(hdr_645->data, hdr_645->len);
command = hdr_645->data + PROTO_645_2007_DI_LEN;
if (*command == PROTO_646_EXT_FTM_UART_CMD_FIX_BAUD) {
sta_glb->soft_record_state = 1;
sta_glb->soft_record_cnt = 0;
} else if (*command == PROTO_646_EXT_FTM_UART_CMD_SWITCH_FTM_MODE) {
switch_to_ftm = 1;
} else {
goto nack;
}
pkt = proto_645_2007_build_mr_rsp(hdr_645->addr,
PROTO_645_2007_EXT_DI_FTM_UART_COMMMAND, NULL, 0, 0);
goto out;
nack:
pkt = proto_645_2007_build_nack_msg(PROTO_645_2007_ERR_OTHER, hdr_645->addr,
PROTO_645_2007_FN_READ_DATA);
out:
if (pkt) {
iot_sg_sta_software_record_uart_send(pkt);
if (switch_to_ftm) {
os_delay(500);
iot_system_restart(IOT_SYS_RST_REASON_FTM);
}
}
return;
}
#if (IOT_SMART_GRID_ZH_FTM_CMD_ENABLE)
iot_pkt_t *iot_sg_sta_uart_set_id_info_handle(proto_645_header_t *hdr_645)
{
uint8_t set_id = 0;
uint8_t user_type = iot_sg_sta_get_user_type();
uint8_t addr[IOT_MAC_ADDR_LEN], buff[PROTO_645_2007_EXT_CHIP_MMID_ID_LEN];
uint16_t vendor_id = iot_sg_get_vendor_id();
iot_pkt_t *pkt = NULL;
proto_645_ext_set_id_info_req_t *req;
iot_sg_plc_state_t *plc_state = &p_sg_glb->plc_state;
iot_oem_base_cfg_t *base_cfg = NULL;
if (!IOT_SG_STA_VENDOR_ID_IS_ZH(vendor_id) ||
(user_type != USER_TYPE_STATE_GRID_MENGXI)) {
goto out;
}
if (hdr_645->len < sizeof(*req)) {
goto out;
}
req = (proto_645_ext_set_id_info_req_t *)hdr_645->data;
if (req->id_type == PROTO_645_2007_EXT_CHIP_ID) {
if (req->data_len != PROTO_645_2007_EXT_CHIP_MMID_ID_LEN) {
goto out;
}
iot_oem_get_chip_mmid(buff, PROTO_645_2007_EXT_CHIP_MMID_ID_LEN);
} else if (req->id_type == PROTO_645_2007_EXT_MODULE_ID) {
if (req->data_len != PROTO_645_2007_EXT_DEVICE_ID_LEN) {
goto out;
}
iot_oem_get_base_cfg(&base_cfg);
os_mem_cpy(buff, base_cfg->dev_id, PROTO_645_2007_EXT_DEVICE_ID_LEN);
} else {
goto out;
}
if (os_mem_cmp(buff, req->data, req->data_len) != 0) {
set_id = 1;
}
if (set_id) {
proto_645_vendor_set_id_info(req, 1);
}
iot_mac_addr_cpy(addr, plc_state->addr);
iot_mac_addr_reverse(addr);
pkt = proto_645_vendor_build_id_info(addr, req->id_type);
out:
return pkt;
}
#else /* IOT_SMART_GRID_ZH_FTM_CMD_ENABLE */
iot_pkt_t *iot_sg_sta_uart_set_id_info_handle(proto_645_header_t *hdr_645)
{
(void)hdr_645;
return NULL;
}
#endif /* IOT_SMART_GRID_ZH_FTM_CMD_ENABLE */
static uint32_t iot_sg_sta_uart_data_handle(uint8_t *data, uint32_t len)
{
uint8_t buf_addr[IOT_MAC_ADDR_LEN], fn, *band = NULL;
uint32_t ret = ERR_INVAL, di;
iot_sg_plc_state_t *plc_state = &p_sg_glb->plc_state;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
proto_645_header_t *hdr_645;
iot_pkt_t *pkt = NULL;
hdr_645 = proto_645_format_check(data, len, PROTO_645_DIR_MASTER);
if (!hdr_645) {
goto out;
}
iot_mac_addr_cpy(buf_addr, hdr_645->addr);
iot_mac_addr_reverse(buf_addr);
switch (hdr_645->control.fn) {
case PROTO_645_2007_FN_WRITE_DATA:
{
if (!iot_mac_addr_cmp(proto_645_any_addr, buf_addr) &&
!iot_mac_addr_cmp(plc_state->addr, buf_addr)) {
goto out;
}
if (proto_645_get_di(data, len, PROTO_645_DIR_MASTER, &di, &fn)) {
goto out;
}
switch (di) {
case PROTO_645_2007_EXT_PASSCODE_REQ:
{
iot_sg_sta_write_passcode_handle(hdr_645);
ret = ERR_OK;
break;
}
case PROTO_645_2007_READ_NW_VER:
{
ret = iot_sg_sta_write_mac_info_handle(hdr_645);
break;
}
default:
break;
}
break;
}
case PROTO_645_2007_FN_READ_DATA:
{
if (!iot_mac_addr_cmp(proto_645_any_addr, buf_addr) &&
!iot_mac_addr_cmp(plc_state->addr, buf_addr)) {
goto out;
}
if (proto_645_get_di(data, len, PROTO_645_DIR_MASTER, &di, &fn)) {
goto out;
}
switch (di) {
case PROTO_645_2007_EXT_DI_READ_VER:
{
iot_sg_sta_meter_read_id_info_handle(PROTO_645_2007_EXT_VER_ID,
hdr_645->addr);
ret = ERR_OK;
break;
}
case PROTO_645_2007_EXT_DI_READ_VER_2:
{
iot_sg_sta_meter_read_id_info_handle(PROTO_645_2007_EXT_VER2_ID,
hdr_645->addr);
ret = ERR_OK;
break;
}
case PROTO_645_2007_READ_NW_VER:
{
iot_sg_sta_meter_read_id_info_handle(PROTO_645_2007_EXT_NW_VER_ID,
hdr_645->addr);
ret = ERR_OK;
break;
}
#if IOT_GW_APP_ENABLE
case PROTO_645_2007_EXT_HUNAN_BASIC_INFO_READ:
case PROTO_645_2007_EXT_HUNAN_CHECK_CODE_READ:
{
if (iot_sg_sta_get_user_type() != USER_TYPE_STATE_GRID_HUNAN &&
iot_sg_sta_get_user_type() != USER_TYPE_STATE_GRID_CQ) {
goto out;
}
sta_glb->soft_record_state = 1;
sta_glb->soft_record_cnt = 0;
iot_sg_sta_software_record_handle(hdr_645, di);
ret = ERR_OK;
break;
}
case PROTO_645_2007_EXT_BJ_BASIC_INFO_READ:
case PROTO_645_2007_EXT_BJ_CHECK_CODE_READ:
{
if (iot_sg_sta_get_user_type() != USER_TYPE_STATE_GRID_BJ) {
goto out;
}
sta_glb->soft_record_state = 1;
sta_glb->soft_record_cnt = 0;
iot_sg_sta_software_record_handle(hdr_645, di);
ret = ERR_OK;
break;
}
#endif
case PROTO_645_2007_EXT_PASSCODE_REQ:
{
iot_sg_sta_read_passcode_handle(hdr_645);
ret = ERR_OK;
break;
}
case PROTO_645_2007_EXT_DI_FTM_UART_COMMMAND:
{
iot_sg_sta_ftm_uart_command_handle(hdr_645);
ret = ERR_OK;
break;
}
case PROTO_645_2007_EXT_DI_NODE_IN_NEIG:
{
ret = iot_sg_sta_node_in_neig_uart_query_handle(hdr_645);
break;
}
default:
break;
}
break;
}
case PROTO_645_2007_FN_BAND_SWITCH:
{
if (!iot_mac_addr_cmp(hdr_645->addr, switch_band_mac)) {
goto out;
}
if (proto_645_get_di(data, len, PROTO_645_DIR_MASTER, &di, &fn)) {
goto out;
}
if (di != PROTO_645_2007_DI_BAND_SWITCH) {
goto out;
}
if (hdr_645->len < (PROTO_645_2007_DI_LEN + sizeof(*band))) {
goto out;
}
proto_645_sub33_handle(hdr_645->data, hdr_645->len);
band = hdr_645->data + PROTO_645_2007_DI_LEN;
iot_sg_sta_meter_read_band_switch_handle();
iot_sg_printf("%s switch band %lu\n", __FUNCTION__, *band);
ret = ERR_OK;
break;
}
case PROTO_645_2007_EXT_FN_QUERY_ID:
{
if (!iot_mac_addr_cmp(proto_645_any_addr, buf_addr) &&
!iot_mac_addr_cmp(plc_state->addr, buf_addr)) {
goto out;
}
if (!hdr_645->len) {
goto out;
}
#if IOT_NW_APP_ENABLE
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW &&
os_boot_time64() < IOT_SG_STA_FACTORY_TIME_MAX) {
pkt = proto_645_vendor_sta_nw_ext_uart_cmd_handle(hdr_645);
if (pkt) {
iot_sg_sta_software_record_uart_send(pkt);
ret = ERR_OK;
break;
}
}
#endif
if (hdr_645->len == PROTO_645_EXT_QUERY_ID_DATA_LEN) {
iot_sg_sta_meter_read_id_info_handle(hdr_645->data[0],
hdr_645->addr);
ret = ERR_OK;
} else if (hdr_645->len == PROTO_645_2007_DI_LEN) {
if (proto_645_get_di(data, len, PROTO_645_DIR_MASTER, &di, &fn)) {
goto out;
}
if (di != PROTO_645_2007_EXT_DI_TCZ_READ_VER) {
goto out;
}
pkt = proto_645_vendor_build_tcz_ver_info(hdr_645->addr);
if (pkt) {
iot_sg_sta_send_uart(pkt);
ret = ERR_OK;
break;
}
} else {
pkt = iot_sg_sta_uart_set_id_info_handle(hdr_645);
if (pkt) {
iot_sg_sta_send_uart(pkt);
ret = ERR_OK;
break;
}
}
break;
}
case PROTO_645_2007_EXT_FN_BR:
{
if (!iot_mac_addr_cmp(proto_645_any_addr, buf_addr) &&
!iot_mac_addr_cmp(plc_state->addr, buf_addr)) {
goto out;
}
if (proto_645_get_di(data, len, PROTO_645_DIR_MASTER, &di, &fn)) {
goto out;
}
if (di != PROTO_645_2007_EXT_DI_BR_TEST) {
goto out;
}
iot_sg_sta_meter_br_test_handle(hdr_645);
ret = ERR_OK;
break;
}
default:
break;
}
out:
return ret;
}
static void iot_sg_sta_3p_zc_state_clear(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
sta_glb->node_properties.opposite_3p = 0;
sta_glb->node_properties.opposite_3p_pos = 0;
sta_glb->node_properties.logic_phase = 0;
sta_glb->node_properties.zc_repeat_3p = 0;
}
static void iot_sg_sta_rtc_update_rpt(iot_pkt_t *pkt)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_plc_rtc_update_rpt_t *rpt;
(void)rpt;
rpt = (iot_plc_rtc_update_rpt_t *)(iot_pkt_data(pkt) +
sizeof(iot_plc_msg_header_t));
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
iot_sg_sta_nw_rtc_update_rpt(rpt->cco_date, rpt->cco_ntb);
} else {
iot_sg_sta_gw_rtc_update_rpt(rpt->cco_date, rpt->cco_ntb);
}
iot_pkt_free(pkt);
}
uint8_t iot_sg_sta_cco_bl_list_get(uint8_t *addr_buff, uint8_t buff_cnt)
{
uint8_t i, addr_cnt = 0, *addr_tmp;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!addr_buff || !buff_cnt) {
goto out;
}
for (i = 0; i < IOT_SG_STA_BLACK_LIST_MAX_CNT; i++) {
if (iot_mac_addr_valid(sta_glb->cco_bl[i].addr)) {
addr_tmp = addr_buff + IOT_MAC_ADDR_LEN * addr_cnt;
iot_mac_addr_cpy(addr_tmp, sta_glb->cco_bl[i].addr);
addr_cnt++;
if (addr_cnt >= buff_cnt) {
break;
}
}
}
out:
return addr_cnt;
}
static uint32_t iot_sg_sta_cco_bl_update(uint8_t *addr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
uint8_t i, usable_index = 0, usable_flag = 0;
uint32_t ret = ERR_FAIL;
if (!addr) {
goto out;
}
for (i = 0; i < IOT_SG_STA_BLACK_LIST_MAX_CNT; i++) {
if (iot_mac_addr_valid(sta_glb->cco_bl[i].addr)) {
if (iot_mac_addr_cmp(sta_glb->cco_bl[i].addr, addr)) {
goto out;
}
continue;
}
/* find usable index to save cco black list infomation */
usable_flag = 1;
usable_index = i;
}
if (!usable_flag) {
goto out;
}
sta_glb->cco_bl_update_flag = 1;
iot_mac_addr_cpy(sta_glb->cco_bl[usable_index].addr, addr);
sta_glb->cco_bl[usable_index].invalid_tm_cnt = sta_glb->cco_bl_invalid_time;
iot_sg_printf("%s addr %02x%02x%02x%02x%02x%02x invalid_time %lu\n",
__FUNCTION__, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
sta_glb->cco_bl_invalid_time);
ret = ERR_OK;
out:
return ret;
}
void iot_sg_sta_cco_bl_list_set(uint8_t *addr_buff, uint8_t buff_cnt)
{
iot_pkt_t *plc_addr_pkt;
uint8_t i, *addr_tmp, plc_addr_cnt = 0, *plc_addr;
if (!addr_buff || !buff_cnt) {
return;
}
plc_addr_pkt = iot_pkt_alloc(IOT_MAC_ADDR_LEN * buff_cnt,
IOT_SMART_GRID_MID);
plc_addr = iot_pkt_put(plc_addr_pkt, IOT_MAC_ADDR_LEN * buff_cnt);
for (i = 0; i < buff_cnt; i++) {
addr_tmp = addr_buff + IOT_MAC_ADDR_LEN * i;
if (iot_sg_sta_cco_bl_update(addr_tmp) == ERR_OK) {
iot_mac_addr_cpy(plc_addr + plc_addr_cnt * IOT_MAC_ADDR_LEN,
addr_tmp);
plc_addr_cnt++;
}
}
if (plc_addr_cnt) {
iot_plc_set_blacklist(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT,
IOT_PLC_BL_ADD, plc_addr_cnt, plc_addr);
}
iot_pkt_free(plc_addr_pkt);
}
uint8_t iot_sg_sta_cco_bl_update_flag_get()
{
return p_sg_glb->desc.sta->cco_bl_update_flag;
}
void iot_sg_sta_cco_bl_update_flag_clean()
{
p_sg_glb->desc.sta->cco_bl_update_flag = 0;
}
static void iot_sg_sta_cco_bl_handle(iot_plc_invalid_mac_rpt_t *rpt)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (!sta_glb->cco_bl_invalid_time ||
rpt->reason != IOT_PLC_INVD_MAC_IN_BLACKLIST) {
goto out;
}
if (iot_sg_sta_cco_bl_update(rpt->cco_mac) != ERR_OK) {
goto out;
}
iot_plc_set_blacklist(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT,
IOT_PLC_BL_ADD, 1, rpt->cco_mac);
out:
return;
}
void iot_sg_sta_drv_upgrade_state_set(uint8_t state)
{
iot_sg_sta_upgrade_info_t *p_info = &p_sg_glb->desc.sta->upgrade_info;
p_info->drv_upgrde_state = state;
}
/* message handling function started state */
static iot_sg_sta_state_t iot_sg_sta_sm_started(iot_sg_msg_t *msg)
{
iot_plc_cfg_set_req_t cfg;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_state_t state = sta_glb->sm.cur_state;
iot_pkt_t *pkt;
iot_plc_msg_header_t *plc_hdr;
iot_plc_invalid_mac_rpt_t *rpt;
iot_plc_dev_state_change_rpt_t *state_rpt;
iot_plc_phase_rpt_t *phase_rpt;
iot_plc_query_band_bitmap_rpt_t *bandbitmap_rpt;
iot_plc_zc_collect_rpt_t *collect_rpt;
iot_plc_neighbor_dev_rpt_t *neighbor_dev_rpt;
iot_plc_set_pm_addr_rpt_t *set_addr_rpt;
uint8_t addr[IOT_MAC_ADDR_LEN], dev_type, new_nw_joined;
uint8_t data_type, done_src, rpt_state;
uint16_t rpt_seq;
uint32_t ret;
switch (msg->task_msg.type) {
case IOT_SG_MSG_TYPE_UART:
{
pkt = (iot_pkt_t *)msg->data;
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_UART_DATA:
{
uint8_t *data;
uint32_t len;
data = iot_pkt_block_ptr(pkt, IOT_PKT_BLOCK_DATA);
len = iot_pkt_block_len(pkt, IOT_PKT_BLOCK_DATA);
if (((sta_glb->drv->dev_type == IOT_SG_STA_DEV_TYPE_POWER_METER)
|| (sta_glb->drv->dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T1))
&& (pm_power_off_event_trig_check(data, len) == ERR_OK)) {
iot_plc_pm_trig_power_off();
iot_pkt_free(pkt);
break;
}
if (!iot_sg_sta_uart_data_handle(data, len)) {
iot_pkt_free(pkt);
break;
}
sta_glb->drv->uart_func(msg->data2, pkt);
break;
}
case IOT_SG_MSG_ID_UART_TSFM_DATA:
{
iot_sg_sta_tsfm_msg_handle(pkt);
break;
}
default:
IOT_ASSERT(0);
iot_pkt_free(pkt);
break;
}
break;
}
case IOT_SG_MSG_TYPE_SWC:
{
iot_sg_handle_swc_data(msg);
break;
}
case IOT_SG_MSG_TYPE_PLC:
{
pkt = (iot_pkt_t *)msg->data;
plc_hdr = (iot_plc_msg_header_t *)iot_pkt_block_ptr(pkt,
IOT_PKT_BLOCK_DATA);
switch (plc_hdr->msg_id) {
case IOT_PLC_MSG_MSDU_RECV:
{
iot_plc_msdu_recv_t *msdu = NULL;
msdu = (iot_plc_msdu_recv_t*)(plc_hdr + 1);
if (p_sg_glb->msdu_fwd_enable) {
iot_sg_ext_send_msdu_msg_to_cus(pkt, msdu);
} else {
iot_sg_sta_handle_msdu_msg(pkt, msdu);
}
break;
}
case IOT_PLC_MSG_INVALID_MAC_RPT:
{
rpt = (iot_plc_invalid_mac_rpt_t*)(plc_hdr + 1);
iot_sg_printf("%s invalid mac %02x%02x%02x%02x%02x%02x reason %lu\n"
, __FUNCTION__, rpt->mac[0], rpt->mac[1], rpt->mac[2],
rpt->mac[3], rpt->mac[4], rpt->mac[5], rpt->reason);
iot_sg_sta_cco_bl_handle(rpt);
dev_type = (uint8_t)sta_glb->drv->get_device_type();
if (dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T3 ||
(dev_type == IOT_SG_STA_DEV_TYPE_COLLECTOR_T1 &&
sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) ||
IOT_BSRM_MODE == IOT_BSRM_MODE_CUS_APP) {
goto invalid_mac_rpt_exit;
}
iot_mac_addr_reverse(rpt->mac);
iot_sg_sta_invalid_mac_add(rpt->mac, rpt->nid);
ret = iot_sg_sta_find_valid_mac(addr);
if (ret == ERR_OK) {
if (iot_mac_addr_cmp(addr, rpt->mac)) {
goto invalid_mac_rpt_exit;
}
if (sta_glb->drv->set_login_addr) {
sta_glb->drv->set_login_addr(addr);
}
iot_mac_addr_reverse(addr);
iot_sg_printf("%s valid mac %02x%02x%02x%02x%02x%02x\n",
__FUNCTION__, addr[0], addr[1], addr[2], addr[3], addr[4],
addr[5]);
os_mem_set(&cfg, 0, sizeof(cfg));
cfg.addr_valid = 1;
cfg.addr_type = IOT_PLC_MAC_ADDR_TYPE_METER;
iot_mac_addr_cpy(cfg.addr, addr);
cfg.dev_type_valid = 1;
cfg.dev_type = iot_sg_sta_to_plc_dev_type(dev_type);
cfg.reset = 1;
iot_plc_set_cfg(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT,
&cfg);
iot_swc_set_cfg(IOT_SWC_API_REQ_ID_DEFAULT, addr,
iot_sg_sta_to_plc_dev_type(dev_type), 1);
} else {
if (sta_glb->drv->nodify_invalid_addr) {
sta_glb->drv->nodify_invalid_addr();
}
}
invalid_mac_rpt_exit:
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_DEV_STATE_CHANGE_RPT:
{
state_rpt = (iot_plc_dev_state_change_rpt_t*)(plc_hdr + 1);
p_sg_glb->plc_state.cert_test_detected =
state_rpt->cert_test_detected;
if (!p_sg_glb->dev_is_ready && state_rpt->is_ready) {
os_mem_set(sta_glb->invalid_addr_list, 0x0,
sizeof(sta_glb->invalid_addr_list));
if (!p_sg_glb->plc_state.cert_test_detected
&& !sta_glb->get_time_done) {
iot_sg_sta_start_get_time();
}
iot_counter_inc(sta_glb->mr.mr_info.join_cnt);
iot_sg_sta_sm_done_evt_start_check(
sta_glb->mr.mr_info.join_cnt);
if (os_boot_time32() < IOT_SG_STA_PT_DETECT_VALID_TIME) {
sta_glb->evt.pt_detected = (uint8_t)state_rpt->pt_detected;
} else {
sta_glb->evt.pt_detected = 0;
}
if (iot_sg_sta_power_on_report_start() != ERR_OK) {
/* if there is no power on event to be reported,
* meter event report is enable.
*/
sta_glb->evt.event_rpt_on = 1;
sta_glb->drv->enable_event_rpt();
}
if (!iot_mac_addr_cmp(sta_glb->cco_addr, state_rpt->cco_mac)
&& iot_mac_addr_valid(sta_glb->cco_addr)) {
iot_sg_sta_rtc_clear(1);
iot_sg_sta_ext_gw_rpt_stop();
}
if (sta_glb->local_nid == state_rpt->nid &&
sta_glb->network_sn == state_rpt->nework_sn &&
iot_mac_addr_cmp(sta_glb->cco_addr, state_rpt->cco_mac)) {
/* all id are exactly the same. */
new_nw_joined = 0;
} else {
sta_glb->joined_ts = os_boot_time64();
sta_glb->local_nid = state_rpt->nid;
sta_glb->network_sn = state_rpt->nework_sn;
iot_mac_addr_cpy(sta_glb->cco_addr, state_rpt->cco_mac);
new_nw_joined = 1;
}
sta_glb->same_vendor = (uint8_t)state_rpt->same_vendor;
if (sta_glb->upgrade_info.drv_upgrde_state ==
IOT_SG_STA_DRV_UPGRADE_STATE_IDLE) {
iot_sg_sta_upgrade_on_join(new_nw_joined);
}
iot_sg_ext_link_state_rpt_to_cusapp(state_rpt->is_ready);
} else if (p_sg_glb->dev_is_ready && !state_rpt->is_ready) {
sta_glb->drv->disable_event_rpt();
sta_glb->mr.mr_info.leave_cnt++;
iot_sg_sta_upgrade_on_leave();
iot_sg_sta_3p_zc_state_clear();
iot_sg_ext_link_state_rpt_to_cusapp(state_rpt->is_ready);
}
p_sg_glb->dev_is_ready = state_rpt->is_ready;
iot_sg_sta_ext_nli_plc_link_state_change_handle(
p_sg_glb->dev_is_ready);
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_CFG_SET_CONF:
{
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_CONN_LESS_RECV:
{
iot_sg_sta_conn_less_msg_handle(pkt,
IOT_SG_LINK_TYPE_PLC_CONN_LESS);
break;
}
case IOT_PLC_MSG_CTRL_PROTO_RECV:
{
iot_sg_sta_ctrl_proto_msg_handle(pkt);
break;
}
case IOT_PLC_MSG_CTRL_PROTO_STATUS_RPT:
{
iot_plc_ctrl_proto_state_rpt_t *ctrl_proto_state_rpt =
(iot_plc_ctrl_proto_state_rpt_t *)(plc_hdr + 1);
if (ctrl_proto_state_rpt->state ==
IOT_PLC_CTRL_PROTO_STATE_CONNECTED) {
sta_glb->ctrl_proto_sn = ctrl_proto_state_rpt->sn;
sta_glb->ctrl_proto_connected = 1;
} else {
sta_glb->ctrl_proto_connected = 0;
iot_sg_sta_queue_app_del_by_type(IOT_SG_LINK_TYPE_PLC_CTRL);
}
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_PHASE_RPT:
{
phase_rpt = (iot_plc_phase_rpt_t*)(plc_hdr + 1);
sta_glb->node_properties.detect_state = phase_rpt->done;
sta_glb->node_properties.opposite_phase = phase_rpt->opposite_phase;
sta_glb->node_properties.phase = phase_rpt->phy_phase;
sta_glb->node_properties.opposite_3p = phase_rpt->opposite_3p;
sta_glb->node_properties.opposite_3p_pos =
phase_rpt->opposite_3p_pos;
sta_glb->node_properties.logic_phase = phase_rpt->logic_phase;
sta_glb->node_properties.zc_repeat_3p = phase_rpt->zc_repeat_3p;
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_TSFM_STATUS_RPT:
{
iot_sg_sta_tsfm_status_rpt(pkt);
break;
}
case IOT_PLC_MSG_SCANBAND_BITMAP_SET_RPT:
{
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_QUERYBAND_BITMAP_RPT:
{
/* TODO: handle query band */
bandbitmap_rpt = (iot_plc_query_band_bitmap_rpt_t*)(plc_hdr + 1);
(void)bandbitmap_rpt;
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_ZC_CLCT_RPT:
{
collect_rpt = (iot_plc_zc_collect_rpt_t*)(plc_hdr + 1);
iot_sg_sta_zc_clct_rpt_handle(plc_hdr->req_id, collect_rpt);
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_NEIGHBOR_DEV_RPT:
{
neighbor_dev_rpt = (iot_plc_neighbor_dev_rpt_t*)(plc_hdr + 1);
iot_sg_sta_neighbor_dev_rpt_handle(neighbor_dev_rpt,
plc_hdr->req_id);
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_PHASE_MASK_SET_CONF:
{
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_PM_ADDR_SET_RPT:
{
if (plc_hdr->req_id == sta_glb->last_addr_reqid) {
set_addr_rpt = (iot_plc_set_pm_addr_rpt_t *)(plc_hdr + 1);
if (set_addr_rpt->result == IOT_PLC_SUCCESS) {
iot_sg_sta_set_addr_list_state(0);
}
}
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_RTC_UPDATE_RPT:
{
iot_sg_sta_rtc_update_rpt(pkt);
break;
}
default:
iot_pkt_free(pkt);
break;
}
break;
}
case IOT_SG_MSG_TYPE_BRM:
{
pkt = (iot_pkt_t *)msg->data;
plc_hdr = (iot_plc_msg_header_t *)iot_pkt_block_ptr(pkt,
IOT_PKT_BLOCK_DATA);
switch (plc_hdr->msg_id) {
case IOT_PLC_MSG_CONN_LESS_RECV:
{
iot_sg_sta_conn_less_msg_handle(pkt, IOT_SG_LINK_TYPE_PLC_BRM);
break;
}
default:
iot_sg_printf("%s drop msg id %d\n", __FUNCTION__, plc_hdr->msg_id);
iot_pkt_free(pkt);
break;
}
}
case IOT_SG_MSG_TYPE_TIMER:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_TIMER_DETECT:
{
/* ignore such timer in started phase */
break;
}
case IOT_SG_MSG_ID_TIMER_STA_DRIVER:
{
sta_glb->drv->timer_func();
break;
}
case IOT_SG_MSG_ID_TIMER_EVENT_RPT:
{
iot_sg_sta_event_ack_handle(IOT_SG_STA_EVENT_RPT_TIMEOUT);
break;
}
case IOT_SG_MSG_ID_TIMER_UPGRADE:
{
iot_sg_sta_upgrade_timer_handler();
break;
}
case IOT_SG_MSG_ID_TIMER_EXT_DEV_UPGRADE:
{
iot_sg_sta_ext_dev_upgrade_timer_handle();
break;
}
case IOT_SG_MSG_ID_TIMER_STA_REFRESH:
{
if (sta_glb->drv && sta_glb->drv->refresh_timer_func) {
sta_glb->drv->refresh_timer_func(IOT_SG_STA_REFRESH_DUR);
}
iot_sg_sta_refresh_timeout_handle();
break;
}
case IOT_SG_MSG_ID_TIMER_POWER_OFF:
{
if (iot_sg_sta_power_off_check()) {
iot_sg_sta_pd_evt_rpt_handle();
} else {
iot_sg_sta_pd_evt_fwd_handle();
}
break;
}
case IOT_SG_MSG_ID_TIMER_POWER_ON:
{
iot_sg_sta_power_on_report_handle();
break;
}
case IOT_SG_MSG_ID_TIMER_READ_TSFM:
{
iot_sg_sta_tsfm_msg_handle(NULL);
break;
}
case IOT_SG_MSG_ID_TIMER_CF_TIMEOUT:
{
iot_sg_sta_tsfm_collect_start();
break;
}
case IOT_SG_MSG_ID_TIMER_SM_DONE_CHK:
{
iot_sg_sta_sm_done_report_handle();
break;
}
case IOT_SG_MSG_ID_TIMER_PIN_STA_OUTPUT:
{
iot_sg_sta_pinsta_low();
break;
}
case IOT_SG_MSG_ID_TIMER_GW_RPT_DELAY:
{
iot_sg_sta_ext_gw_rpt_func();
break;
}
default:
IOT_ASSERT(0);
break;
}
/* iot_sg_printf("timeout %lu\n", msg->task_msg.id);
* iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_INFO,
* IOT_SG_STA_SM_STARTED_TO_ID, 1, msg->task_msg.id);
*/
break;
}
case IOT_SG_MSG_TYPE_DRV:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_DRV_METER_R_DONE:
{
data_type = (uint8_t)msg->data2;
done_src = (uint8_t)(msg->data2 >> 8);
iot_sg_sta_meter_read_done_intern(data_type, done_src, msg->data);
break;
}
case IOT_SG_MSG_ID_DRV_PRIVATE_CALL_REQ:
{
if (sta_glb->drv) {
if (sta_glb->drv->private_func) {
sta_glb->drv->private_func(msg->data2, msg->data);
break;
}
}
IOT_ASSERT(0);
break;
}
case IOT_SG_MSG_ID_DRV_CHECK_PM_DONE:
{
if (iot_sg_sta_pd_check_done_handle(msg->data2)) {
iot_sg_sta_power_off_rpt_start();
}
break;
}
case IOT_SG_MSG_ID_DRV_START_NODE_REG:
{
iot_sg_sta_start_sec_node_reg(IOT_SG_STA_NODE_REG_REASON_DRV);
break;
}
case IOT_SG_MSG_ID_DRV_START_GET_TIME:
{
if (!p_sg_glb->plc_state.cert_test_detected) {
iot_sg_sta_start_get_time();
}
break;
}
default:
IOT_ASSERT(0);
break;
}
break;
}
case IOT_SG_MSG_TYPE_INTERNAL:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_INTERN_START:
{
break;
}
case IOT_SG_MSG_ID_INTERN_POWER_OFF_INIT:
{
iot_sg_sta_power_msg_handle(msg->data2);
break;
}
case IOT_SG_MSG_ID_INTERN_HW_TSFM_INFO:
{
pkt = (iot_pkt_t *)msg->data;
iot_sg_sta_save_tsfm_info(
(iot_sg_sta_tsfm_info_t *)iot_pkt_data(pkt));
iot_sg_sta_tsfm_info_rpt_start();
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_ID_INTERN_EXT_SM:
{
iot_sg_sta_ext_sm_func();
break;
}
case IOT_SG_MSG_ID_INTERN_HW_TOPO_INFO:
{
pkt = (iot_pkt_t *)msg->data;
iot_sg_sta_save_tsfm_topo_info(
(iot_sg_sta_tsfm_topo_info_t *)iot_pkt_data(pkt));
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_ID_INTERN_RPT_SEND_DONE:
{
rpt_state = (uint8_t)msg->data2;
rpt_seq = (uint16_t)(msg->data2 >> 8);
(void)rpt_state;
(void)rpt_seq;
iot_sg_sta_ext_gw_rpt_done_handle(rpt_seq, rpt_state);
break;
}
default:
IOT_ASSERT(0);
break;
}
break;
}
case IOT_SG_MSG_TYPE_COMMAND:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_COMMAND_CUS:
{
iot_sg_ext_sta_command_process(msg);
break;
}
case IOT_SG_MSG_ID_MSDU_CUS:
{
iot_sg_ext_sta_msdu_process(msg);
break;
}
default:
IOT_ASSERT(0);
}
break;
}
default:
/* if code hit here, please add logic to handle event carefully */
IOT_ASSERT(0);
break;
}
iot_task_free_msg(p_sg_glb->task_h, &msg->task_msg);
return state;
}
/* message handling function starting state */
static iot_sg_sta_state_t iot_sg_sta_sm_starting(iot_sg_msg_t *msg)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_state_t state = sta_glb->sm.cur_state;
iot_pkt_t *pkt;
iot_plc_msg_header_t *plc_hdr;
iot_plc_phase_rpt_t *phase_rpt;
iot_plc_query_band_bitmap_rpt_t *bandbitmap_rpt;
iot_plc_set_pm_addr_rpt_t *set_addr_rpt;
switch (msg->task_msg.type) {
case IOT_SG_MSG_TYPE_UART:
{
pkt = (iot_pkt_t *)msg->data;
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_UART_DATA:
{
uint8_t *data;
uint32_t len;
data = iot_pkt_block_ptr(pkt, IOT_PKT_BLOCK_DATA);
len = iot_pkt_block_len(pkt, IOT_PKT_BLOCK_DATA);
if (iot_sg_sta_power_off_check()) {
iot_pkt_free(pkt);
break;
}
if (!iot_sg_sta_uart_data_handle(data, len)) {
iot_pkt_free(pkt);
break;
}
g_sta_drv_table[sta_glb->detect_idx]->uart_func(msg->data2,
pkt);
break;
}
case IOT_SG_MSG_ID_UART_TSFM_DATA:
{
iot_sg_sta_tsfm_msg_handle(pkt);
break;
}
default:
IOT_ASSERT(0);
iot_pkt_free(pkt);
break;
}
break;
}
case IOT_SG_MSG_TYPE_PLC:
{
pkt = (iot_pkt_t *)msg->data;
plc_hdr = (iot_plc_msg_header_t *)iot_pkt_block_ptr(pkt,
IOT_PKT_BLOCK_DATA);
switch (plc_hdr->msg_id) {
case IOT_PLC_MSG_MSDU_RECV:
{
/* won't handle message other than upgrade in starting state */
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_PHASE_RPT:
{
phase_rpt = (iot_plc_phase_rpt_t*)(plc_hdr + 1);
sta_glb->node_properties.detect_state = phase_rpt->done;
sta_glb->node_properties.opposite_phase = phase_rpt->opposite_phase;
sta_glb->node_properties.phase = phase_rpt->phy_phase;
sta_glb->node_properties.opposite_3p = phase_rpt->opposite_3p;
sta_glb->node_properties.opposite_3p_pos =
phase_rpt->opposite_3p_pos;
sta_glb->node_properties.logic_phase = phase_rpt->logic_phase;
sta_glb->node_properties.zc_repeat_3p = phase_rpt->zc_repeat_3p;
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_INVALID_MAC_RPT:
case IOT_PLC_MSG_CFG_SET_CONF:
case IOT_PLC_MSG_DEV_STATE_CHANGE_RPT:
case IOT_PLC_MSG_CONN_LESS_RECV:
case IOT_PLC_MSG_CTRL_PROTO_RECV:
case IOT_PLC_MSG_CTRL_PROTO_STATUS_RPT:
case IOT_PLC_MSG_SCANBAND_BITMAP_SET_RPT:
case IOT_PLC_MSG_ZC_CLCT_RPT:
case IOT_PLC_MSG_PHASE_MASK_SET_CONF:
{
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_PM_ADDR_SET_RPT:
{
if (plc_hdr->req_id == sta_glb->last_addr_reqid) {
set_addr_rpt = (iot_plc_set_pm_addr_rpt_t *)(plc_hdr + 1);
if (set_addr_rpt->result == IOT_PLC_SUCCESS) {
iot_sg_sta_set_addr_list_state(0);
}
}
iot_pkt_free(pkt);
break;
}
case IOT_PLC_MSG_QUERYBAND_BITMAP_RPT:
{
/* TODO: handle query band */
bandbitmap_rpt = (iot_plc_query_band_bitmap_rpt_t*)(plc_hdr + 1);
(void)bandbitmap_rpt;
iot_pkt_free(pkt);
break;
}
default:
{
iot_pkt_free(pkt);
break;
}
}
break;
}
case IOT_SG_MSG_TYPE_BRM:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_TYPE_TIMER:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_TIMER_DETECT:
{
ret = iot_sg_sta_check_detect();
if (ret) {
/* device not detected, trigger next detect */
ret = iot_sg_sta_trigger_detect();
if (ret) {
/* no driver support device detect, move to init state */
state = iot_sg_sta_state_init;
} else {
iot_sg_sta_drv_detect_round_check();
}
} else {
iot_sg_sta_drv_detect_done_handle();
state = iot_sg_sta_state_started;
}
break;
}
case IOT_SG_MSG_ID_TIMER_STA_DRIVER:
{
if (g_sta_drv_table[sta_glb->detect_idx]) {
if (g_sta_drv_table[sta_glb->detect_idx]->timer_func)
g_sta_drv_table[sta_glb->detect_idx]->timer_func();
}
break;
}
case IOT_SG_MSG_ID_TIMER_READ_TSFM:
{
iot_sg_sta_tsfm_msg_handle(NULL);
break;
}
case IOT_SG_MSG_ID_TIMER_STA_REFRESH:
{
if (sta_glb->drv) {
if (sta_glb->drv->refresh_timer_func) {
sta_glb->drv->refresh_timer_func(IOT_SG_STA_REFRESH_DUR);
}
}
break;
}
case IOT_SG_MSG_ID_TIMER_SM_DONE_CHK:
case IOT_SG_MSG_ID_TIMER_CF_TIMEOUT:
case IOT_SG_MSG_ID_TIMER_POWER_OFF:
case IOT_SG_MSG_ID_TIMER_POWER_ON:
case IOT_SG_MSG_ID_TIMER_EVENT_RPT:
case IOT_SG_MSG_ID_TIMER_UPGRADE:
case IOT_SG_MSG_ID_TIMER_PIN_STA_OUTPUT:
case IOT_SG_MSG_ID_TIMER_GW_RPT_DELAY:
{
/* ignore such timer in starting phase */
break;
}
default:
IOT_ASSERT(0);
break;
}
break;
}
case IOT_SG_MSG_TYPE_DRV:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_DRV_DETECT_DONE:
{
iot_sg_sta_stop_detect_timer();
ret = iot_sg_sta_check_detect();
if (ret) {
/* device not detected, trigger next detect */
ret = iot_sg_sta_trigger_detect();
if (ret) {
/* no driver support device detect, move to init state */
state = iot_sg_sta_state_init;
} else {
iot_sg_sta_drv_detect_round_check();
}
} else {
iot_sg_sta_drv_detect_done_handle();
state = iot_sg_sta_state_started;
}
break;
}
case IOT_SG_MSG_ID_DRV_PRIVATE_CALL_REQ:
{
if (sta_glb->drv) {
if (sta_glb->drv->private_func) {
sta_glb->drv->private_func(msg->data2,msg->data);
break;
}
}
IOT_ASSERT(0);
break;
}
case IOT_SG_MSG_ID_DRV_CHECK_PM_DONE:
{
break;
}
case IOT_SG_MSG_ID_DRV_START_NODE_REG:
{
break;
}
case IOT_SG_MSG_ID_DRV_START_GET_TIME:
{
break;
}
default:
/* if code hit here, please add logic to handle event carefully */
IOT_ASSERT(0);
break;
}
break;
}
case IOT_SG_MSG_TYPE_INTERNAL:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_INTERN_START:
{
break;
}
case IOT_SG_MSG_ID_INTERN_POWER_OFF_INIT:
{
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_FUJIAN
&& msg->data2 == IOT_PLC_PM_MSG_POWER_RECOVERED) {
iot_system_restart(IOT_SYS_RST_REASON_POWER_UP_AGAIN);
}
break;
}
case IOT_SG_MSG_ID_INTERN_EXT_SM:
{
break;
}
case IOT_SG_MSG_ID_INTERN_HW_TSFM_INFO:
{
pkt = (iot_pkt_t *)msg->data;
iot_sg_sta_save_tsfm_info(
(iot_sg_sta_tsfm_info_t *)iot_pkt_data(pkt));
iot_sg_sta_tsfm_info_rpt_start();
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_ID_INTERN_HW_TOPO_INFO:
{
pkt = (iot_pkt_t *)msg->data;
iot_sg_sta_save_tsfm_topo_info(
(iot_sg_sta_tsfm_topo_info_t *)iot_pkt_data(pkt));
iot_pkt_free(pkt);
break;
}
default:
IOT_ASSERT(0);
break;
}
break;
}
case IOT_SG_MSG_TYPE_COMMAND:
{
iot_sg_ext_sta_command_process(msg);
break;
}
default:
/* if code hit here, please add logic to handle event carefully */
IOT_ASSERT(0);
break;
}
iot_task_free_msg(p_sg_glb->task_h, &msg->task_msg);
return state;
}
/* message handling function init state */
static iot_sg_sta_state_t iot_sg_sta_sm_init(iot_sg_msg_t *msg)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_state_t state = sta_glb->sm.cur_state;
iot_pkt_t *pkt;
switch (msg->task_msg.type) {
case IOT_SG_MSG_TYPE_UART:
case IOT_SG_MSG_TYPE_PLC:
case IOT_SG_MSG_TYPE_BRM:
{
/* won't handle any PLC & UART message in init stage */
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_TYPE_INTERNAL:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_INTERN_START:
{
iot_sg_sta_scan_band_bitmap_init();
/* start device detecting */
ret = iot_sg_sta_trigger_detect();
if (ret == ERR_OK) {
os_start_timer(sta_glb->refresh_timer, IOT_SG_STA_REFRESH_DUR);
iot_sg_sta_hw_tsfm_start();
state = iot_sg_sta_state_starting;
} else {
/* driver failed to detecting the device,
* stay in init state.
*/
}
break;
}
case IOT_SG_MSG_ID_INTERN_POWER_OFF_INIT:
{
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_FUJIAN
&& msg->data2 == IOT_PLC_PM_MSG_POWER_RECOVERED) {
iot_system_restart(IOT_SYS_RST_REASON_POWER_UP_AGAIN);
}
break;
}
case IOT_SG_MSG_ID_INTERN_EXT_SM:
{
break;
}
case IOT_SG_MSG_ID_INTERN_HW_TSFM_INFO:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_ID_INTERN_HW_TOPO_INFO:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
default:
IOT_ASSERT(0);
break;
}
break;
}
default:
/* if code hit here, please add logic to handle event carefully */
IOT_ASSERT(0);
break;
}
iot_task_free_msg(p_sg_glb->task_h, &msg->task_msg);
return state;
}
static void iot_sg_sta_on_state_changed(iot_sg_sta_state_t prev_state,
iot_sg_sta_state_t new_state)
{
(void)prev_state;
if (iot_sg_sta_state_started == new_state) {
iot_sg_sta_upgrade_init();
}
}
/* message executing callback */
static void iot_sg_sta_msg_exe_func(iot_sg_msg_t *msg)
{
iot_plc_msg_header_t *hdr;
iot_pkt_t *pkt;
uint8_t tmp_mac[IOT_MAC_ADDR_LEN] = {0};
uint16_t net_lock_time, abn_lock_time;
iot_sg_sta_state_t new_state;
iot_sg_sta_state_t cur_state = p_sg_glb->desc.sta->sm.cur_state;
switch (msg->task_msg.type) {
case IOT_SG_MSG_TYPE_PLC:
{
pkt = (iot_pkt_t *)msg->data;
hdr = (iot_plc_msg_header_t *)iot_pkt_data(pkt);
switch (hdr->msg_id) {
case IOT_PLC_MSG_APP_REG_CONF:
{
if (iot_mac_addr_valid(p_sg_glb->pib.sta.rw->sta.tsfm_addr)) {
iot_mac_addr_cpy(tmp_mac, p_sg_glb->pib.sta.rw->sta.tsfm_addr);
iot_mac_addr_reverse(tmp_mac);
iot_plc_tsfm_set_tsfm_addr(p_sg_glb->plc_app_h, tmp_mac);
}
if (iot_sg_sta_hw_tsfm_is_3p()) {
iot_plc_set_whitelist(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, IOT_PLC_WL_ENABLE, 0, NULL);
if (iot_mac_addr_valid(tmp_mac)) {
iot_plc_set_whitelist(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, IOT_PLC_WL_ADD, 1, tmp_mac);
}
}
if (iot_sg_sta_get_user_type() == USER_TYPE_BRM_SMALL_LOAD_GOLDEN) {
iot_plc_set_whitelist(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, IOT_PLC_WL_ENABLE, 0, NULL);
iot_plc_set_freq_band(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, PLC_LIB_FREQ_BAND_2);
}
if (p_sg_glb->pib.sta.rw->sta.lock_time_flag) {
net_lock_time = p_sg_glb->pib.sta.rw->sta.net_lock_time;
abn_lock_time = p_sg_glb->pib.sta.rw->sta.abn_lock_time;
iot_plc_tsfm_set_lock_time(p_sg_glb->plc_app_h, &net_lock_time,
&abn_lock_time);
} else if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_ZHEJIANG) {
net_lock_time = IOT_SG_STA_NW_NOR_LOCK_TIME;
abn_lock_time = IOT_SG_STA_NW_ABN_LOCK_TIME;
iot_plc_tsfm_set_lock_time(p_sg_glb->plc_app_h, &net_lock_time,
&abn_lock_time);
}
iot_pkt_free(pkt);
iot_task_free_msg(p_sg_glb->task_h, &msg->task_msg);
return;
}
default:
break;
}
break;
}
default:
break;
}
/* deliver to state machine */
new_state = p_sg_glb->desc.sta->sm.func[cur_state](msg);
if (new_state != cur_state) {
iot_sg_printf("%s state %lu to %lu\n", __FUNCTION__,
cur_state, new_state);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_ERR,
IOT_SG_STA_SM_ID, 2, cur_state, new_state);
p_sg_glb->desc.sta->sm.prev_state = cur_state;
p_sg_glb->desc.sta->sm.cur_state = new_state;
iot_sg_sta_on_state_changed(cur_state, new_state);
}
}
/* message canceling callback */
static void iot_sg_sta_msg_cancel_func(iot_sg_msg_t *msg)
{
iot_pkt_t *pkt = NULL;
switch (msg->task_msg.type) {
case IOT_SG_MSG_TYPE_UART:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_TYPE_SWC:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_TYPE_PLC:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_TYPE_BRM:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_TYPE_INTERNAL:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_INTERN_START:
case IOT_SG_MSG_ID_INTERN_POWER_OFF_INIT:
case IOT_SG_MSG_ID_INTERN_EXT_SM:
case IOT_SG_MSG_ID_INTERN_RPT_SEND_DONE:
{
break;
}
case IOT_SG_MSG_ID_INTERN_HW_TSFM_INFO:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
case IOT_SG_MSG_ID_INTERN_HW_TOPO_INFO:
{
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
break;
}
default:
IOT_ASSERT(0);
break;
}
break;
}
case IOT_SG_MSG_TYPE_TIMER:
{
break;
}
case IOT_SG_MSG_TYPE_DRV:
{
switch(msg->task_msg.id) {
case IOT_SG_MSG_ID_DRV_METER_R_DONE:
case IOT_SG_MSG_ID_DRV_PRIVATE_CALL_REQ:
{
if (msg->data) {
pkt = (iot_pkt_t *)msg->data;
iot_pkt_free(pkt);
}
break;
}
case IOT_SG_MSG_ID_DRV_DETECT_DONE:
case IOT_SG_MSG_ID_DRV_CHECK_PM_DONE:
{
break;
}
default:
IOT_ASSERT(0);
break;
}
break;
}
case IOT_SG_MSG_TYPE_COMMAND:
{
switch (msg->task_msg.id) {
case IOT_SG_MSG_ID_COMMAND_CUS:
{
iot_sg_ext_sta_command_cancel(msg);
break;
}
case IOT_SG_MSG_ID_MSDU_CUS:
{
iot_sg_ext_sta_msdu_cancel(msg);
break;
}
default:
IOT_ASSERT(0);
}
break;
}
default:
IOT_ASSERT(0);
break;
}
iot_task_free_msg(p_sg_glb->task_h, &msg->task_msg);
}
static void iot_sg_sta_meter_read_done_src(uint8_t data_type, uint8_t done_src,
iot_pkt_t *rsp_pkt)
{
/* deliver a message to self context to break the deep loop to ease
* the stack depth load.
* read -> read_done -> read -> read_done
*/
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_DRV;
msg->task_msg.id = IOT_SG_MSG_ID_DRV_METER_R_DONE;
msg->data = rsp_pkt;
msg->data2 = data_type;
msg->data2 |= (done_src << 8);
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
if (rsp_pkt)
iot_pkt_free(rsp_pkt);
}
}
void iot_sg_sta_meter_read_done_framework(uint8_t data_type, iot_pkt_t *rsp_pkt)
{
iot_sg_sta_meter_read_done_src(data_type, IOT_SG_STA_MR_DONE_BY_FRAMEWORK,
rsp_pkt);
}
void iot_sg_sta_meter_read_done(uint8_t data_type, iot_pkt_t *rsp_pkt)
{
iot_sg_sta_meter_read_done_src(data_type, IOT_SG_STA_MR_DONE_BY_DRIVE,
rsp_pkt);
}
void iot_sg_sta_node_reg_clear_last_obsolete(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
uint8_t i, idx = IOT_SG_STA_SEC_NODE_MAX;
uint8_t *addr;
for (i = 0; i < IOT_SG_STA_SEC_NODE_MAX; i++) {
idx--;
if (sta_glb->node_list[idx] != NULL) {
node = sta_glb->node_list[idx];
if (node->obsolete) {
addr = sta_glb->node_list[idx]->entry.addr;
iot_sg_sta_flash_meter_delete(addr);
iot_sg_sta_ext_meter_delete(node);
iot_addr_hash_table_remove(sta_glb->node_table,
&node->entry);
iot_addr_hash_table_free(sta_glb->node_table,
&node->entry);
sta_glb->node_list[idx] = NULL;
iot_sg_sta_set_addr_list_state(1);
break;
}
}
}
}
static void iot_sg_sta_judge_phase_report(uint8_t is_three_phase, uint8_t v_rps,
uint8_t phase, uint8_t *node_addr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
iot_sg_sta_evt_global_t *evt = &sta_glb->evt;
iot_plc_tsfm_status_rpt_t tsfm_status = sta_glb->tsfm_status;
uint8_t login_addr[IOT_MAC_ADDR_LEN], abn_ps = 0;
if (sta_glb->proto != IOT_SG_STA_APP_PROTO_GW) {
goto out;
}
if (drv == NULL || (drv->get_device_type() !=
IOT_SG_STA_DEV_TYPE_POWER_METER)) {
goto out;
}
drv->get_login_addr(login_addr);
if (!iot_mac_addr_cmp(node_addr, login_addr)) {
goto out;
}
if (!is_three_phase) {
goto out;
}
if (!evt->event_rpt_on) {
goto out;
}
if (phase) {
iot_plc_set_phase_mask(p_sg_glb->plc_app_h, IOT_PLC_API_REQ_ID_DEFAULT,
((~phase) & 0x07));
}
/* v_rps and phase infomation by pm drive timer to update,
* interval time is 60s.
* opposite_3p by framework timer to update, interval time is 60s.
*/
if (phase && iot_sg_get_phase_cnt(phase) < 3) {
abn_ps |= 0x01;
}
if (v_rps) {
abn_ps |= 0x02;
}
if (tsfm_status.opposite_3p) {
abn_ps |= 0x04;
}
/* when abn_ps change phase event report,
* abn_ps is 0 normal others are abnormal.
*/
if ((evt->his_zc_status_sn != tsfm_status.zc_status_sn ||
evt->his_abn_ps != abn_ps) && !evt->event_rpt_pending) {
iot_sg_printf("%s abn sn %lu\n", __FUNCTION__, abn_ps);
evt->his_zc_status_sn = tsfm_status.zc_status_sn;
evt->abn_ps = abn_ps;
iot_sg_sta_report_phase_event(evt->abn_ps, 1);
}
out:
return;
}
static void iot_sg_sta_node_init(iot_sg_sta_node_desc_t *node)
{
if (!node) {
return;
}
node->data_type = 0;
node->double_proto = 0;
node->nli_en = 0;
node->gw_clclt_en = 0;
node->module_type = 0;
node->is_09_rule = 0;
node->is_three_phase = 0;
node->phase = 0;
node->v_rps = 0;
node->phase_ident = 0;
node->obsolete = 0;
node->lr_en = 0;
node->sm_rpt_state = 0;
node->data_freeze_en = 0;
node->nw_lc_en = 0;
node->nli_detected = 0;
node->supp_lr = 0;
node->clct_task_en = 0;
node->ss_en = 0;
node->data_clct_en = 0;
node->sus_pof = 0;
node->time_abnormal = 0;
node->clct_last_df = 0;
node->lr_rec_abnormal = 0;
node->ec_en = 0;
os_mem_set(&node->ext, 0x0, sizeof(node->ext));
}
void iot_sg_sta_node_reg_report(iot_sg_sta_drv_node_info_t *node_info,
uint8_t rpt_type)
{
uint32_t idx, ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_req_queue_t *queue = &sta_glb->queue;
iot_sg_sta_node_desc_t *node;
iot_sg_sta_req_entry_t *req_entry;
iot_list_head_t *pos, *temp;
node = (iot_sg_sta_node_desc_t *)iot_addr_hash_table_find(
sta_glb->node_table, node_info->pm_addr);
if (rpt_type == IOT_SG_STA_NODE_RPT_TYPE_EXIST) {
iot_sg_sta_bl_node_rm(node_info->pm_addr);
}
if (node) {
/* update node information */
node->data_type = node_info->data_type;
node->module_type = node_info->module_type;
node->is_09_rule = node_info->is_09_rule;
node->is_three_phase = node_info->is_three_phase;
node->phase = node_info->phase;
node->v_rps = node_info->v_rps;
node->phase_ident = node_info->phase_ident;
node->supp_lr = node_info->supp_lr;
node->sus_pof = node_info->sus_pof;
node->double_proto = node_info->double_proto;
if (rpt_type == IOT_SG_STA_NODE_RPT_TYPE_EXIST) {
node->obsolete = 0;
} else if (rpt_type == IOT_SG_STA_NODE_RPT_TYPE_NO_EXIST) {
node->obsolete = 1;
}
iot_sg_sta_judge_phase_report(node->is_three_phase, node->v_rps,
node->phase, node_info->pm_addr);
iot_sg_sta_ext_meter_add(node);
return;
} else if (rpt_type == IOT_SG_STA_NODE_RPT_TYPE_UPDATE) {
return;
}
if (rpt_type == IOT_SG_STA_NODE_RPT_TYPE_EXIST) {
/* check whether there is a corresponding reading mater data packet in
* the unknown request queue, and if so, move to the known request
* queue.
*/
iot_list_for_each_safe(pos, temp,
&queue->head[IOT_SG_STA_REQ_QUEUE_LP]) {
req_entry = iot_list_entry(pos, iot_sg_sta_req_entry_t, link);
if (iot_mac_addr_valid(req_entry->req.pm_addr)
&& iot_mac_addr_cmp(req_entry->req.pm_addr,
node_info->pm_addr)) {
iot_list_del(pos);
iot_list_add_prev(pos, &queue->head[IOT_SG_STA_REQ_QUEUE_HP]);
}
}
}
node = (iot_sg_sta_node_desc_t *)iot_addr_hash_table_alloc(
sta_glb->node_table);
if (!node) {
/* if sta can't find free entry to save the new node info, clear the
* last obsolete node info to resave the new node info.
*/
iot_sg_sta_node_reg_clear_last_obsolete();
node = (iot_sg_sta_node_desc_t *)iot_addr_hash_table_alloc(
sta_glb->node_table);
}
/* find free entry to save the new node info */
if (node) {
iot_sg_sta_node_init(node);
iot_mac_addr_cpy(node->entry.addr, node_info->pm_addr);
node->data_type = node_info->data_type;
node->module_type = node_info->module_type;
node->is_09_rule = node_info->is_09_rule;
node->is_three_phase = node_info->is_three_phase;
node->phase = node_info->phase;
node->v_rps = node_info->v_rps;
node->phase_ident = node_info->phase_ident;
node->supp_lr = node_info->supp_lr;
node->sus_pof = node_info->sus_pof;
node->double_proto = node_info->double_proto;
if (rpt_type == IOT_SG_STA_NODE_RPT_TYPE_EXIST) {
node->obsolete = 0;
} else {
node->obsolete = 1;
}
ret = iot_addr_hash_table_add(sta_glb->node_table,
&node->entry);
if (ret) {
/* node already exist */
iot_addr_hash_table_free(sta_glb->node_table,
&node->entry);
} else {
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx] == NULL) {
sta_glb->node_list[idx] = node;
iot_sg_sta_set_addr_list_state(1);
if (rpt_type == IOT_SG_STA_NODE_RPT_TYPE_EXIST) {
iot_sg_sta_ext_meter_add(node);
}
break;
}
}
}
}
}
void iot_sg_sta_drv_start_sec_node_reg(void)
{
iot_sg_msg_t *msg;
msg = (iot_sg_msg_t *)iot_task_alloc_msg(p_sg_glb->task_h);
if (msg) {
msg->task_msg.type = IOT_SG_MSG_TYPE_DRV;
msg->task_msg.id = IOT_SG_MSG_ID_DRV_START_NODE_REG;
iot_task_queue_msg(p_sg_glb->task_h, &msg->task_msg,
IOT_SG_MSG_QUEUE_LP);
} else {
IOT_ASSERT(0);
}
}
void iot_sg_sta_start_sec_node_reg(uint8_t reason)
{
uint8_t idx;
uint64_t cur_time;
uint32_t interval;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
if (reason == IOT_SG_STA_NODE_REG_REASON_QUERY) {
cur_time = os_boot_time64();
interval = (uint32_t)((cur_time -
sta_glb->node_reg.last_node_reg_ts) / (60 * 1000));
if (sta_glb->node_reg.last_node_reg_ts
&& (interval < IOT_SG_STA_LAST_NODE_REG_RESULT_INTERVAL)) {
return;
}
}
if (!sta_glb->node_reg.node_reg_on) {
iot_sg_printf("%s\n", __FUNCTION__);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_INFO,
IOT_SG_STA_START_SEC_NODE_REG_S_ID, 0);
sta_glb->node_reg.node_reg_on = 1;
/* mark all meters to be obsolete */
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx] != NULL) {
sta_glb->node_list[idx]->obsolete = 1;
}
}
drv->start_node_reg();
}
}
void iot_sg_sta_stop_sec_node_reg(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
if (sta_glb->node_reg.node_reg_on) {
iot_sg_printf("%s\n", __FUNCTION__);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_INFO,
IOT_SG_STA_STOP_SEC_NODE_REG_S_ID, 0);
sta_glb->node_reg.node_reg_on = 0;
drv->stop_node_reg();
iot_sg_sta_node_reg_clear_all_obsolete();
}
}
void iot_sg_sta_node_reg_deregister(uint8_t *addr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
uint32_t idx;
node = (iot_sg_sta_node_desc_t *)iot_addr_hash_table_find(
sta_glb->node_table, addr);
if (node) {
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx] == node) {
iot_sg_sta_flash_meter_delete(addr);
iot_sg_sta_ext_meter_delete(sta_glb->node_list[idx]);
iot_sg_sta_set_addr_list_state(1);
sta_glb->node_list[idx] = NULL;
iot_addr_hash_table_remove(sta_glb->node_table,
&node->entry);
iot_addr_hash_table_free(sta_glb->node_table,
&node->entry);
break;
}
}
}
}
void iot_sg_sta_node_reg_deregister_all(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
uint32_t idx;
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx] != NULL) {
node = sta_glb->node_list[idx];
iot_sg_sta_flash_meter_delete(node->entry.addr);
iot_sg_sta_ext_meter_delete(node);
iot_addr_hash_table_remove(sta_glb->node_table,
&node->entry);
iot_addr_hash_table_free(sta_glb->node_table,
&node->entry);
sta_glb->node_list[idx] = NULL;
iot_sg_sta_set_addr_list_state(1);
}
}
}
static void iot_sg_sta_bl_node_rm_callback(iot_addr_hash_entry_t *entry,
void* param)
{
(void)param;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_addr_hash_table_remove(sta_glb->node_bl_table,
entry);
iot_addr_hash_table_free(sta_glb->node_bl_table,
entry);
}
uint32_t iot_sg_sta_is_bl_node(uint8_t *addr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_addr_hash_entry_t *entry;
entry = iot_addr_hash_table_find(sta_glb->node_bl_table, addr);
if (entry)
return 1;
else
return 0;
}
void iot_sg_sta_bl_node_add(uint8_t *addr, uint32_t dur)
{
uint32_t curr_ts;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_bl_desc_t *node;
curr_ts = (uint32_t)(os_boot_time64() / 1000);
node = (iot_sg_sta_node_bl_desc_t *)iot_addr_hash_table_find(
sta_glb->node_bl_table, addr);
if (node) {
node->rm_ts = curr_ts + dur;
} else {
/* find free entry to save the new node info */
node = (iot_sg_sta_node_bl_desc_t *)iot_addr_hash_table_alloc(
sta_glb->node_bl_table);
if (node) {
iot_mac_addr_cpy(node->entry.addr, addr);
node->rm_ts = curr_ts + dur;
iot_addr_hash_table_add(sta_glb->node_bl_table,
&node->entry);
}
}
}
void iot_sg_sta_bl_node_rm(uint8_t *addr)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_addr_hash_entry_t *entry;
entry = iot_addr_hash_table_find(sta_glb->node_bl_table, addr);
if (entry) {
iot_addr_hash_table_remove(sta_glb->node_bl_table, entry);
iot_addr_hash_table_free(sta_glb->node_bl_table, entry);
}
}
void iot_sg_sta_bl_node_rm_all(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_addr_hash_table_loop(sta_glb->node_bl_table,
iot_sg_sta_bl_node_rm_callback, NULL);
}
void iot_sg_sta_node_reg_done(void)
{
uint8_t idx, cnt = 0;
uint8_t *addr;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_data_clct_info_t *data_clct = &sta_glb->ext_info.data_clct;
sta_glb->node_reg.node_reg_on = 0;
if (!data_clct->sm_complete) {
data_clct->sm_complete = 1;
}
iot_sg_sta_node_reg_clear_all_obsolete();
sta_glb->node_reg.last_node_reg_ts = os_boot_time64();
/* clear all obsolete meters */
for (idx = 0; idx < IOT_SG_STA_SEC_NODE_MAX; idx++) {
if (sta_glb->node_list[idx] != NULL) {
addr = sta_glb->node_list[idx]->entry.addr;
if (iot_mac_addr_valid(addr)) {
cnt++;
iot_sg_printf("%s %lu -- addr %02x%02x%02x%02x%02x%02x\n",
__FUNCTION__, cnt, addr[5], addr[4], addr[3],
addr[2], addr[1], addr[0]);
}
}
}
}
static void iot_sg_sta_pd_meter_evt_enable(uint8_t *data, uint32_t len)
{
iot_plc_cfg_set_req_t cfg = {0};
uint8_t user_type = iot_sg_sta_get_user_type();
if (iot_sg_sta_pd_meter_evt_rpt_is_support() == ERR_OK && data && len &&
iot_sg_sta_power_off_check()) {
if (proto_69845_sanity_check(data, (uint16_t)len) ||
(iot_sg_sta_nw_new_meter_check() &&
proto_645_format_check_ext(data, len, PROTO_645_DIR_SLAVE)) ||
user_type == USER_TYPE_STATE_GRID_OVERSEAS_SX) {
cfg.ignore_pw_collapsed = 1;
cfg.pw_collapsed_valid = 1;
iot_sg_printf("%s ignore pw collapsed\n", __FUNCTION__);
iot_plc_set_cfg(p_sg_glb->plc_app_h,
IOT_PLC_API_REQ_ID_DEFAULT, &cfg);
}
}
}
uint32_t iot_sg_sta_report_event(uint8_t *addr, uint8_t *data_ptr,
uint32_t len, uint8_t new_evt)
{
iot_sg_sta_pd_meter_evt_enable(data_ptr, len);
return iot_sg_sta_report_event_with_type(addr, data_ptr, len, new_evt,
IOT_SG_STA_RPT_METER_NORMAL_EVT);
}
uint32_t iot_sg_sta_report_event_with_seq(uint8_t *addr, uint8_t *data_ptr,
uint32_t len, uint16_t seq)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
(void)addr;
(void)data_ptr;
(void)len;
(void)seq;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
ret = iot_sg_sta_gw_event_send_with_seq(addr, data_ptr, len,
seq, IOT_SG_STA_RPT_MODULE_SEQ_EVT);
} else {
ret = ERR_NOSUPP;
}
return ret;
}
uint32_t iot_sg_sta_report_ec_health_event(
uint8_t *addr, uint8_t score, iot_sg_sta_drv_score_bit_map_t *bitmap)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
ret = iot_sg_sta_nw_report_ec_health_event(addr, score, bitmap);
} else {
ret = ERR_NOSUPP;
}
return ret;
}
uint32_t iot_sg_sta_report_ec_overvoltage_event(uint8_t *addr,
uint8_t is_three_phase, uint16_t av, uint16_t bv, uint16_t cv)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
ret = iot_sg_sta_nw_report_ec_overvoltage_event(
addr, is_three_phase, av, bv, cv);
} else {
ret = ERR_NOSUPP;
}
return ret;
}
uint32_t iot_sg_sta_report_ec_undervoltage_event(uint8_t *addr,
uint8_t is_three_phase, uint16_t av, uint16_t bv, uint16_t cv)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
ret = iot_sg_sta_nw_report_ec_undervoltage_event(
addr, is_three_phase, av, bv, cv);
} else {
ret = ERR_NOSUPP;
}
return ret;
}
uint32_t iot_sg_sta_report_ec_second_pulse_event(
uint8_t *addr, uint16_t err_val)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
ret = iot_sg_sta_nw_report_ec_second_pulse_event(addr, err_val);
} else {
ret = ERR_NOSUPP;
}
return ret;
}
uint32_t iot_sg_sta_report_nli_event(iot_sg_sta_ext_nli_evt_data_field_t *data)
{
(void)data;
uint32_t ret = ERR_FAIL;
iot_pkt_t *pkt = NULL;
uint8_t addr[IOT_MAC_ADDR_LEN];
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_nli_evt_rpt_info_t *rpt_info =
&sta_glb->ext_info.nli_rpt_info;
gw_app_nli_abnormal_data_t *node_info =
(gw_app_nli_abnormal_data_t *)data->nli_data;
BUILD_BUG_ON(sizeof(iot_sg_sta_ext_nli_evt_data_t) ==
sizeof(gw_app_nli_abnormal_data_t));
(void)node_info;
sta_glb->drv->get_login_addr(addr);
if (!rpt_info->seq) {
rpt_info->seq = iot_sg_sta_get_event_rpt_seq();
}
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
pkt = iot_sg_sta_gw_nli_evt_build(data->rpt_cnt, node_info);
} else {
ret = ERR_NOSUPP;
}
if (pkt) {
ret = iot_sg_sta_gw_event_send_with_seq(addr,
iot_pkt_data(pkt), iot_pkt_data_len(pkt),
rpt_info->seq, IOT_SG_STA_RPT_MODULE_NLI_EVT);
iot_pkt_free(pkt);
}
return ret;
}
uint32_t iot_sg_sta_send_uart(iot_pkt_t *pkt)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->soft_record_state) {
iot_pkt_free(pkt);
return ERR_OK;
}
iot_sg_data_print("<--uart send--", iot_pkt_data(pkt),
iot_pkt_data_len(pkt));
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_INFO,
IOT_SG_PROTO_UART_SEND, 0);
#if IOT_SG_EXT_SDK_ENABLE
uint8_t arg = 0;
IOT_SG_EXT_UART_FULL_FRAME_SET(arg);
return iot_sg_ext_send_to_cusapp(pkt, arg);
#else
return iot_uart_send(p_sg_glb->uart_h, pkt, NULL);
#endif
}
uint32_t iot_sg_sta_config_uart(uint32_t baud, uint8_t parity,
uint8_t data, uint8_t stop, iot_frame_fmt *fmt, uint32_t thrd)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->soft_record_state) {
return ERR_OK;
}
#if IOT_SG_EXT_SDK_ENABLE
return iot_sg_ext_cusuart_config(baud, parity, data, stop, fmt, thrd,
(uint32_t)IOT_SG_EXT_INVALID_THRD);
#else
if (!iot_uart_set_config(p_sg_glb->uart_h, baud, parity, data, stop)) {
goto drop;
}
if (fmt && !iot_uart_set_frame(p_sg_glb->uart_h, fmt)) {
goto drop;
}
iot_uart_set_threshold(p_sg_glb->uart_h, UART_THR_RXTIMEOUT, thrd);
return ERR_OK;
drop:
return ERR_FAIL;
#endif
}
uint32_t iot_sg_sta_start_driver_timer(uint32_t dur)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (dur == 0) {
dur = 1;
}
os_start_timer(sta_glb->driver_timer, dur);
return ERR_OK;
}
void iot_sg_sta_stop_driver_timer()
{
os_stop_timer(p_sg_glb->desc.sta->driver_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_STA_DRIVER);
}
uint32_t iot_sg_sta_start_read_tsfm_timer(uint32_t dur)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (dur == 0) {
dur = 1;
}
os_start_timer(sta_glb->read_tsfm_timer, dur);
return ERR_OK;
}
void iot_sg_sta_stop_read_tsfm_timer(void)
{
os_stop_timer(p_sg_glb->desc.sta->read_tsfm_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_READ_TSFM);
}
void iot_sg_sta_start_tsfm_feature_collect_timer(uint32_t dur)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
os_start_timer(sta_glb->collect_timer, dur);
}
void iot_sg_sta_stop_tsfm_feature_collect_timer(void)
{
os_stop_timer(p_sg_glb->desc.sta->collect_timer);
iot_task_clean_msg(p_sg_glb->task_h, IOT_SG_MSG_TYPE_TIMER,
IOT_SG_MSG_ID_TIMER_CF_TIMEOUT);
}
static void iot_sg_sta_correct_time_msg_handle(iot_time_tm_t *corr_tm)
{
uint8_t user_type = iot_sg_sta_get_user_type(), time_to_cache = 0;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_time_tm_t cur_tm = { 0 };
if (user_type != USER_TYPE_SOUTHEN_POWER_GRID_GX &&
user_type != USER_TYPE_STATE_GRID_HUNAN &&
user_type != USER_TYPE_STATE_GRID_HEBEI &&
user_type != USER_TYPE_STATE_GRID_GANSU &&
!sta_glb->br2_enable &&
sta_glb->drv->get_device_type() != IOT_SG_STA_DEV_TYPE_COLLECTOR_T3) {
goto out;
}
if (user_type == USER_TYPE_STATE_GRID_GANSU) {
if (iot_sg_sta_rtc_get(&cur_tm, 0) == ERR_OK) {
if (sta_glb->ct_rec.year == cur_tm.tm_year &&
sta_glb->ct_rec.mon == cur_tm.tm_mon &&
sta_glb->ct_rec.day == cur_tm.tm_mday) {
iot_sg_printf("%s fail\n", __FUNCTION__);
goto out;
}
sta_glb->ct_rec.year = cur_tm.tm_year;
sta_glb->ct_rec.mon = cur_tm.tm_mon;
sta_glb->ct_rec.day = cur_tm.tm_mday;
}
iot_sg_sta_ext_auto_ct_set(1, 1);
} else if (user_type == USER_TYPE_SOUTHEN_POWER_GRID_GX) {
iot_sg_sta_ext_auto_ct_set(1, 1);
time_to_cache = 1;
} else if (user_type == USER_TYPE_STATE_GRID_HUNAN) {
sta_glb->tm_info.rpt_flag = 1;
sta_glb->tm_info.threshold = 5 * 60;
sta_glb->tm_info.rpt_delay = 0;
time_to_cache = 1;
}
if (time_to_cache) {
/* current correct time is not system time,
* use for auto_tm and clock_skew_report.
*/
sta_glb->tm_info.cache_time = *corr_tm;
sta_glb->tm_info.cache_time_ts = (uint32_t)(os_boot_time64() / 1000);
goto out;
}
iot_sg_sta_rtc_set(corr_tm, 1);
out:
return;
}
uint8_t iot_sg_sta_get_phy_type()
{
uint8_t phy_type;
if (iot_plc_get_comm_type() == IOT_PLC_COMM_TYPE_DUAL_MODE) {
phy_type = IOT_SG_STA_PLC_COMM_TYPE_DUAL_MODE;
} else {
phy_type = IOT_SG_STA_PLC_COMM_TYPE_HPLC_MODE;
}
return phy_type;
}
uint32_t iot_sg_sta_correct_time(iot_pkt_t *pkt)
{
proto_645_header_t *hdr_645;
proto_69845_frame_head_info_t *hdr_698 = NULL;
uint8_t *ds, corr_msg_type = IOT_SG_STA_CORR_TYPE_UNKNOWN;
uint8_t user_type = iot_sg_sta_get_user_type();
uint16_t oi;
uint32_t len, ret = ERR_FAIL;
iot_time_tm_t iot_ts = { 0 };
apdu_info_t apdu = { 0 };
proto_69845_apdu_t *apdu_hdr;
proto_69845_app_action_req_t *req_hdr;
proto_69845_app_action_req_single_t *action_hdr;
proto_69845_app_data_time_s_t *time_698;
proto_645_corr_time_t *time_07;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (p_sg_glb->plc_state.cert_test_detected) {
/* if cert test command ever detected stop check correct time. */
goto out;
}
if ((sta_glb->drv->get_device_type() != IOT_SG_STA_DEV_TYPE_POWER_METER)
&& (sta_glb->drv->get_device_type() != IOT_SG_STA_DEV_TYPE_COLLECTOR_T3)
&& user_type != USER_TYPE_STATE_GRID_ZHEJIANG && !sta_glb->br2_enable) {
/* if device type isn't power meter and protocol type isn't zhejiang
* and isn't br2 function, stop check correct time.
*/
goto out;
}
ds = iot_pkt_data(pkt);
len = iot_pkt_data_len(pkt);
hdr_645 = proto_645_format_check(ds, len, PROTO_645_DIR_MASTER);
if (hdr_645) {
if (hdr_645->control.fn == PROTO_645_2007_FN_CORRECT_TIME
&& hdr_645->len >= sizeof(*time_07)) {
proto_645_sub33_handle(hdr_645->data, hdr_645->len);
if (iot_bcd_data_check(hdr_645->data, hdr_645->len)) {
time_07 = (proto_645_corr_time_t*)&hdr_645->data;
/* the year is incomplete in DL/T 645 protocol,
* so it add 2000
*/
iot_ts.tm_year = iot_bcd_to_byte(time_07->year) + 2000;
iot_ts.tm_mon = iot_bcd_to_byte(time_07->month);
iot_ts.tm_mday = iot_bcd_to_byte(time_07->day);
iot_ts.tm_hour = iot_bcd_to_byte(time_07->hour);
iot_ts.tm_min = iot_bcd_to_byte(time_07->minute);
iot_ts.tm_sec = iot_bcd_to_byte(time_07->second);
corr_msg_type = IOT_SG_STA_CORR_TYPE_645;
}
proto_645_add33_handle(hdr_645->data, hdr_645->len);
}
goto out;
}
if (proto_69845_parse(&ds, &len, &hdr_698, &apdu) == ERR_OK) {
if (apdu.len < (sizeof(*apdu_hdr) + sizeof(*req_hdr)
+ sizeof(*action_hdr) + sizeof(*time_698))) {
goto fwd;
}
if (sta_glb->drv->get_device_type() == IOT_SG_STA_DEV_TYPE_COLLECTOR_T1
&& user_type == USER_TYPE_TM) {
if (hdr_698->addr.flag.sa_type != PROTO_69845_SA_TYPE_BROADCAST) {
goto fwd;
}
}
proto_69845_oi_to_byte(PROTO_69845_APP_OI_TIME, (uint8_t*)&oi);
apdu_hdr = (proto_69845_apdu_t*)apdu.ptr;
req_hdr = (proto_69845_app_action_req_t*)apdu_hdr->data;
action_hdr = (proto_69845_app_action_req_single_t*)req_hdr->data;
time_698 = (proto_69845_app_data_time_s_t*)action_hdr->data.data;
if (apdu_hdr->type != PROTO_69845_C_APP_ACTION_REQ
|| req_hdr->data_type != PROTO_69845_APP_ACTION_NORMAL
|| action_hdr->omd.oi != oi
|| action_hdr->omd.method_id != PROTO_OMD_CORRECT_TIME_METHOD_ID
|| action_hdr->data.data_type != PROTO_69845_APP_DATA_TIME_S) {
goto fwd;
}
iot_ts.tm_year = iot_bytes_to_uint16((uint8_t*)&time_698->year, 1);
iot_ts.tm_mon = time_698->month;
iot_ts.tm_mday = time_698->day;
iot_ts.tm_hour = time_698->hour;
iot_ts.tm_min = time_698->minute;
iot_ts.tm_sec = time_698->second;
corr_msg_type = IOT_SG_STA_CORR_TYPE_698;
fwd:
if (hdr_698 && hdr_698->ctrl.flag_scramble) {
/* the message is forwarded after recovery */
proto_69845_add33_handle(apdu.ptr, apdu.len);
}
}
out:
if (corr_msg_type != IOT_SG_STA_CORR_TYPE_UNKNOWN) {
iot_sg_sta_correct_time_msg_handle(&iot_ts);
ret = ERR_OK;
}
return ret;
}
uint8_t iot_sg_sta_is_3p_module()
{
uint8_t is_three_phase = 0;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (p_sg_glb->module_type == MODULE_TYPE_3_PHASE_STA ||
sta_pib->is_three_phase) {
is_three_phase = 1;
}
return is_three_phase;
}
uint8_t iot_sg_sta_is_sidle_meter_read(uint8_t data_type)
{
return (data_type == IOT_SG_STA_DATA_TYPE_TRANS &&
iot_sg_sta_get_proto_type() == IOT_SG_STA_APP_PROTO_GW);
}
uint8_t iot_sg_sta_save_correct_tm_pib(int64_t delta, uint8_t *addr)
{
uint8_t ref, ret = ERR_OK, reason;
uint16_t ticket;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if (!iot_mac_addr_valid(addr)) {
reason = 1;
ret = ERR_INVAL;
goto drop;
}
if (!sta_pib) {
reason = 2;
ret = ERR_INVAL;
goto drop;
}
iot_sg_printf("%s src pib addr %02x:%02x:%02x:%02x:%02x:%02x delta %lld\n",
__FUNCTION__, sta_pib->pm_addr[0], sta_pib->pm_addr[1],
sta_pib->pm_addr[2], sta_pib->pm_addr[3], sta_pib->pm_addr[4],
sta_pib->pm_addr[5], sta_pib->tm_sta_delta);
iot_sg_printf("%s save addr %02x:%02x:%02x:%02x:%02x:%02x delta %lld\n",
__FUNCTION__, addr[0], addr[1], addr[2], addr[3], addr[4],
addr[5], delta);
iot_pib_acquire_app_commit_ref(&ref);
sta_pib->tm_sta_delta = delta;
iot_mac_addr_cpy(sta_pib->pm_addr, addr);
iot_pib_release_app_commit_ref(&ref);
iot_pib_app_commit(&ticket);
/* reset next read data time */
iot_sg_sta_ext_tm_reset();
goto out;
drop:
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
out:
return ret;
}
uint8_t iot_sg_sta_get_user_type()
{
return p_sg_glb->user_type;
}
uint8_t iot_sg_sta_get_cert_test_detected(void)
{
return p_sg_glb->plc_state.cert_test_detected;
}
uint8_t iot_sg_sta_get_nw_pt_detected(void)
{
return p_sg_glb->desc.sta->nw_pt_detected;
}
uint8_t iot_sg_sta_phase_rpt_enable_check(void)
{
uint8_t user_type = iot_sg_sta_get_user_type();
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if ((user_type != USER_TYPE_STATE_GRID_HEBEI
&& user_type != USER_TYPE_BRM_PEIWANG)
|| (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW)) {
return 0;
} else {
return 1;
}
}
void iot_sg_sta_lock_time_save(uint16_t net_lock_time,
uint16_t abn_lock_time)
{
uint8_t ref;
uint16_t ticket;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
if ((sta_pib->lock_time_flag && ((sta_pib->net_lock_time != net_lock_time)
|| (sta_pib->abn_lock_time != abn_lock_time)))
|| !sta_pib->lock_time_flag) {
iot_pib_acquire_app_commit_ref(&ref);
sta_pib->net_lock_time = net_lock_time;
sta_pib->abn_lock_time = abn_lock_time;
sta_pib->lock_time_flag = 1;
iot_pib_release_app_commit_ref(&ref);
iot_pib_app_commit(&ticket);
}
}
#if IOT_BRM_ENABLE
void iot_sg_sta_handle_cus_cfg(iot_sg_ext_cus_cfg_t *cfg)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_node_desc_t *node;
iot_sg_ext_cus_cfg_param_t *param_cfg;
iot_sg_ext_cus_node_attr_cfg_t *node_cfg;
uint8_t add_meter = 0;
switch (cfg->cfg_id) {
case IOT_SG_EXT_CFG_ID_PARAM:
{
param_cfg = (iot_sg_ext_cus_cfg_param_t *)cfg->data;
if (param_cfg->mr_to_min_valid) {
p_sg_glb->desc.sta->mr.mr_timeout_min = param_cfg->mr_timeout_min;
iot_sg_printf("%s mr_timeout %lu\n", __FUNCTION__,
p_sg_glb->desc.sta->mr.mr_timeout_min);
}
if (param_cfg->addr_filter_en_valid) {
p_sg_glb->desc.sta->mr.addr_filter_en = param_cfg->addr_filter_en;
iot_sg_printf("%s addr_filter_en %lu\n", __FUNCTION__,
p_sg_glb->desc.sta->mr.addr_filter_en);
}
if (param_cfg->tsfm_addr_valid &&
iot_mac_addr_valid(param_cfg->tsfm_addr)) {
iot_sg_sta_set_hw_tsfm_addr(param_cfg->tsfm_addr);
iot_sg_printf("%s tsfm addr %02x%02x%02x%02x%02x%02x\n",
__FUNCTION__, param_cfg->tsfm_addr[5], param_cfg->tsfm_addr[4],
param_cfg->tsfm_addr[3], param_cfg->tsfm_addr[2],
param_cfg->tsfm_addr[1], param_cfg->tsfm_addr[0]);
}
if (param_cfg->stop_flag_valid && param_cfg->stop_flag) {
iot_sg_sta_ext_disable();
iot_sg_printf("%s disable ext func\n", __FUNCTION__);
}
break;
}
case IOT_SG_EXT_CFG_ID_PM_ATTR:
{
node_cfg = (iot_sg_ext_cus_node_attr_cfg_t *)cfg->data;
for (uint8_t i = 0; i < node_cfg->cnt; i++) {
node = (iot_sg_sta_node_desc_t *)iot_addr_hash_table_find(
sta_glb->node_table, node_cfg->info[i].addr);
if (!node)
continue;
if (node_cfg->info[i].time_abnormal
&& !node->time_abnormal) {
/* for meters with load recording function, if the clock is
* abnormal, supplement the load recording locally.
*/
node->time_abnormal = 1;
add_meter = 1;
}
if (node_cfg->info[i].lr_rec_abnormal
&& !node->lr_rec_abnormal) {
node->lr_rec_abnormal = 1;
add_meter = 1;
}
if (add_meter) {
iot_sg_sta_ext_meter_add(node);
}
}
break;
}
default:
break;
}
}
void iot_sg_sta_handle_cus_sync_node_list(
iot_sg_ext_node_list_sync_t *node_list)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
if (sta_glb->drv->sync_node_func) {
sta_glb->drv->sync_node_func(node_list);
}
}
#else /* IOT_BRM_ENABLE */
void iot_sg_sta_handle_cus_cfg(iot_sg_ext_cus_cfg_t *cfg)
{
iot_sg_ext_cus_cfg_param_t *param_cfg;
switch (cfg->cfg_id) {
case IOT_SG_EXT_CFG_ID_PARAM:
{
param_cfg = (iot_sg_ext_cus_cfg_param_t *)cfg->data;
if (param_cfg->stop_flag_valid && param_cfg->stop_flag) {
iot_sg_sta_ext_disable();
iot_sg_printf("%s stop ext func\n", __FUNCTION__);
}
break;
}
default:
break;
}
}
void iot_sg_sta_handle_cus_sync_node_list(
iot_sg_ext_node_list_sync_t *node_list)
{
(void)node_list;
}
#endif /* IOT_BRM_ENABLE */
void iot_sg_sta_modify_locked_tsfm_addr(uint8_t *tsfm_addr)
{
iot_sg_sta_tsfm_info_t tsfm_info;
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
tsfm_info.phase = sta_pib->phase;
if (tsfm_addr) {
iot_mac_addr_cpy(tsfm_info.cco_addr, tsfm_addr);
iot_mac_addr_reverse(tsfm_info.cco_addr);
} else {
os_mem_set(tsfm_info.cco_addr, 0, IOT_MAC_ADDR_LEN);
}
iot_sg_sta_save_tsfm_info(&tsfm_info);
}
void iot_sg_sta_correct_time_compensate(
uint32_t cco_ntb, uint8_t *data, uint32_t length)
{
uint8_t *ds = data;
uint16_t oi;
uint32_t len = length;
iot_time_tm_t tm;
proto_645_header_t *hdr_645;
proto_645_corr_time_t *time;
proto_645_tailer_t *tail;
apdu_info_t apdu = { 0 };
proto_69845_frame_head_info_t *hdr_698;
proto_69845_apdu_t *apdu_hdr;
proto_69845_app_action_req_t *req_hdr;
proto_69845_app_action_req_single_t *action_hdr;
proto_69845_app_data_time_s_t *time_698;
hdr_645 = proto_645_format_check(ds, len, PROTO_645_DIR_MASTER);
if (hdr_645) {
if (hdr_645->control.fn == PROTO_645_2007_FN_CORRECT_TIME
&& hdr_645->len >= sizeof(*time)) {
proto_645_sub33_handle(hdr_645->data, hdr_645->len);
if (iot_bcd_data_check(hdr_645->data, hdr_645->len)
&& (hdr_645->len >= sizeof(*time))) {
time = (proto_645_corr_time_t*)&hdr_645->data;
tm.tm_year = iot_bcd_to_byte(time->year) + 2000;
tm.tm_mon = iot_bcd_to_byte(time->month);
tm.tm_mday = iot_bcd_to_byte(time->day);
tm.tm_hour = iot_bcd_to_byte(time->hour);
tm.tm_min = iot_bcd_to_byte(time->minute);
tm.tm_sec = iot_bcd_to_byte(time->second);
iot_sg_sta_cur_ntb_correct_ts(cco_ntb, &tm);
time->year = iot_byte_to_bcd((uint8_t)(tm.tm_year - 2000));
time->month = iot_byte_to_bcd(tm.tm_mon);
time->day = iot_byte_to_bcd(tm.tm_mday);
time->hour = iot_byte_to_bcd(tm.tm_hour);
time->minute = iot_byte_to_bcd(tm.tm_min);
time->second = iot_byte_to_bcd(tm.tm_sec);
proto_645_add33_handle(hdr_645->data, hdr_645->len);
tail = (proto_645_tailer_t*)(hdr_645->data + sizeof(*time));
tail->cs = proto_645_calc_cs(hdr_645);
} else {
proto_645_add33_handle(hdr_645->data, hdr_645->len);
}
}
} else if (proto_69845_parse(&ds, &len, &hdr_698, &apdu) == ERR_OK) {
if (len < (sizeof(*apdu_hdr) + sizeof(*req_hdr)
+ sizeof(*action_hdr) + sizeof(*time_698))) {
goto fwd;
}
proto_69845_oi_to_byte(PROTO_69845_APP_OI_TIME, (uint8_t*)&oi);
apdu_hdr = (proto_69845_apdu_t*)ds;
req_hdr = (proto_69845_app_action_req_t*)apdu_hdr->data;
action_hdr = (proto_69845_app_action_req_single_t*)req_hdr->data;
time_698 = (proto_69845_app_data_time_s_t*)action_hdr->data.data;
if (apdu_hdr->type != PROTO_69845_C_APP_ACTION_REQ
|| req_hdr->data_type != PROTO_69845_APP_ACTION_NORMAL
|| action_hdr->omd.oi != oi
|| action_hdr->omd.method_id != PROTO_OMD_CORRECT_TIME_METHOD_ID
|| action_hdr->data.data_type != PROTO_69845_APP_DATA_TIME_S) {
goto fwd;
}
tm.tm_year = iot_bytes_to_uint16((uint8_t*)&time_698->year, 1);
tm.tm_mon = time_698->month;
tm.tm_mday = time_698->day;
tm.tm_hour = time_698->hour;
tm.tm_min = time_698->minute;
tm.tm_sec = time_698->second;
iot_sg_sta_cur_ntb_correct_ts(cco_ntb, &tm);
iot_uint16_to_bytes(tm.tm_year, (uint8_t*)&time_698->year, 1);
time_698->month = tm.tm_mon;
time_698->day = tm.tm_mday;
time_698->hour = tm.tm_hour;
time_698->minute = tm.tm_min;
time_698->second = tm.tm_sec;
fwd:
if (hdr_698->ctrl.flag_scramble) {
proto_69845_add33_handle(apdu.ptr, apdu.len);
}
proto_69845_tail_fill(hdr_698, (apdu.ptr + apdu.len),
sizeof(proto_69845_tailer_t));
}
return;
}
void iot_sg_sta_cur_ntb_correct_ts(uint32_t old_ntb, iot_time_tm_t *iot_ts)
{
uint32_t cur_ntb, delta;
cur_ntb = iot_plc_get_ntb(p_sg_glb->plc_app_h);
if (cur_ntb > old_ntb) {
delta = cur_ntb - old_ntb;
} else {
delta = 0xffffffff - old_ntb + cur_ntb;
}
delta = IOT_SG_STA_NTB_TO_MS(delta) / 1000;
if (delta) {
iot_rtc_delta_add((int64_t)delta, iot_ts);
}
}
static uint8_t iot_sg_sta_br2_enable_get(void)
{
uint8_t enable = 0;
if (iot_sg_sta_tsfm_supp_mode_check(IOT_PLC_HW_TSFM_SEND_MODE_LOAD)
== ERR_OK) {
enable = 1;
}
return enable;
}
uint8_t iot_sg_sta_minute_clct_is_enable()
{
uint8_t user_type, ret = 0;
iot_sg_sta_global_t* sta_glb = p_sg_glb->desc.sta;
user_type = iot_sg_sta_get_user_type();
if ((user_type == USER_TYPE_YNS)
|| (user_type == USER_TYPE_STATE_GRID_JIANGSU)
|| (user_type == USER_TYPE_TM && sta_glb->drv
&& sta_glb->drv->get_device_type()
== IOT_SG_STA_DEV_TYPE_COLLECTOR_T1)) {
ret = 1;
}
return ret;
}
void iot_sg_sta_21meter_mode_mac_get(uint8_t *mac)
{
iot_sg_sta_global_t* sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_NW) {
iot_sg_sta_nw_21meter_mode_mac_get(mac);
}
}
uint32_t iot_sg_sta_clct_data_rpt_send(uint8_t *data,
uint16_t len, uint8_t cnt, uint16_t seq,
iot_pkt_free_func_t send_done_func)
{
iot_sg_sta_global_t* sta_glb = p_sg_glb->desc.sta;
if (sta_glb->proto == IOT_SG_STA_APP_PROTO_GW) {
return iot_sg_sta_gw_min_clct_data_rpt_send(data, len, cnt, seq,
send_done_func);
} else {
return ERR_NOSUPP;
}
}
uint32_t iot_sg_sta_init()
{
iot_sg_sta_global_t *sta_glb;
uint8_t i;
uint32_t ret = 0, cert_baund;
sta_glb = os_mem_malloc(IOT_SMART_GRID_MID, sizeof(*sta_glb));
if (sta_glb == NULL) {
ret = ERR_NOMEM;
goto out;
}
sta_glb->proto = p_sg_glb->app_proto;
sta_glb->node_table =
iot_addr_hash_table_create(IOT_SMART_GRID_MID, IOT_SG_STA_SEC_NODE_MAX,
sizeof(iot_sg_sta_node_desc_t), IOT_SG_STA_SEC_NODE_HASH_TABLE_SIZE);
if (sta_glb->node_table == NULL) {
ret = ERR_NOMEM;
goto err_table;
}
sta_glb->node_bl_table =
iot_addr_hash_table_create(IOT_SMART_GRID_MID,
IOT_SG_STA_SEC_NODE_BL_MAX, sizeof(iot_sg_sta_node_bl_desc_t),
IOT_SG_STA_SEC_NODE_BL_HASH_TABLE_SIZE);
if (sta_glb->node_bl_table == NULL) {
ret = ERR_NOMEM;
goto err_bl_table;
}
sta_glb->detect_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_detect_func, NULL);
if (sta_glb->detect_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_detect;
}
sta_glb->driver_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_driver_func, NULL);
if (sta_glb->driver_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_driver;
}
sta_glb->event_rpt_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_event_rpt_func, NULL);
if (sta_glb->event_rpt_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_event_rpt;
}
sta_glb->read_tsfm_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_read_tsfm_func, NULL);
if (sta_glb->read_tsfm_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_read_info;
}
sta_glb->collect_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_tsfm_collection_func, NULL);
if (sta_glb->collect_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_collect_feature;
}
sta_glb->upgrade_info.upgrade_timer = os_create_timer(IOT_SMART_GRID_MID,
false, iot_sg_sta_upgrade_func, NULL);
if (sta_glb->upgrade_info.upgrade_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_upgrade;
}
#if IOT_SG_STA_UPGRADE_EXT_DEV_ENABLE
sta_glb->upgrade_info.ext_dev_upgrade_timer = os_create_timer(
IOT_SMART_GRID_MID, false, iot_sg_sta_ext_dev_upgrade_func, NULL);
if (sta_glb->upgrade_info.ext_dev_upgrade_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_ext_dev_upgrade;
}
#endif
sta_glb->ext_info.ext_timer = os_create_timer(IOT_SMART_GRID_MID,
false, iot_sg_sta_ext_time_func, NULL);
if (sta_glb->ext_info.ext_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_extend_function;
}
os_mem_set(&sta_glb->mr.mr_info, 0, sizeof(iot_sg_sta_mr_stats_t));
sta_glb->refresh_timer = os_create_timer(IOT_SMART_GRID_MID, true,
iot_sg_sta_refresh_func, NULL);
if (sta_glb->refresh_timer == 0) {
ret = ERR_NOMEM;
goto err_timer_refresh;
}
sta_glb->power_on_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_power_on_func, NULL);
if (sta_glb->power_on_timer == 0) {
ret = ERR_NOMEM;
goto err_power_on;
}
sta_glb->sm_evt_chk_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_sm_done_chk_func, NULL);
if (sta_glb->sm_evt_chk_timer == 0) {
ret = ERR_NOMEM;
goto err_sm_evt_chk_timer;
}
sta_glb->evt.pt_detected = 0;
sta_glb->evt.power_on_rpt_seq = 0;
sta_glb->evt.power_on_rpt_cnt = 0;
sta_glb->evt.power_on_rpt_pending = 0;
os_mem_set(&sta_glb->evt.pu_addr_ctrl, 0,
sizeof(iot_sg_sta_power_on_addrmap_desc_t));
sta_glb->power_off_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_power_off_func, NULL);
if (sta_glb->power_off_timer == 0) {
ret = ERR_NOMEM;
goto err_power_off;
}
sta_glb->evt.power_off_rpt_status = IOT_SG_STA_POWEROFF_IDLE;
sta_glb->time_flag = 0;
sta_glb->get_time_done = 0;
sta_glb->time_cnt = 0;
sta_glb->addr_list_change = 0;
sta_glb->last_addr_reqid = 0;
sta_glb->passcode = iot_board_get_user_passcode();
sta_glb->cco_bl_invalid_time = 0;
os_mem_set(sta_glb->cco_addr, 0, IOT_MAC_ADDR_LEN);
os_mem_set(sta_glb->cco_bl, 0, sizeof(sta_glb->cco_bl));
os_mem_set(&sta_glb->uart_state_info, 0,
sizeof(iot_sg_sta_uart_check_info_t));
os_mem_set(&sta_glb->evt.power_off_bm, 0,
sizeof(iot_sg_sta_power_off_bm_t));
os_mem_set(&sta_glb->evt.pd_addr_ctrl, 0,
sizeof(iot_sg_sta_pd_addrs_ctrl_t));
os_mem_set(&sta_glb->node_properties, 0,
sizeof(iot_sg_sta_properties_global_t));
os_mem_set(&sta_glb->plc_query, 0,
sizeof(iot_sg_sta_query_plc_global_t));
ret = iot_mem_pool_new(IOT_SMART_GRID_MID,
IOT_SG_STA_REQ_QUEUE_SIZE, sizeof(iot_sg_sta_req_entry_t),
&sta_glb->queue.q_pool, 0);
if (ret) {
goto create_queue_fail;
}
iot_list_init(&sta_glb->queue.head[IOT_SG_STA_REQ_QUEUE_HP]);
sta_glb->queue.cnt[IOT_SG_STA_REQ_QUEUE_HP] = 0;
iot_list_init(&sta_glb->queue.head[IOT_SG_STA_REQ_QUEUE_MP]);
sta_glb->queue.cnt[IOT_SG_STA_REQ_QUEUE_MP] = 0;
iot_list_init(&sta_glb->queue.head[IOT_SG_STA_REQ_QUEUE_LP]);
sta_glb->queue.cnt[IOT_SG_STA_REQ_QUEUE_LP] = 0;
ret = iot_sg_sta_load_pib_info(sta_glb);
if (ret) {
goto err_load_pib;
}
sta_glb->detect_idx = 0;
sta_glb->debug_cnt = 0;
cert_baund = iot_oem_get_cert_baund();
if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_OVERSEAS_SX) {
if (IOT_FOREIGN_QSXJ_PM_ENABLE) {
sta_glb->cco_bl_invalid_time = 720;
sta_glb->pib.ro->cfg.drv_id = IOT_SG_STA_DRV_ID_QSXJ_PM;
} else {
/* prevents upgrades to non-overseas programs */
IOT_ASSERT(0);
}
} else if (iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_OVERSEAS_SW) {
if (IOT_FOREIGN_1662_PM_ENABLE) {
sta_glb->pib.ro->cfg.drv_id = IOT_SG_STA_DRV_ID_1662_PM;
} else {
/* prevents upgrades to non-overseas programs */
IOT_ASSERT(0);
}
} else if (cert_baund != 0 && cert_baund != 0xFFFFFFFF) {
if (IOT_NW_CT1_DRIVER_ENABLE
|| iot_sg_sta_get_user_type() == USER_TYPE_TM) {
sta_glb->pib.ro->cfg.drv_id = IOT_SG_STA_DRV_ID_CT1;
}
}
if (sta_glb->pib.ro->cfg.drv_id != IOT_SG_STA_DRV_ID_INVALID) {
for (i = 0; i < IOT_SG_STA_DRV_TABLE_SIZE; i++) {
if (g_sta_drv_table[i]) {
/* init requested driver */
if (sta_glb->pib.ro->cfg.drv_id == g_sta_drv_table[i]->drv_id) {
sta_glb->drv = g_sta_drv_table[i];
sta_glb->detect_idx = i;
break;
}
}
}
}
if (sta_glb->pib.ro->cfg.drv_id != IOT_SG_STA_DRV_ID_CT2) {
sta_glb->sta_out_gpio_num = iot_board_get_gpio(GPIO_STA_OUT);
if ((sta_glb->sta_out_gpio_num != 0)
&& (sta_glb->sta_out_gpio_num != 0xff)) {
iot_gpio_open_as_output(sta_glb->sta_out_gpio_num);
iot_gpio_value_set(sta_glb->sta_out_gpio_num, 0);
sta_glb->sta_out_timer = os_create_timer(IOT_SMART_GRID_MID, false,
iot_sg_sta_pinsta_time_func, NULL);
}
}
/* init sta role state machine */
sta_glb->sm.prev_state = iot_sg_sta_state_init;
sta_glb->sm.cur_state = iot_sg_sta_state_init;
sta_glb->sm.func[iot_sg_sta_state_init] = iot_sg_sta_sm_init;
sta_glb->sm.func[iot_sg_sta_state_starting] = iot_sg_sta_sm_starting;
sta_glb->sm.func[iot_sg_sta_state_started] = iot_sg_sta_sm_started;
sta_glb->br2_enable = iot_sg_sta_br2_enable_get();
sta_glb->br2_record_init = 0;
p_sg_glb->desc.sta = sta_glb;
p_sg_glb->msg_exe_func = iot_sg_sta_msg_exe_func;
p_sg_glb->msg_cancel_func = iot_sg_sta_msg_cancel_func;
iot_sg_sta_hw_tsfm_init();
iot_sg_sta_tsfm_collect_init();
iot_sg_sta_tm_init();
iot_sg_sta_event_rpt_seq_init();
if (ERR_OK == iot_sg_sta_brm_init()) {
goto out;
}
err_load_pib:
iot_mem_pool_destroy(sta_glb->queue.q_pool);
create_queue_fail:
os_delete_timer(sta_glb->power_off_timer);
err_power_off:
os_delete_timer(sta_glb->sm_evt_chk_timer);
err_sm_evt_chk_timer:
os_delete_timer(sta_glb->power_on_timer);
err_power_on:
os_delete_timer(sta_glb->refresh_timer);
err_timer_refresh:
os_delete_timer(sta_glb->ext_info.ext_timer);
err_timer_extend_function:
#if IOT_SG_STA_UPGRADE_EXT_DEV_ENABLE
os_delete_timer(sta_glb->upgrade_info.ext_dev_upgrade_timer);
err_timer_ext_dev_upgrade:
#endif
os_delete_timer(sta_glb->upgrade_info.upgrade_timer);
err_timer_upgrade:
os_delete_timer(sta_glb->collect_timer);
err_timer_collect_feature:
os_delete_timer(sta_glb->read_tsfm_timer);
err_timer_read_info:
os_delete_timer(sta_glb->event_rpt_timer);
err_timer_event_rpt:
os_delete_timer(sta_glb->driver_timer);
err_timer_driver:
os_delete_timer(sta_glb->detect_timer);
err_timer_detect:
iot_addr_hash_table_delete(sta_glb->node_bl_table);
err_bl_table:
iot_addr_hash_table_delete(sta_glb->node_table);
err_table:
os_mem_free(sta_glb);
out:
return ret;
}
void iot_sg_sta_deinit()
{
#if HW_PLATFORM == HW_PLATFORM_SIMU
if (p_sg_glb->desc.sta) {
os_delete_timer(p_sg_glb->desc.sta->event_rpt_timer);
os_delete_timer(p_sg_glb->desc.sta->ext_info.ext_timer);
os_delete_timer(p_sg_glb->desc.sta->upgrade_info.upgrade_timer);
os_delete_timer(p_sg_glb->desc.sta->refresh_timer);
os_delete_timer(p_sg_glb->desc.sta->driver_timer);
os_delete_timer(p_sg_glb->desc.sta->detect_timer);
os_delete_timer(p_sg_glb->desc.sta->power_off_timer);
os_delete_timer(p_sg_glb->desc.sta->power_on_timer);
os_delete_timer(p_sg_glb->desc.sta->read_tsfm_timer);
os_delete_timer(p_sg_glb->desc.sta->collect_timer);
iot_mem_pool_destroy(p_sg_glb->desc.sta->queue.q_pool);
iot_addr_hash_table_delete(
p_sg_glb->desc.sta->node_bl_table);
iot_addr_hash_table_delete(p_sg_glb->desc.sta->node_table);
iot_sg_sta_unload_pib_info(p_sg_glb->desc.sta);
iot_sg_sta_flash_deinit();
iot_sg_sta_hw_tsfm_deinit();
iot_sg_sta_tsfm_collect_deinit();
iot_sg_sta_ext_deinit();
os_mem_free(p_sg_glb->desc.sta);
p_sg_glb->desc.sta = NULL;
}
#else
IOT_ASSERT(0);
#endif
}
#endif /* IOT_SMART_GRID_ENABLE && PLC_SUPPORT_STA_ROLE */