568 lines
20 KiB
C
568 lines
20 KiB
C
|
|
/****************************************************************************
|
||
|
|
|
||
|
|
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_utils_api.h"
|
||
|
|
|
||
|
|
/* iot common header files */
|
||
|
|
#include "iot_io_api.h"
|
||
|
|
#include "iot_oem_api.h"
|
||
|
|
|
||
|
|
/* smart grid internal header files */
|
||
|
|
#include "iot_sg_fr.h"
|
||
|
|
#include "iot_sg.h"
|
||
|
|
#include "proto_645.h"
|
||
|
|
#include "proto_69845.h"
|
||
|
|
#include "iot_sg_sta_ext.h"
|
||
|
|
|
||
|
|
#if (IOT_SMART_GRID_EXT_NLI_FUNC_ENABLE)
|
||
|
|
|
||
|
|
static const uint32_t nli_645_07_di_list[] = {
|
||
|
|
PROTO_645_2007_DI_I_A,
|
||
|
|
PROTO_645_2007_DI_I_N,
|
||
|
|
PROTO_645_2007_DI_TIME,
|
||
|
|
PROTO_645_2007_DI_TIME_YMD,
|
||
|
|
PROTO_645_2007_DI_TIME_HMS,
|
||
|
|
};
|
||
|
|
|
||
|
|
void iot_sg_sta_ext_nli_info_reset(void)
|
||
|
|
{
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
|
||
|
|
|
||
|
|
ext_info->nli_info.di_idx = 0;
|
||
|
|
ext_info->nli_info.flag_resp = 0;
|
||
|
|
ext_info->nli_info.repeat_cnt = 0;
|
||
|
|
ext_info->nli_info.state = IOT_SG_STA_EXT_NLI_STATE_IDLE;
|
||
|
|
ext_info->nli_info.timeout_cnt = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void iot_sg_sta_ext_nli_node_reset(void)
|
||
|
|
{
|
||
|
|
uint8_t i;
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
|
||
|
|
for (i = 0; i < IOT_SG_STA_SEC_NODE_MAX; i++) {
|
||
|
|
if (sta_glb->node_list[i] != NULL) {
|
||
|
|
sta_glb->node_list[i]->nli_detected = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void iot_sg_sta_ext_nli_rpt_info_reset(void)
|
||
|
|
{
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &p_sg_glb->desc.sta->ext_info;
|
||
|
|
iot_sg_sta_ext_nli_evt_rpt_info_t *rpt_info = &ext_info->nli_rpt_info;
|
||
|
|
|
||
|
|
if (rpt_info->pkt) {
|
||
|
|
iot_pkt_free(rpt_info->pkt);
|
||
|
|
}
|
||
|
|
os_mem_set(rpt_info, 0, sizeof(*rpt_info));
|
||
|
|
}
|
||
|
|
|
||
|
|
void iot_sg_sta_ext_nli_reset(void)
|
||
|
|
{
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
iot_sg_sta_ext_nli_info_t *nli_info = &sta_glb->ext_info.nli_info;
|
||
|
|
|
||
|
|
nli_info->next_time = 0;
|
||
|
|
iot_sg_sta_ext_nli_node_reset();
|
||
|
|
iot_sg_sta_ext_nli_info_reset();
|
||
|
|
iot_sg_sta_ext_nli_rpt_info_reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
void iot_sg_sta_ext_nl_abnormal_detect_state_set(uint8_t enable)
|
||
|
|
{
|
||
|
|
uint8_t ref;
|
||
|
|
uint16_t ticket;
|
||
|
|
iot_sg_sta_app_info_t *sta_pib = iot_sg_sta_get_rw_pib();
|
||
|
|
|
||
|
|
if (sta_pib == NULL ||
|
||
|
|
iot_sg_sta_get_user_type() != USER_TYPE_STATE_GRID_XIAN) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
iot_sg_printf("%s - %lu\n", __FUNCTION__, enable);
|
||
|
|
if (sta_pib->ext_nli_valid) {
|
||
|
|
if (sta_pib->ext_nli_en == !!enable) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
iot_pib_acquire_app_commit_ref(&ref);
|
||
|
|
sta_pib->ext_nli_en = !!enable;
|
||
|
|
sta_pib->ext_nli_valid = 1;
|
||
|
|
iot_pib_release_app_commit_ref(&ref);
|
||
|
|
iot_pib_app_commit(&ticket);
|
||
|
|
iot_sg_sta_ext_nli_reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t iot_sg_sta_ext_nl_abnormal_detect_state_get(void)
|
||
|
|
{
|
||
|
|
uint8_t ret = 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_XIAN) {
|
||
|
|
if (sta_pib != NULL && sta_pib->ext_nli_valid == 1) {
|
||
|
|
ret = (uint8_t)sta_pib->ext_nli_en;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void iot_sg_sta_ext_nli_evt_node_add(
|
||
|
|
iot_sg_sta_ext_nli_evt_data_t *data)
|
||
|
|
{
|
||
|
|
uint32_t pkt_len = 0;
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &p_sg_glb->desc.sta->ext_info;
|
||
|
|
iot_sg_sta_ext_nli_evt_rpt_info_t *rpt_info = &ext_info->nli_rpt_info;
|
||
|
|
iot_sg_sta_ext_nli_evt_data_field_t *rpt_hdr = NULL;
|
||
|
|
iot_pkt_t *pkt = NULL;
|
||
|
|
|
||
|
|
if (rpt_info->pkt == NULL) {
|
||
|
|
/* if cache pkt is null, create a pkt that can store
|
||
|
|
* IOT_STA_EXT_NLI_EVT_PKT_PM_CNT_DEFAULT nodes.
|
||
|
|
*/
|
||
|
|
pkt_len = sizeof(*rpt_hdr) +
|
||
|
|
sizeof(*data) * IOT_STA_EXT_NLI_EVT_PKT_PM_CNT_DEFAULT;
|
||
|
|
rpt_info->pkt = iot_pkt_alloc(pkt_len, IOT_SMART_GRID_MID);
|
||
|
|
if (rpt_info->pkt == NULL) {
|
||
|
|
iot_sg_printf("%s err mem 1\n", __FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
rpt_hdr = (iot_sg_sta_ext_nli_evt_data_field_t *)
|
||
|
|
iot_pkt_data(rpt_info->pkt);
|
||
|
|
iot_pkt_put(rpt_info->pkt, sizeof(*rpt_hdr));
|
||
|
|
} else if (iot_pkt_tail_len(rpt_info->pkt) < sizeof(*data)) {
|
||
|
|
/* if cache pkt is lack, expand the size of the cache pkt. */
|
||
|
|
pkt = iot_pkt_alloc(iot_pkt_data_len(rpt_info->pkt)
|
||
|
|
+ sizeof(*data), IOT_SMART_GRID_MID);
|
||
|
|
if (pkt == NULL) {
|
||
|
|
iot_sg_printf("%s err mem 2\n", __FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
iot_pkt_cpy(pkt, rpt_info->pkt);
|
||
|
|
iot_pkt_free(rpt_info->pkt);
|
||
|
|
rpt_info->pkt = pkt;
|
||
|
|
}
|
||
|
|
rpt_hdr = (iot_sg_sta_ext_nli_evt_data_field_t *)
|
||
|
|
iot_pkt_data(rpt_info->pkt);
|
||
|
|
rpt_hdr->rpt_cnt++;
|
||
|
|
os_mem_cpy(iot_pkt_tail(rpt_info->pkt), data, sizeof(*data));
|
||
|
|
iot_pkt_put(rpt_info->pkt, sizeof(*data));
|
||
|
|
}
|
||
|
|
|
||
|
|
void iot_sg_sta_ext_nli_evt_ack_done(void)
|
||
|
|
{
|
||
|
|
iot_sg_sta_ext_nli_rpt_info_reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t iot_sg_sta_ext_nli_seq_check(uint16_t seq)
|
||
|
|
{
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &p_sg_glb->desc.sta->ext_info;
|
||
|
|
iot_sg_sta_ext_nli_evt_rpt_info_t *rpt_info = &ext_info->nli_rpt_info;
|
||
|
|
|
||
|
|
if (rpt_info->pkt && rpt_info->seq == seq) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint32_t iot_sg_sta_ext_nli_evt_rpt_start(void)
|
||
|
|
{
|
||
|
|
uint32_t ret = ERR_OK;
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &p_sg_glb->desc.sta->ext_info;
|
||
|
|
iot_sg_sta_ext_nli_evt_rpt_info_t *rpt_info = &ext_info->nli_rpt_info;
|
||
|
|
|
||
|
|
if (rpt_info->pkt) {
|
||
|
|
iot_sg_printf("%s start\n", __FUNCTION__);
|
||
|
|
rpt_info->report_cnt = 0;
|
||
|
|
rpt_info->timeout_cnt = IOT_SG_STA_EXT_NLI_EVT_RPT_START;
|
||
|
|
rpt_info->seq = 0;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
void iot_sg_sta_ext_nli_rpt_refresh(void)
|
||
|
|
{
|
||
|
|
uint32_t ret;
|
||
|
|
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;
|
||
|
|
|
||
|
|
if (iot_sg_sta_get_user_type() != USER_TYPE_STATE_GRID_XIAN
|
||
|
|
|| rpt_info->pkt == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (rpt_info->timeout_cnt) {
|
||
|
|
rpt_info->timeout_cnt--;
|
||
|
|
if (!rpt_info->timeout_cnt) {
|
||
|
|
if (rpt_info->report_cnt < IOT_SG_STA_EXT_NLI_REPEAT_MAX) {
|
||
|
|
ret = iot_sg_sta_report_nli_event(
|
||
|
|
(iot_sg_sta_ext_nli_evt_data_field_t *)
|
||
|
|
iot_pkt_data(rpt_info->pkt));
|
||
|
|
if (ret == ERR_OK) {
|
||
|
|
rpt_info->report_cnt++;
|
||
|
|
rpt_info->timeout_cnt = IOT_SG_STA_EXT_NLI_REPORT_TIMEOUT;
|
||
|
|
iot_sg_printf("%s nli evt rpt %luth\n", __FUNCTION__,
|
||
|
|
rpt_info->report_cnt);
|
||
|
|
} else if (ret == ERR_NOSUPP) {
|
||
|
|
iot_sg_sta_ext_nli_evt_ack_done();
|
||
|
|
iot_sg_printf("%s nli evt rpt nosuppt\n", __FUNCTION__);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
iot_sg_sta_ext_nli_evt_ack_done();
|
||
|
|
iot_sg_printf("%s nli evt rpt failed\n", __FUNCTION__);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static iot_pkt_t *iot_sg_ext_nli_69845_mr_msg_build(uint8_t *addr)
|
||
|
|
{
|
||
|
|
uint8_t i, attribute;
|
||
|
|
uint32_t get_list_req_size, oad;
|
||
|
|
iot_pkt_t *pkt = NULL, *get_list_req = NULL;
|
||
|
|
proto_69845_app_get_list_req_info_t *req = NULL;
|
||
|
|
server_addr_info_t server = {0};
|
||
|
|
iot_sg_sta_ext_nli_info_t *nli_info = &p_sg_glb->desc.sta->ext_info.nli_info;
|
||
|
|
|
||
|
|
get_list_req_size = sizeof(proto_69845_app_oad_t) * 3 + sizeof(*req);
|
||
|
|
get_list_req = iot_pkt_alloc(get_list_req_size, IOT_SMART_GRID_MID);
|
||
|
|
if (!get_list_req) {
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
req = (proto_69845_app_get_list_req_info_t *)iot_pkt_put(get_list_req,
|
||
|
|
get_list_req_size);
|
||
|
|
req->type = PROTO_69845_APP_GET_NORMALLIST;
|
||
|
|
req->piid.priority = PROTO_69845_APP_PIID_PRIORITY_GENERAL;
|
||
|
|
req->piid.sn = iot_sg_sta_ext_get_69845_apdu_sn();
|
||
|
|
|
||
|
|
for (i = 0; i <= IOT_SG_STA_EXT_NLI_READ_TIME; i++) {
|
||
|
|
oad = proto_645_di_to_698_oad(nli_645_07_di_list[i]);
|
||
|
|
if (oad != PROTO_69845_APP_OAD_INVALID) {
|
||
|
|
req->oad[i].oi = (uint16_t)(oad >> 16);
|
||
|
|
attribute = (oad >> 8) & 0xff;
|
||
|
|
req->oad[i].attribute_id = attribute & 0x1f;
|
||
|
|
req->oad[i].attribute_char = attribute >> 5;
|
||
|
|
req->oad[i].element_index = oad & 0xff;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
nli_info->di_idx = IOT_SG_STA_EXT_NLI_READ_TIME;
|
||
|
|
req->oad_cnt = IOT_SG_STA_EXT_NLI_READ_TIME + 1;
|
||
|
|
server.len = PROTO_69845_SA_LEN;
|
||
|
|
server.type = PROTO_69845_SA_TYPE_SIG;
|
||
|
|
iot_mac_addr_cpy(server.addr, addr);
|
||
|
|
pkt = proto_69845_build_get_req_msg_with_rn(req, &server);
|
||
|
|
iot_pkt_free(get_list_req);
|
||
|
|
out:
|
||
|
|
return pkt;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void iot_sg_ext_nli_evt_check(uint8_t *addr)
|
||
|
|
{
|
||
|
|
uint32_t d_value = 0;
|
||
|
|
int32_t phase_a = 0, gnd_a = 0;
|
||
|
|
iot_pkt_t *pkt = NULL;
|
||
|
|
iot_sg_sta_ext_nli_evt_data_t *evt_node = NULL;
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
iot_sg_sta_ext_meter_data_t *data = &sta_glb->ext_info.meter_data;
|
||
|
|
|
||
|
|
if (!proto_645_bcd_data_check(data->a.a, PROTO_645_07_A_LEN, 1) ||
|
||
|
|
!proto_645_bcd_data_check(data->gnd_a, PROTO_645_07_A_LEN, 1)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
phase_a = proto_645_bcd_to_integer(data->a.a, PROTO_645_07_A_LEN, 1);
|
||
|
|
gnd_a = proto_645_bcd_to_integer(data->gnd_a, PROTO_645_07_A_LEN, 1);
|
||
|
|
if (IOT_ABS(gnd_a) > IOT_ABS(phase_a)) {
|
||
|
|
/* If the neutral wire current is greater than the live wire
|
||
|
|
* current by more than 100mA, record the event.
|
||
|
|
*/
|
||
|
|
d_value = IOT_ABS(gnd_a) - IOT_ABS(phase_a);
|
||
|
|
if (d_value > IOT_STA_EXT_NLI_EVT_TRIGGER_VALUE) {
|
||
|
|
pkt = iot_pkt_alloc(sizeof(*evt_node), IOT_SMART_GRID_MID);
|
||
|
|
if (!pkt) {
|
||
|
|
iot_sg_printf("%s err mem\n", __FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
evt_node = (iot_sg_sta_ext_nli_evt_data_t *)iot_pkt_data(pkt);
|
||
|
|
iot_mac_addr_cpy(evt_node->pm_addr, addr);
|
||
|
|
os_mem_cpy(evt_node->phase_electric,data->a.a,
|
||
|
|
GW_APP_ELECTRIC_CURRENT_LEN);
|
||
|
|
os_mem_cpy(evt_node->neutralwire_electric,data->gnd_a,
|
||
|
|
GW_APP_ELECTRIC_CURRENT_LEN);
|
||
|
|
proto_645_unsig_to_bcd(d_value, GW_APP_ELECTRIC_CURRENT_LEN,
|
||
|
|
evt_node->nl_electric);
|
||
|
|
evt_node->time[0] = data->time.second;
|
||
|
|
evt_node->time[1] = data->time.minute;
|
||
|
|
evt_node->time[2] = data->time.hour;
|
||
|
|
evt_node->time[3] = data->time.day;
|
||
|
|
evt_node->time[4] = data->time.month;
|
||
|
|
evt_node->time[5] = data->time.year;
|
||
|
|
iot_sg_sta_ext_nli_evt_node_add(evt_node);
|
||
|
|
iot_sg_printf("%s nli event happened\n", __FUNCTION__);
|
||
|
|
iot_pkt_free(pkt);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void iot_sg_sta_ext_nli_read_handle(uint16_t seq,
|
||
|
|
uint8_t data_type, uint8_t *resp_data, uint16_t resp_len,
|
||
|
|
uint8_t *req_data, uint16_t req_len)
|
||
|
|
{
|
||
|
|
uint32_t ret = ERR_INVAL;
|
||
|
|
uint8_t flag_nack = 0;
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
|
||
|
|
|
||
|
|
if (data_type == IOT_SG_STA_DATA_TYPE_69845) {
|
||
|
|
ret = iot_sg_ext_read_698_data_handle(seq, data_type, resp_data,
|
||
|
|
resp_len, req_data, req_len);
|
||
|
|
} else if (data_type == IOT_SG_STA_DATA_TYPE_645_07) {
|
||
|
|
ret = iot_sg_ext_read_645_07_data_handle(seq, data_type, resp_data,
|
||
|
|
resp_len, req_data, req_len, &flag_nack);
|
||
|
|
}
|
||
|
|
if (ret == ERR_OK || ret == ERR_TIMEOVER) {
|
||
|
|
if (ret == ERR_OK) {
|
||
|
|
ext_info->nli_info.flag_resp = !flag_nack;
|
||
|
|
ext_info->nli_info.repeat_cnt = 0;
|
||
|
|
}
|
||
|
|
ext_info->nli_info.timeout_cnt = 0;
|
||
|
|
iot_sg_sta_ext_sm_stop_action();
|
||
|
|
iot_sg_sta_ext_sm_next_action(IOT_SG_STA_EXT_SM_MIN_DELAY);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void iot_sg_sta_ext_nli_plc_link_state_change_handle(uint8_t linked)
|
||
|
|
{
|
||
|
|
if (!linked) {
|
||
|
|
iot_sg_sta_ext_nli_reset();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint8_t iot_sg_sta_ext_nli_detect_state_check(void)
|
||
|
|
{
|
||
|
|
uint8_t ret = IOT_SG_STA_EXT_NLI_DETECTED_STATE_IDLE;
|
||
|
|
uint8_t i, dct = 0, undct = 0;
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
|
||
|
|
for (i = 0; i < IOT_SG_STA_SEC_NODE_MAX; i++) {
|
||
|
|
if (sta_glb->node_list[i] != NULL) {
|
||
|
|
if (sta_glb->node_list[i]->nli_detected) {
|
||
|
|
dct++;
|
||
|
|
} else {
|
||
|
|
undct++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (dct == 0) {
|
||
|
|
/* if all power meter undetected, in IDLE */
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_DETECTED_STATE_IDLE;
|
||
|
|
} else if (undct) {
|
||
|
|
/* if any one undetected, and some meter detected, in BUSY */
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_DETECTED_STATE_BUSY;
|
||
|
|
} else {
|
||
|
|
/* if all power meter detected, in END */
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_DETECTED_STATE_END;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint8_t iot_sg_sta_ext_nli_idle_handle(iot_sg_sta_node_desc_t *node)
|
||
|
|
{
|
||
|
|
uint8_t ret = IOT_SG_STA_EXT_NLI_STATE_END, state;
|
||
|
|
uint64_t time;
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
|
||
|
|
iot_sg_sta_ext_nli_info_t *nli_info = &ext_info->nli_info;
|
||
|
|
|
||
|
|
if (!p_sg_glb->plc_state.link_ready ||
|
||
|
|
!iot_sg_sta_ext_nl_abnormal_detect_state_get()) {
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
if (node->nli_detected) {
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
state = iot_sg_sta_ext_nli_detect_state_check();
|
||
|
|
if (state == IOT_SG_STA_EXT_NLI_DETECTED_STATE_IDLE) {
|
||
|
|
time = os_boot_time64();
|
||
|
|
if (time >= nli_info->next_time) {
|
||
|
|
nli_info->next_time = time + IOT_SG_STA_EXT_NLI_INTER;
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_SEND;
|
||
|
|
}
|
||
|
|
} else if (state == IOT_SG_STA_EXT_NLI_DETECTED_STATE_BUSY) {
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_SEND;
|
||
|
|
}
|
||
|
|
out:
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint8_t iot_sg_sta_ext_nli_wait_handle(iot_sg_sta_node_desc_t *node,
|
||
|
|
uint8_t *flag_new)
|
||
|
|
{
|
||
|
|
uint8_t ret = IOT_SG_STA_EXT_NLI_STATE_WAIT;
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
|
||
|
|
iot_sg_sta_ext_nli_info_t *nli_info = &ext_info->nli_info;
|
||
|
|
|
||
|
|
if (nli_info->flag_resp) {
|
||
|
|
if (node->data_type == IOT_SG_STA_DATA_TYPE_69845) {
|
||
|
|
goto done;
|
||
|
|
} else {
|
||
|
|
if (nli_info->di_idx == IOT_SG_STA_EXT_NLI_READ_TIME ||
|
||
|
|
nli_info->di_idx == IOT_SG_STA_EXT_NLI_READ_TIME_HMS) {
|
||
|
|
/* 645 07 read timestamp or time succeed, deemed complete */
|
||
|
|
goto done;
|
||
|
|
} else {
|
||
|
|
nli_info->di_idx++;
|
||
|
|
*flag_new = 1;
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_SEND;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (nli_info->timeout_cnt) {
|
||
|
|
nli_info->timeout_cnt--;
|
||
|
|
} else {
|
||
|
|
if (nli_info->repeat_cnt) {
|
||
|
|
nli_info->repeat_cnt--;
|
||
|
|
*flag_new = 0;
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_SEND;
|
||
|
|
} else {
|
||
|
|
iot_sg_printf("%s read %lu faild\n", __FUNCTION__,
|
||
|
|
nli_info->di_idx);
|
||
|
|
if (node->data_type == IOT_SG_STA_DATA_TYPE_645_07 &&
|
||
|
|
nli_info->di_idx == IOT_SG_STA_EXT_NLI_READ_TIME) {
|
||
|
|
/* if the timestamp of 645_07 read failed, continue
|
||
|
|
* trying to read the date and time
|
||
|
|
*/
|
||
|
|
nli_info->di_idx++;
|
||
|
|
*flag_new = 1;
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_SEND;
|
||
|
|
} else {
|
||
|
|
/* if other data reading fails, abandoned */
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_END;
|
||
|
|
node->nli_detected = 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
goto out;
|
||
|
|
done:
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_END;
|
||
|
|
node->nli_detected = 1;
|
||
|
|
iot_sg_ext_nli_evt_check(node->entry.addr);
|
||
|
|
out:
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint8_t iot_sg_sta_ext_nli_send_handle(iot_sg_sta_node_desc_t *node,
|
||
|
|
uint8_t flag_new)
|
||
|
|
{
|
||
|
|
uint32_t tmp, di;
|
||
|
|
uint8_t ret = IOT_SG_STA_EXT_NLI_STATE_SEND;
|
||
|
|
iot_pkt_t *pkt = NULL;
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
|
||
|
|
iot_sg_sta_ext_nli_info_t *nli_info = &ext_info->nli_info;
|
||
|
|
|
||
|
|
if (node->data_type == IOT_SG_STA_DATA_TYPE_69845) {
|
||
|
|
iot_sg_printf("%s read 698\n", __FUNCTION__);
|
||
|
|
pkt = iot_sg_ext_nli_69845_mr_msg_build(node->entry.addr);
|
||
|
|
} else if (node->data_type == IOT_SG_STA_DATA_TYPE_645_07) {
|
||
|
|
if (nli_info->di_idx > sizeof(nli_645_07_di_list) /
|
||
|
|
sizeof(nli_645_07_di_list[0])) {
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_END;
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
di = nli_645_07_di_list[nli_info->di_idx];
|
||
|
|
iot_sg_printf("%s read 645 %.8X\n", __FUNCTION__, di);
|
||
|
|
pkt = proto_645_build_mr_msg(PROTO_645_2007_ID, node->entry.addr, di);
|
||
|
|
}
|
||
|
|
if (pkt) {
|
||
|
|
tmp = iot_sg_sta_add_mr_req(IOT_SG_STA_MR_SRC_ID_NLI_DETECT,
|
||
|
|
node->entry.addr, 0, node->data_type, iot_pkt_data(pkt),
|
||
|
|
(uint16_t)iot_pkt_data_len(pkt), IOT_SG_STA_EXT_DRV_READ_TIMEOUT);
|
||
|
|
if (tmp == ERR_OK) {
|
||
|
|
nli_info->flag_resp = 0;
|
||
|
|
ret = IOT_SG_STA_EXT_NLI_STATE_WAIT;
|
||
|
|
nli_info->timeout_cnt = IOT_SG_STA_EXT_READ_DATA_TIMEOUT;
|
||
|
|
if (flag_new) {
|
||
|
|
nli_info->repeat_cnt = 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
iot_pkt_free(pkt);
|
||
|
|
} else {
|
||
|
|
iot_sg_printf("%s err mem\n", __FUNCTION__);
|
||
|
|
}
|
||
|
|
out:
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t iot_sg_sta_ext_nli_func(uint8_t *addr)
|
||
|
|
{
|
||
|
|
uint8_t complete = 0, flag_new = 0;
|
||
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
||
|
|
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
|
||
|
|
iot_sg_sta_ext_nli_info_t *nli_info = &ext_info->nli_info;
|
||
|
|
iot_sg_sta_node_desc_t *node = iot_sg_sta_node_find_by_addr(addr);
|
||
|
|
|
||
|
|
IOT_ASSERT(node);
|
||
|
|
switch (nli_info->state) {
|
||
|
|
case IOT_SG_STA_EXT_NLI_STATE_IDLE:
|
||
|
|
{
|
||
|
|
nli_info->state = iot_sg_sta_ext_nli_idle_handle(node);
|
||
|
|
if (nli_info->state == IOT_SG_STA_EXT_NLI_STATE_END) {
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
/* else state is IOT_SG_STA_EXT_NLI_STATE_SEND,
|
||
|
|
* and enters the case of send.
|
||
|
|
*/
|
||
|
|
flag_new = 1;
|
||
|
|
}
|
||
|
|
case IOT_SG_STA_EXT_NLI_STATE_SEND:
|
||
|
|
{
|
||
|
|
send:
|
||
|
|
nli_info->state = iot_sg_sta_ext_nli_send_handle(node, flag_new);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case IOT_SG_STA_EXT_NLI_STATE_WAIT:
|
||
|
|
{
|
||
|
|
nli_info->state = iot_sg_sta_ext_nli_wait_handle(node, &flag_new);
|
||
|
|
if (nli_info->state == IOT_SG_STA_EXT_NLI_STATE_SEND) {
|
||
|
|
goto send;
|
||
|
|
} else if (nli_info->state == IOT_SG_STA_EXT_NLI_STATE_END) {
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case IOT_SG_STA_EXT_NLI_STATE_END:
|
||
|
|
{
|
||
|
|
done:
|
||
|
|
if (iot_sg_sta_ext_nli_detect_state_check() ==
|
||
|
|
IOT_SG_STA_EXT_NLI_DETECTED_STATE_END) {
|
||
|
|
/* All power meter has been detected neutralwire
|
||
|
|
* and livewire abnormal.
|
||
|
|
*/
|
||
|
|
iot_sg_sta_ext_nli_node_reset();
|
||
|
|
iot_sg_sta_ext_nli_evt_rpt_start();
|
||
|
|
}
|
||
|
|
complete = 1;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
IOT_ASSERT(0);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
return complete;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif /* IOT_SMART_GRID_EXT_NLI_FUNC_ENABLE */
|