8966 lines
281 KiB
C
Executable File
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 */
|