1904 lines
60 KiB
C
1904 lines
60 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.
|
|
|
|
****************************************************************************/
|
|
/* iot common header files */
|
|
#include "iot_io_api.h"
|
|
#include "os_utils_api.h"
|
|
|
|
/* smart grid internal header files */
|
|
#include "iot_sg.h"
|
|
#include "iot_sg_sta_nw.h"
|
|
#include "iot_sg_sta_ext.h"
|
|
#include "iot_sg_sta_ext_ec.h"
|
|
#include "iot_sg_sta_ext_mf.h"
|
|
|
|
#if IOT_SMART_GRID_EDGE_COMPUTING_ENABLE
|
|
|
|
/* define trace debug enable */
|
|
#define IOT_SMART_GRID_EDGE_COMPUTING_TRACE_ENABLE (0)
|
|
|
|
#if IOT_SMART_GRID_EDGE_COMPUTING_TRACE_ENABLE
|
|
#define iot_sg_sta_ext_ec_debug(str, ...) \
|
|
iot_sg_printf("ext ec: "str, ##__VA_ARGS__)
|
|
#else
|
|
#define iot_sg_sta_ext_ec_debug(str, ...)
|
|
#endif
|
|
|
|
/* define state score read maximum count of individual data items */
|
|
#define IOT_SG_STA_EXT_EC_READ_MAX_CNT (1)
|
|
/* define extend function read state score data timeout time,
|
|
* uint is IOT_SG_STA_EXT_SM_DELAY
|
|
*/
|
|
#define IOT_SG_STA_EXT_EC_READ_DATA_TIMEOUT (2)
|
|
/* define edge computing health proto minimum version number */
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_MIN_VER_NUM (8)
|
|
/* define edge computing health power down maximum days */
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_PD_MAX_DAYS (8)
|
|
/* define edge computing health program enable maximum days */
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_PROGRAM_EN_MAX_DAYS (10)
|
|
/* define edge computing health voltage fault maximum days */
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_V_FAULT_MAX_DAYS (5)
|
|
/* define edge computing health electric energy threshold, unit 0.01kwh */
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_ENERGY_THRESHOLD (1000)
|
|
/* define edge computing health open covers maximum days */
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_OC_MAX_DAYS (10)
|
|
/* define edge computing health minimum voltage, unit 0.1v */
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_MIN_V (1600)
|
|
/* define edge computing health maximum voltage, unit 0.1v */
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_MAX_V (2800)
|
|
/* define value invalid voltage value */
|
|
#define IOT_SG_STA_EXT_EC_INVALID_VOLTAGE (0xFFFF)
|
|
/* define number of runs required per startup */
|
|
#define IOT_SG_STA_EXT_EC_PULSE_RUNTIME_ONCE (3)
|
|
|
|
/* define edge computing clock、overvoltage and undervoltage default config */
|
|
#define IOT_SG_STA_EXT_EC_OVERVOLTAGE_DEF_THRESHOLD (260)
|
|
#define IOT_SG_STA_EXT_EC_UNDERVOLTAGE_DEF_THRESHOLD (180)
|
|
#define IOT_SG_STA_EXT_EC_PULSE_DEF_THRESHOLD_US (50)
|
|
#define IOT_SG_STA_EXT_EC_PM_USE_LIFE_YEARS (8)
|
|
#define IOT_SG_STA_EXT_EC_OVERVOLTAGE_DEF_ENABLE (0)
|
|
#define IOT_SG_STA_EXT_EC_UNDERVOLTAGE_DEF_ENABLE (0)
|
|
#define IOT_SG_STA_EXT_EC_PULSE_DEF_ENABLE (0)
|
|
#define IOT_SG_STA_EXT_EC_HEALTH_DEF_ENABLE (0)
|
|
|
|
/* define edge computing function id */
|
|
#define IOT_SG_STA_EXT_EC_FUNC_ID_HEALTH (0)
|
|
#define IOT_SG_STA_EXT_EC_FUNC_ID_OVERVOLTAGE (1)
|
|
#define IOT_SG_STA_EXT_EC_FUNC_ID_UNDERVOLTAGE (2)
|
|
#define IOT_SG_STA_EXT_EC_FUNC_ID_PUSLE (3)
|
|
|
|
static const uint32_t ec_dis_table[] = {
|
|
PROTO_645_2007_DI_RUN_STA_WORD_1,
|
|
PROTO_645_2007_DI_R_PROTO_VER,
|
|
PROTO_645_2007_DI_R_MFG,
|
|
PROTO_645_2007_DI_EPT_POS_ALL_LAST1,
|
|
PROTO_645_2007_DI_EPT_POS_ALL,
|
|
PROTO_645_2007_DI_COVER_OPEN_R,
|
|
PROTO_645_2007_DI_PROGRAM_R,
|
|
PROTO_645_2007_DI_PD_RECORD_LAST6,
|
|
PROTO_645_2007_DI_V_ALL, /* V_ALL and V_A must be last */
|
|
PROTO_645_2007_DI_V_A,
|
|
};
|
|
|
|
static uint8_t iot_sg_sta_ext_get_node_cnt(void)
|
|
{
|
|
uint8_t i, cnt = 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) {
|
|
cnt++;
|
|
}
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_score_subtraction(uint8_t *score, uint8_t sub)
|
|
{
|
|
if (*score > sub + IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
*score -= sub;
|
|
} else {
|
|
*score = IOT_SG_EXT_STATE_MIN_SCORE;
|
|
}
|
|
}
|
|
|
|
static uint8_t iot_sg_sta_ext_score_bit_map_handle(
|
|
iot_sg_sta_drv_score_bit_map_t *bit_map)
|
|
{
|
|
uint8_t score = 100;
|
|
if (bit_map->clock_battery) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_30);
|
|
}
|
|
if (bit_map->proto_ver) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_20);
|
|
}
|
|
if (bit_map->mfg_date) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_40);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->memory) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_50);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->ctrl_loop) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_50);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->inter_card) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_50);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->inter_program) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_50);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->v_fault) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_40);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->open_covers) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_30);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->program) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_30);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->pos_energy) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_40);
|
|
}
|
|
if (score <= IOT_SG_EXT_STATE_MIN_SCORE) {
|
|
goto out;
|
|
}
|
|
if (bit_map->pd_record) {
|
|
iot_sg_sta_ext_score_subtraction(
|
|
&score, IOT_SG_EXT_STATE_WEIGHT_SCORE_40);
|
|
}
|
|
out:
|
|
return score;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_run_word_1_handle(uint8_t *data)
|
|
{
|
|
proto_645_07_rs_word_1_t *word = (proto_645_07_rs_word_1_t *)data;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
ec_info->cache.bitmap.clock_battery = word->clock_battery;
|
|
ec_info->cache.bitmap.memory = word->memory;
|
|
ec_info->cache.bitmap.ctrl_loop = word->ctrl_loop;
|
|
ec_info->cache.bitmap.inter_program = word->inter_program;
|
|
|
|
iot_sg_sta_ext_ec_debug("run word(cb: %d, m: %d, cl: %d, ip: %d)\n",
|
|
word->clock_battery, word->memory, word->ctrl_loop,
|
|
word->inter_program);
|
|
}
|
|
|
|
static int iot_sg_sta_ext_ec_char_last_index(uint8_t *str, uint8_t chr)
|
|
{
|
|
int i = 0, ret = -1;
|
|
|
|
while (1) {
|
|
if (str[i] == '\0') {
|
|
break;
|
|
}
|
|
if (str[i] == chr) {
|
|
ret = i;
|
|
}
|
|
i++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_str_toupper(uint8_t *str)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; str[i] != '\0'; i++) {
|
|
if (str[i] >= 'a' && str[i] <= 'z') {
|
|
str[i] &= 0x5F;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_str_remove_spaces(uint8_t *str)
|
|
{
|
|
int i, j = 0;
|
|
|
|
for (i = 0; str[i] != '\0'; i++) {
|
|
if (str[i] != ' ') {
|
|
str[j++] = str[i];
|
|
}
|
|
}
|
|
str[j] = '\0';
|
|
}
|
|
|
|
static uint32_t iot_sg_sta_ext_ec_strlen(uint8_t *str)
|
|
{
|
|
uint32_t len = 0;
|
|
|
|
while (str[len]) {
|
|
len++;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_health_proto_ver_handle(uint8_t *data)
|
|
{
|
|
uint8_t ver_num = 0, index, i;
|
|
uint32_t ret = ERR_OK;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
uint8_t version[PROTO_645_2007_VER_NUM_LEN + 1];
|
|
uint8_t proto_ver[] = "DL/T645-2007";
|
|
uint8_t ver_len = (uint8_t)iot_sg_sta_ext_ec_strlen(proto_ver);
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
/**
|
|
* proto version format is
|
|
* "DL/T645-2007-23\n",
|
|
* "DL/T 645-2007-21",
|
|
* data is little-endian
|
|
*/
|
|
os_mem_cpy(version + 1, data, PROTO_645_2007_VER_NUM_LEN);
|
|
version[0] = '\0';
|
|
iot_data_reverse(version, PROTO_645_2007_VER_NUM_LEN + 1);
|
|
iot_sg_sta_ext_ec_debug("proto ver %s\n", version);
|
|
iot_sg_sta_ext_ec_str_remove_spaces(version);
|
|
iot_sg_sta_ext_ec_str_toupper(version);
|
|
|
|
if (os_mem_cmp(proto_ver, version, ver_len)) {
|
|
ret = ERR_INVAL;
|
|
goto out;
|
|
}
|
|
|
|
index = (uint8_t)iot_sg_sta_ext_ec_char_last_index(version + ver_len, '-');
|
|
if (index == -1) {
|
|
ret = ERR_INVAL;
|
|
goto out;
|
|
}
|
|
|
|
for (i = ver_len + index + 1; version[i] != '\0'; i++) {
|
|
if (version[i] < '0' || version[i] > '9') {
|
|
break;
|
|
}
|
|
ver_num *= 10;
|
|
ver_num += iot_ascii_to_byte(version[i]);
|
|
}
|
|
|
|
if (ver_num < IOT_SG_STA_EXT_EC_HEALTH_MIN_VER_NUM) {
|
|
iot_sg_sta_ext_ec_debug("ext ec: proto %d < %d\n", ver_num,
|
|
IOT_SG_STA_EXT_EC_HEALTH_MIN_VER_NUM);
|
|
ret = ERR_INVAL;
|
|
goto out;
|
|
}
|
|
out:
|
|
if (ret != ERR_OK) {
|
|
iot_sg_printf("ext ec: proto failed\n");
|
|
ec_info->cache.bitmap.proto_ver = 1;
|
|
}
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_mfg_handle(uint8_t *data)
|
|
{
|
|
uint16_t year;
|
|
uint8_t month, day;
|
|
iot_time_tm_t now = { 0 };
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t ec_cfg = {0};
|
|
uint8_t date[PROTO_645_2007_MFG_DATE_LEN + 1];
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
if (iot_sg_sta_rtc_get(&now, 0) ||
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_get(&ec_cfg)) {
|
|
return;
|
|
}
|
|
|
|
// data format is 2000-01-01, little Endian
|
|
os_mem_cpy(date + 1, data, PROTO_645_2007_MFG_DATE_LEN);
|
|
iot_data_reverse(date, IOT_ARRAY_CNT(date));
|
|
date[PROTO_645_2007_MFG_DATE_LEN] = '\0';
|
|
iot_sg_sta_ext_ec_debug("date %s\n", date);
|
|
year = iot_ascii_to_byte(date[0]) * 1000 +
|
|
iot_ascii_to_byte(date[1]) * 100 +
|
|
iot_ascii_to_byte(date[2]) * 10 +
|
|
iot_ascii_to_byte(date[3]);
|
|
month = iot_ascii_to_byte(date[5]) * 10 + iot_ascii_to_byte(date[6]);
|
|
day = iot_ascii_to_byte(date[8]) * 10 + iot_ascii_to_byte(date[9]);
|
|
year += ec_cfg.pm_use_life;
|
|
if (year < now.tm_year || (year == now.tm_year && (month < now.tm_mon ||
|
|
(month == now.tm_mon && day < now.tm_mday)))) {
|
|
iot_sg_printf("ext ec: err mfg\n");
|
|
ec_info->cache.bitmap.mfg_date = 1;
|
|
}
|
|
}
|
|
|
|
static uint16_t iot_sg_sta_ext_ec_voltage_parse(uint8_t *data)
|
|
{
|
|
uint16_t value = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
|
|
if (iot_bcd_data_check(data, PROTO_645_V_LEN)) {
|
|
value = iot_bcd_to_byte(data[1]) * 100 + iot_bcd_to_byte(data[0]);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static inline uint8_t iot_sg_sta_ext_ec_health_voltage_check(uint16_t voltage)
|
|
{
|
|
return (voltage < IOT_SG_STA_EXT_EC_HEALTH_MIN_V ||
|
|
voltage > IOT_SG_STA_EXT_EC_HEALTH_MAX_V);
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_voltage_handle(uint8_t *data, uint8_t three_phase)
|
|
{
|
|
uint8_t undervoltage = 0, overvoltage = 0;
|
|
uint16_t a_v = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
uint16_t b_v = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
uint16_t c_v = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
proto_645_v_t *voltages;
|
|
iot_sg_sta_node_desc_t *node = NULL;
|
|
iot_sg_sta_ext_info_t *ext_info = &p_sg_glb->desc.sta->ext_info;
|
|
iot_sg_sta_ext_ec_t *ec_info = ext_info->ec_info;
|
|
iot_sg_sta_node_ec_info_t *node_ec_info = NULL;
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t ec_cfg = {0};
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
if(iot_sg_sta_flash_nw_edge_computing_cfg_get(&ec_cfg)) {
|
|
return;
|
|
}
|
|
node = iot_sg_sta_node_find_by_addr(ext_info->addr);
|
|
if (!node) {
|
|
return;
|
|
}
|
|
voltages = (proto_645_v_t *)data;
|
|
a_v = iot_sg_sta_ext_ec_voltage_parse(voltages->a);
|
|
if (three_phase && node->is_three_phase) {
|
|
b_v = iot_sg_sta_ext_ec_voltage_parse(voltages->b);
|
|
c_v = iot_sg_sta_ext_ec_voltage_parse(voltages->c);
|
|
}
|
|
|
|
iot_sg_sta_ext_ec_debug("phase A %d, B is %d, C %d\n", a_v, b_v, c_v);
|
|
if (ec_info->health_run) {
|
|
if ((a_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE &&
|
|
iot_sg_sta_ext_ec_health_voltage_check(a_v)) ||
|
|
(b_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE &&
|
|
iot_sg_sta_ext_ec_health_voltage_check(b_v)) ||
|
|
(c_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE &&
|
|
iot_sg_sta_ext_ec_health_voltage_check(c_v))) {
|
|
iot_sg_printf("ext ec: err voltage\n");
|
|
ec_info->cache.v_fault = 1;
|
|
}
|
|
}
|
|
|
|
node_ec_info = &node->ext_1.ec_info;
|
|
if (ec_info->undervoltage_run) {
|
|
if (a_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE) {
|
|
if (a_v < ec_cfg.threshold_undervoltage * 10) {
|
|
undervoltage = 1;
|
|
}
|
|
if (node_ec_info->min_va == IOT_SG_STA_EXT_EC_INVALID_VOLTAGE ||
|
|
a_v < node_ec_info->min_va) {
|
|
node_ec_info->min_va = a_v;
|
|
}
|
|
}
|
|
if (b_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE) {
|
|
if (b_v < ec_cfg.threshold_undervoltage * 10) {
|
|
undervoltage = 1;
|
|
}
|
|
if (node_ec_info->min_vb == IOT_SG_STA_EXT_EC_INVALID_VOLTAGE ||
|
|
b_v < node_ec_info->min_vb) {
|
|
node_ec_info->min_vb = b_v;
|
|
}
|
|
}
|
|
if (c_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE) {
|
|
if (c_v < ec_cfg.threshold_undervoltage * 10) {
|
|
undervoltage = 1;
|
|
}
|
|
if (node_ec_info->min_vc == IOT_SG_STA_EXT_EC_INVALID_VOLTAGE ||
|
|
c_v < node_ec_info->min_vc) {
|
|
node_ec_info->min_vc = c_v;
|
|
}
|
|
}
|
|
if (undervoltage) {
|
|
node_ec_info->undervoltage_cnt++;
|
|
if (node_ec_info->undervoltage_cnt >= ec_cfg.count_undervoltage) {
|
|
ec_info->undervoltage_event = 1;
|
|
node_ec_info->undervoltage = 1;
|
|
iot_sg_printf("ext ec: undervoltage\n");
|
|
}
|
|
} else {
|
|
node->ext_1.ec_info.undervoltage = 0;
|
|
node->ext_1.ec_info.undervoltage_cnt = 0;
|
|
node->ext_1.ec_info.min_va = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node->ext_1.ec_info.min_vb = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node->ext_1.ec_info.min_vc = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
}
|
|
}
|
|
|
|
if (ec_info->overvoltage_run) {
|
|
if (a_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE) {
|
|
if (a_v > ec_cfg.threshold_overvoltage * 10) {
|
|
overvoltage = 1;
|
|
}
|
|
if (node_ec_info->max_va == IOT_SG_STA_EXT_EC_INVALID_VOLTAGE ||
|
|
a_v > node_ec_info->max_va) {
|
|
node_ec_info->max_va = a_v;
|
|
}
|
|
}
|
|
if (b_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE) {
|
|
if (b_v > ec_cfg.threshold_overvoltage * 10) {
|
|
overvoltage = 1;
|
|
}
|
|
if (node_ec_info->max_vb == IOT_SG_STA_EXT_EC_INVALID_VOLTAGE ||
|
|
b_v > node_ec_info->max_vb) {
|
|
node_ec_info->max_vb = b_v;
|
|
}
|
|
}
|
|
if (c_v != IOT_SG_STA_EXT_EC_INVALID_VOLTAGE) {
|
|
if (c_v > ec_cfg.threshold_overvoltage * 10) {
|
|
overvoltage = 1;
|
|
}
|
|
if (node_ec_info->max_vc == IOT_SG_STA_EXT_EC_INVALID_VOLTAGE ||
|
|
c_v > node_ec_info->max_vc) {
|
|
node_ec_info->max_vc = c_v;
|
|
}
|
|
}
|
|
if (overvoltage) {
|
|
node_ec_info->overvoltage_cnt++;
|
|
if (node_ec_info->overvoltage_cnt >= ec_cfg.count_overvoltage) {
|
|
ec_info->overvoltage_event = 1;
|
|
node_ec_info->overvoltage = 1;
|
|
iot_sg_printf("ext ec: overvoltage\n");
|
|
}
|
|
} else {
|
|
node->ext_1.ec_info.overvoltage = 0;
|
|
node->ext_1.ec_info.overvoltage_cnt = 0;
|
|
node->ext_1.ec_info.max_va = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node->ext_1.ec_info.max_vb = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node->ext_1.ec_info.max_vc = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_esp_pos_sum_checks(uint8_t *cur_total)
|
|
{
|
|
uint32_t cur_pos_sum, last_pos_sum, delta;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
cur_pos_sum = iot_bcd_to_byte(cur_total[3]) * 1000000 +
|
|
iot_bcd_to_byte(cur_total[2]) * 10000 +
|
|
iot_bcd_to_byte(cur_total[1]) * 100 + iot_bcd_to_byte(cur_total[0]);
|
|
last_pos_sum = iot_bcd_to_byte(ec_info->cache.last_total[3]) * 1000000 +
|
|
iot_bcd_to_byte(ec_info->cache.last_total[2]) * 10000 +
|
|
iot_bcd_to_byte(ec_info->cache.last_total[1]) * 100 +
|
|
iot_bcd_to_byte(ec_info->cache.last_total[0]);
|
|
if (last_pos_sum <= cur_pos_sum) {
|
|
goto out;
|
|
}
|
|
delta = last_pos_sum - cur_pos_sum;
|
|
if (delta > IOT_SG_STA_EXT_EC_HEALTH_ENERGY_THRESHOLD || !cur_pos_sum) {
|
|
ec_info->cache.bitmap.pos_energy = 1;
|
|
}
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_cover_open_handle(uint8_t *data)
|
|
{
|
|
int64_t delta, day;
|
|
iot_time_tm_t start_tm, now;
|
|
proto_645_07_open_covers_record_t *record;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
if (iot_sg_sta_rtc_get(&now, 0)) {
|
|
goto out;
|
|
}
|
|
record = (proto_645_07_open_covers_record_t *)data;
|
|
if (!record->start_time.year || !record->start_time.month ||
|
|
!record->start_time.day || record->end_time.year ||
|
|
record->end_time.month || record->end_time.day) {
|
|
goto out;
|
|
}
|
|
start_tm.tm_year = iot_bcd_to_byte(record->start_time.year) + 2000;
|
|
start_tm.tm_mon = iot_bcd_to_byte(record->start_time.month);
|
|
start_tm.tm_mday = iot_bcd_to_byte(record->start_time.day);
|
|
start_tm.tm_hour = iot_bcd_to_byte(record->start_time.hour);
|
|
start_tm.tm_min = iot_bcd_to_byte(record->start_time.minute);
|
|
start_tm.tm_sec = iot_bcd_to_byte(record->start_time.second);
|
|
delta = iot_rtc_delta_calc(&start_tm, &now);
|
|
if (delta < 0) {
|
|
goto out;
|
|
}
|
|
day = delta / (60 * 60 * 24);
|
|
if (day >= IOT_SG_STA_EXT_EC_HEALTH_OC_MAX_DAYS) {
|
|
ec_info->cache.bitmap.open_covers = 1;
|
|
iot_sg_printf("ext ec: open cover\n");
|
|
}
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_pd_record_handle(uint8_t *data)
|
|
{
|
|
iot_time_tm_t cur_tm, pd_tm;
|
|
proto_645_07_power_down_record_t *pd_record;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
if (iot_sg_sta_rtc_get(&cur_tm, 0)) {
|
|
goto out;
|
|
}
|
|
pd_record = (proto_645_07_power_down_record_t *)data;
|
|
if (!pd_record->start_time.year || !pd_record->start_time.month ||
|
|
!pd_record->start_time.day) {
|
|
goto out;
|
|
}
|
|
pd_tm.tm_year = iot_bcd_to_byte(pd_record->start_time.year) + 2000;
|
|
pd_tm.tm_mon = iot_bcd_to_byte(pd_record->start_time.month);
|
|
pd_tm.tm_mday = iot_bcd_to_byte(pd_record->start_time.day);
|
|
if (pd_tm.tm_year == cur_tm.tm_year && pd_tm.tm_mon == cur_tm.tm_mon &&
|
|
pd_tm.tm_mday == cur_tm.tm_mday) {
|
|
ec_info->cache.pd_freq = 1;
|
|
iot_sg_printf("ext ec: powerdown\n");
|
|
}
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_program_record_handle(uint8_t *data)
|
|
{
|
|
int64_t delta_time;
|
|
iot_time_tm_t now, start_tm;
|
|
proto_645_07_program_record_t *record;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
if (iot_sg_sta_rtc_get(&now, 0)) {
|
|
goto out;
|
|
}
|
|
record = (proto_645_07_program_record_t *)data;
|
|
if (!record->start_time.year || !record->start_time.month ||
|
|
!record->start_time.day) {
|
|
goto out;
|
|
}
|
|
start_tm.tm_year = iot_bcd_to_byte(record->start_time.year) + 2000;
|
|
start_tm.tm_mon = iot_bcd_to_byte(record->start_time.month);
|
|
start_tm.tm_mday = iot_bcd_to_byte(record->start_time.day);
|
|
start_tm.tm_hour = iot_bcd_to_byte(record->start_time.hour);
|
|
start_tm.tm_min = iot_bcd_to_byte(record->start_time.minute);
|
|
start_tm.tm_sec = iot_bcd_to_byte(record->start_time.second);
|
|
delta_time = iot_rtc_delta_calc(&start_tm, &now);
|
|
if (delta_time > 0 && delta_time < (60 * 60 * 24)) {
|
|
ec_info->cache.program_en = 1;
|
|
iot_sg_printf("ext ec: program\n");
|
|
}
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_resp_handle(
|
|
uint32_t di, uint8_t *data, uint8_t len)
|
|
{
|
|
uint8_t reason = 0;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
switch (di) {
|
|
case PROTO_645_2007_DI_RUN_STA_WORD_1:
|
|
{
|
|
if (len < sizeof(proto_645_07_rs_word_1_t)) {
|
|
reason = 1;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_run_word_1_handle(data);
|
|
break;
|
|
}
|
|
case PROTO_645_2007_DI_R_PROTO_VER:
|
|
{
|
|
if (len < PROTO_645_2007_VER_NUM_LEN) {
|
|
reason = 2;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_health_proto_ver_handle(data);
|
|
break;
|
|
}
|
|
case PROTO_645_2007_DI_R_MFG:
|
|
{
|
|
if (len < PROTO_645_2007_MFG_DATE_LEN) {
|
|
reason = 3;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_mfg_handle(data);
|
|
break;
|
|
}
|
|
case PROTO_645_2007_DI_EPT_POS_ALL_LAST1:
|
|
{
|
|
if (len < sizeof(proto_645_07_energy_data_t)) {
|
|
reason = 4;
|
|
break;
|
|
}
|
|
os_mem_cpy(
|
|
ec_info->cache.last_total, data, PROTO_645_07_ENERGY_DATA_LEN);
|
|
break;
|
|
}
|
|
case PROTO_645_2007_DI_EPT_POS_ALL:
|
|
{
|
|
if (len < sizeof(proto_645_07_energy_data_t)) {
|
|
reason = 5;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_esp_pos_sum_checks(data);
|
|
break;
|
|
}
|
|
case PROTO_645_2007_DI_COVER_OPEN_R:
|
|
{
|
|
if (len < sizeof(proto_645_07_open_covers_record_t)) {
|
|
reason = 6;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_cover_open_handle(data);
|
|
break;
|
|
}
|
|
case PROTO_645_2007_DI_PD_RECORD_LAST6:
|
|
{
|
|
if (len < sizeof(proto_645_07_power_down_record_t)) {
|
|
reason = 7;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_pd_record_handle(data);
|
|
break;
|
|
}
|
|
case PROTO_645_2007_DI_V_ALL:
|
|
{
|
|
if (len < (PROTO_645_V_LEN * 3)) {
|
|
reason = 8;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_voltage_handle(data, 1);
|
|
/* three-phase voltage score success skip single-phase vlotage score */
|
|
ec_info->index++;
|
|
break;
|
|
}
|
|
case PROTO_645_2007_DI_V_A:
|
|
{
|
|
if (len < PROTO_645_V_LEN) {
|
|
reason = 9;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_voltage_handle(data, 0);
|
|
}
|
|
case PROTO_645_2007_DI_PROGRAM_R:
|
|
{
|
|
if (len < sizeof(proto_645_07_program_record_t)) {
|
|
reason = 10;
|
|
break;
|
|
}
|
|
iot_sg_sta_ext_ec_program_record_handle(data);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (reason) {
|
|
iot_sg_printf("ext ec: read failed err %lu\n", reason);
|
|
}
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_data_handle(uint16_t seq, uint8_t data_type,
|
|
uint8_t *resp_data, uint16_t resp_len, uint8_t *req_data, uint16_t req_len)
|
|
{
|
|
uint8_t reason = 0, *data, data_len;
|
|
uint32_t rsp_di;
|
|
proto_645_header_t *resp_hdr, *req_hdr;
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
|
|
|
|
(void)seq;
|
|
if (data_type != IOT_SG_STA_DATA_TYPE_645_07) {
|
|
reason = 1;
|
|
goto out;
|
|
}
|
|
if ((req_data == NULL) || !req_len) {
|
|
reason = 2;
|
|
goto out;
|
|
}
|
|
if ((resp_data == NULL) || !resp_len) {
|
|
reason = 3;
|
|
goto out;
|
|
}
|
|
if (proto_645_check_di_fn_match(req_data, req_len, resp_data, resp_len)) {
|
|
reason = 4;
|
|
goto out;
|
|
}
|
|
resp_hdr = (proto_645_header_t *)resp_data;
|
|
req_hdr = (proto_645_header_t *)req_data;
|
|
if (!iot_mac_addr_cmp(req_hdr->addr, resp_hdr->addr)) {
|
|
reason = 5;
|
|
goto out;
|
|
}
|
|
if ((resp_hdr->control.ack != PROTO_645_ACK_NORMAL) ||
|
|
(resp_hdr->control.dir != PROTO_645_DIR_SLAVE)) {
|
|
reason = 6;
|
|
goto out;
|
|
}
|
|
if (!iot_mac_addr_cmp(ext_info->addr, resp_hdr->addr)) {
|
|
reason = 7;
|
|
goto out;
|
|
}
|
|
if (resp_hdr->len < PROTO_645_2007_DI_LEN) {
|
|
reason = 8;
|
|
goto out;
|
|
}
|
|
proto_645_sub33_handle(resp_hdr->data, resp_hdr->len);
|
|
rsp_di = proto_645_2007_byte_to_di(resp_hdr->data);
|
|
iot_sg_printf("ext ec: di %.8X\n", rsp_di);
|
|
data_len = resp_hdr->len - PROTO_645_2007_DI_LEN;
|
|
data = resp_hdr->data + PROTO_645_2007_DI_LEN;
|
|
iot_sg_sta_ext_ec_resp_handle(rsp_di, data, data_len);
|
|
ext_info->ec_info->respond = 1;
|
|
ext_info->ec_info->timeout = 0;
|
|
iot_sg_sta_ext_sm_stop_action();
|
|
iot_sg_sta_ext_sm_next_action(IOT_SG_STA_EXT_SM_MIN_DELAY);
|
|
return;
|
|
out:
|
|
if (reason) {
|
|
iot_sg_printf("ext ec: pm ack err %lu\n", reason);
|
|
}
|
|
}
|
|
|
|
static uint8_t iot_sg_ext_ec_is_time_valid(iot_time_tm_t tm)
|
|
{
|
|
return (tm.tm_year || tm.tm_mon || tm.tm_mday || tm.tm_hour ||
|
|
tm.tm_min || tm.tm_sec);
|
|
}
|
|
|
|
void iot_sg_ext_ec_get_next_run_datetime(iot_time_tm_t *last)
|
|
{
|
|
iot_time_tm_t now = {0};
|
|
|
|
iot_sg_sta_rtc_get(&now, 0);
|
|
if (!iot_sg_ext_ec_is_time_valid(*last)) {
|
|
if (now.tm_hour >= 22) {
|
|
iot_rtc_delta_add(60 * 60 * 24, &now);
|
|
}
|
|
os_mem_cpy(last, &now, sizeof(now));
|
|
} else {
|
|
iot_rtc_delta_add(60 * 60 * 24, last);
|
|
}
|
|
last->tm_hour = 22;
|
|
last->tm_min = 0;
|
|
last->tm_sec = 0;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_score_save(uint8_t *addr)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
iot_sg_sta_drv_meter_ss_data_t his_data = {0}, data = {0};
|
|
iot_sg_sta_ext_info_t *ext_info = &p_sg_glb->desc.sta->ext_info;
|
|
iot_sg_sta_ext_ec_t *ec_info = ext_info->ec_info;
|
|
iot_sg_sta_node_desc_t *node = NULL;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
os_mem_cpy(&data.bit_map, &ec_info->cache.bitmap, sizeof(data.bit_map));
|
|
ret = iot_sg_sta_flash_score_data_read(addr, (uint8_t *)&his_data,
|
|
sizeof(his_data), IOT_SG_STA_METER_DATA_TYPE_EC);
|
|
|
|
if (ec_info->cache.pd_freq) {
|
|
data.pd_days = ret ? 1 : his_data.pd_days + 1;
|
|
if (data.pd_days >= IOT_SG_STA_EXT_EC_HEALTH_PD_MAX_DAYS) {
|
|
data.bit_map.pd_record = 1;
|
|
}
|
|
}
|
|
if (ec_info->cache.program_en) {
|
|
data.program_en_days = ret ? 1 : his_data.program_en_days + 1;
|
|
if (data.program_en_days >=
|
|
IOT_SG_STA_EXT_EC_HEALTH_PROGRAM_EN_MAX_DAYS) {
|
|
data.bit_map.program = 1;
|
|
}
|
|
}
|
|
if (ec_info->cache.v_fault) {
|
|
data.v_fault_days = ret ? 1 : his_data.v_fault_days + 1;
|
|
if (data.v_fault_days >= IOT_SG_STA_EXT_EC_HEALTH_V_FAULT_MAX_DAYS) {
|
|
data.bit_map.v_fault = 1;
|
|
}
|
|
}
|
|
data.score = iot_sg_sta_ext_score_bit_map_handle(&data.bit_map);
|
|
if (data.score < IOT_SG_EXT_STATE_WEIGHT_SCORE_60) {
|
|
ec_info->health_event = 1;
|
|
node = iot_sg_sta_node_find_by_addr(addr);
|
|
if (node) {
|
|
node->ext_1.ec_info.health = 1;
|
|
}
|
|
}
|
|
iot_sg_printf("ext ec: score %lu(%lu,%lu,%lu) bitmap %.4X\n", data.score,
|
|
data.v_fault_days, data.program_en_days, data.pd_days, data.bit_map);
|
|
if (ret || data.pd_days != his_data.pd_days ||
|
|
data.program_en_days != his_data.program_en_days ||
|
|
data.v_fault_days != his_data.v_fault_days ||
|
|
os_mem_cmp(&data.bit_map, &his_data.bit_map, sizeof(his_data.bit_map))) {
|
|
iot_sg_sta_flash_score_data_save(addr, (uint8_t *)&data,
|
|
sizeof(data), IOT_SG_STA_METER_DATA_TYPE_EC);
|
|
}
|
|
os_mem_set(&ec_info->cache, 0, sizeof(&ec_info->cache));
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_set_start_index(uint8_t index)
|
|
{
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
IOT_ASSERT(index < ec_info->di_cnt);
|
|
ec_info->index = index;
|
|
ec_info->send_cnt = 0;
|
|
ec_info->timeout = 0;
|
|
ec_info->respond = 0;
|
|
}
|
|
|
|
static uint8_t iot_sg_ext_ec_is_finish()
|
|
{
|
|
uint8_t complete = 0;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info || ec_info->index >= ec_info->di_cnt) {
|
|
complete = 1;
|
|
}
|
|
return complete;
|
|
}
|
|
|
|
uint8_t iot_sg_ext_ec_func(uint8_t *addr)
|
|
{
|
|
uint8_t complete = 0;
|
|
uint16_t timeout = 0;
|
|
uint32_t ret;
|
|
iot_pkt_t *pkt = NULL;
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
complete = 1;
|
|
goto out;
|
|
}
|
|
if (iot_sg_ext_ec_is_finish()) {
|
|
complete = 1;
|
|
goto out;
|
|
}
|
|
if (!(ec_info->health_run || ec_info->overvoltage_run ||
|
|
ec_info->undervoltage_run)) {
|
|
complete = 1;
|
|
goto out;
|
|
}
|
|
if (ec_info->timeout) {
|
|
ec_info->timeout--;
|
|
goto out;
|
|
}
|
|
if (ec_info->send_cnt >= IOT_SG_STA_EXT_EC_READ_MAX_CNT ||
|
|
ec_info->respond) {
|
|
ec_info->respond = 0;
|
|
ec_info->send_cnt = 0;
|
|
ec_info->index++;
|
|
}
|
|
if (ec_info->index >= ec_info->di_cnt) {
|
|
if (ec_info->health_run) {
|
|
ec_info->health_complete_cnt++;
|
|
}
|
|
if (ec_info->overvoltage_run) {
|
|
ec_info->ov_complete_cnt++;
|
|
}
|
|
if (ec_info->undervoltage_run) {
|
|
ec_info->uv_complete_cnt++;
|
|
}
|
|
if (ec_info->health_run) {
|
|
iot_sg_sta_ext_ec_set_start_index(0);
|
|
} else if (ec_info->overvoltage_run || ec_info->undervoltage_run) {
|
|
iot_sg_sta_ext_ec_set_start_index((uint8_t)(ec_info->di_cnt - 2));
|
|
}
|
|
if (ec_info->health_run) {
|
|
iot_sg_sta_ext_ec_score_save(addr);
|
|
os_mem_set(&ec_info->cache, 0, sizeof(ec_info->cache));
|
|
}
|
|
complete = 1;
|
|
goto out;
|
|
}
|
|
pkt = proto_645_build_mr_msg(
|
|
PROTO_645_2007_ID, addr, ec_dis_table[ec_info->index]);
|
|
if (pkt) {
|
|
timeout = min(IOT_SG_STA_EXT_EC_READ_DATA_TIMEOUT *
|
|
IOT_SG_STA_EXT_SM_DELAY / 100, IOT_SG_STA_EXT_DRV_READ_TIMEOUT);
|
|
ret = iot_sg_sta_add_mr_req(IOT_SG_STA_MR_SRC_ID_EXT_EC, addr, 0,
|
|
IOT_SG_STA_DATA_TYPE_645_07, iot_pkt_data(pkt),
|
|
(uint16_t)iot_pkt_data_len(pkt), timeout);
|
|
if (ret == ERR_OK) {
|
|
ec_info->timeout = IOT_SG_STA_EXT_EC_READ_DATA_TIMEOUT;
|
|
ec_info->send_cnt++;
|
|
iot_sg_printf("ext ec: di [%d]%08X %luth\n",
|
|
ec_info->index, ec_dis_table[ec_info->index],
|
|
ec_info->send_cnt);
|
|
}
|
|
iot_pkt_free(pkt);
|
|
}
|
|
out:
|
|
return complete;
|
|
}
|
|
|
|
static void iot_sg_ext_ec_default_cfg(
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *cfg)
|
|
{
|
|
IOT_ASSERT(cfg);
|
|
os_mem_set(cfg, 0, sizeof(*cfg));
|
|
cfg->overvoltage_enable = IOT_SG_STA_EXT_EC_OVERVOLTAGE_DEF_ENABLE;
|
|
cfg->undervoltage_enable = IOT_SG_STA_EXT_EC_UNDERVOLTAGE_DEF_ENABLE;
|
|
cfg->pulse_check_enable = IOT_SG_STA_EXT_EC_PULSE_DEF_ENABLE;
|
|
cfg->health_check_enable = IOT_SG_STA_EXT_EC_HEALTH_DEF_ENABLE;
|
|
cfg->threshold_overvoltage = IOT_SG_STA_EXT_EC_OVERVOLTAGE_DEF_THRESHOLD;
|
|
cfg->threshold_undervoltage = IOT_SG_STA_EXT_EC_UNDERVOLTAGE_DEF_THRESHOLD;
|
|
cfg->threshold_pulse = IOT_SG_STA_EXT_EC_PULSE_DEF_THRESHOLD_US;
|
|
cfg->pm_use_life = IOT_SG_STA_EXT_EC_PM_USE_LIFE_YEARS;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_pulse_handle(uint32_t cycle)
|
|
{
|
|
int32_t err_val = 0;
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t ec_cfg = {0};
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
ec_info->pulse_count++;
|
|
ec_info->pulse_err_value += cycle;
|
|
if (ec_info->pulse_count < IOT_SG_STA_EXT_EC_PULSE_RUNTIME_ONCE) {
|
|
iot_sg_sta_ext_mf_start_second_pulse_monitor(
|
|
iot_sg_sta_ext_ec_pulse_handle);
|
|
} else {
|
|
if (iot_sg_sta_flash_nw_edge_computing_cfg_get(&ec_cfg)) {
|
|
return;
|
|
}
|
|
ec_info->pulse_run = 0;
|
|
err_val = (int32_t)(ec_info->pulse_err_value / ec_info->pulse_count);
|
|
err_val = IOT_ABS(err_val - 1000000);
|
|
err_val = min(err_val, 0xFFFF);
|
|
iot_sg_printf("ext ec: pusle err val %d\n", err_val);
|
|
if (err_val > ec_cfg.threshold_pulse) {
|
|
ec_info->pulse_err_value = err_val;
|
|
ec_info->pulse_event = 1;
|
|
} else {
|
|
ec_info->pulse_event = 0;
|
|
ec_info->pulse_err_value = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t iot_sg_sta_ext_ec_init()
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
uint8_t addr[IOT_MAC_ADDR_LEN];
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = NULL;
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t ec_cfg = {0};
|
|
|
|
if (sta_glb->proto != IOT_SG_STA_APP_PROTO_NW) {
|
|
ret = ERR_NOSUPP;
|
|
goto out;
|
|
}
|
|
if (sta_glb->ext_info.ec_info) {
|
|
goto out;
|
|
}
|
|
sta_glb->ext_info.ec_info = os_mem_malloc(IOT_SMART_GRID_MID,
|
|
sizeof(*sta_glb->ext_info.ec_info));
|
|
if (sta_glb->ext_info.ec_info == NULL) {
|
|
ret = ERR_NOMEM;
|
|
goto out;
|
|
}
|
|
ec_info = sta_glb->ext_info.ec_info;
|
|
os_mem_set(ec_info, 0, sizeof(*ec_info));
|
|
ec_info->di_cnt = IOT_ARRAY_CNT(ec_dis_table);
|
|
IOT_ASSERT(ec_info->di_cnt);
|
|
if (iot_sg_sta_flash_nw_edge_computing_cfg_get(&ec_cfg)) {
|
|
iot_sg_printf("ext ec: no cfg\n");
|
|
goto restore;
|
|
}
|
|
ec_info->health_enable = ec_cfg.health_check_enable;
|
|
ec_info->overvoltage_enable = ec_cfg.overvoltage_enable;
|
|
ec_info->undervoltage_enable = ec_cfg.undervoltage_enable;
|
|
ec_info->pulse_check_enable = ec_cfg.pulse_check_enable;
|
|
if (sta_glb->drv->dev_type == IOT_SG_STA_DEV_TYPE_POWER_METER) {
|
|
sta_glb->drv->get_login_addr(addr);
|
|
if (!iot_mac_addr_cmp(addr, ec_cfg.addr)) {
|
|
goto restore;
|
|
}
|
|
}
|
|
goto out;
|
|
|
|
restore:
|
|
iot_sg_ext_ec_default_cfg(&ec_cfg);
|
|
iot_sg_sta_ec_set_config(&ec_cfg);
|
|
iot_sg_printf("ext ec: restore\n");
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_deinit()
|
|
{
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
|
|
if (sta_glb->ext_info.ec_info == NULL) {
|
|
return;
|
|
}
|
|
os_mem_set(sta_glb->ext_info.ec_info, 0,
|
|
sizeof(*sta_glb->ext_info.ec_info));
|
|
os_mem_free(sta_glb->ext_info.ec_info);
|
|
sta_glb->ext_info.ec_info = NULL;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_health_config_changed(
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *old,
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *new)
|
|
{
|
|
uint8_t index = 0;
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_node_ec_info_t *node_ec_info = NULL;
|
|
|
|
if (old->health_check_enable != new->health_check_enable) {
|
|
iot_sg_printf("ext ec: cfg health %lu %lu\n",
|
|
new->health_check_enable, new->pm_use_life);
|
|
ec_info->health_run = 0;
|
|
ec_info->health_event = 0;
|
|
os_mem_set(&ec_info->next_health_time, 0,
|
|
sizeof(ec_info->next_health_time));
|
|
os_mem_set(&ec_info->cache, 0, sizeof(ec_info->cache));
|
|
for (index = 0; index < IOT_SG_STA_SEC_NODE_MAX; index++) {
|
|
if (sta_glb->node_list[index] != NULL) {
|
|
node_ec_info = &sta_glb->node_list[index]->ext_1.ec_info;
|
|
node_ec_info->health = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_overvoltage_config_changed(
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *old,
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *new)
|
|
{
|
|
uint8_t index = 0;
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_node_ec_info_t *node_ec_info = NULL;
|
|
|
|
if (old->overvoltage_enable != new->overvoltage_enable ||
|
|
old->count_overvoltage != new->count_overvoltage ||
|
|
old->period_overvoltage != new->period_overvoltage ||
|
|
old->threshold_overvoltage != new->threshold_overvoltage) {
|
|
iot_sg_printf("ext ec: cfg ov %lu %lu %lu %lu\n",
|
|
new->overvoltage_enable, new->count_overvoltage,
|
|
new->period_overvoltage, new->threshold_overvoltage);
|
|
ec_info->overvoltage_run = 0;
|
|
ec_info->next_ov_time = 0;
|
|
for (index = 0; index < IOT_SG_STA_SEC_NODE_MAX; index++) {
|
|
if (sta_glb->node_list[index] != NULL) {
|
|
node_ec_info = &sta_glb->node_list[index]->ext_1.ec_info;
|
|
node_ec_info->max_va = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node_ec_info->max_vb = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node_ec_info->max_vc = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node_ec_info->overvoltage_cnt = 0;
|
|
node_ec_info->overvoltage = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_undervoltage_config_changed(
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *old,
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *new)
|
|
{
|
|
uint8_t index = 0;
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_node_ec_info_t *node_ec_info = NULL;
|
|
|
|
if (old->undervoltage_enable != new->undervoltage_enable ||
|
|
old->count_undervoltage != new->count_undervoltage ||
|
|
old->period_undervoltage != new->period_undervoltage ||
|
|
old->threshold_undervoltage != new->threshold_undervoltage) {
|
|
iot_sg_printf("ext ec: cfg uv %lu %lu %lu %lu\n",
|
|
new->undervoltage_enable, new->count_undervoltage,
|
|
new->period_undervoltage, new->threshold_undervoltage);
|
|
ec_info->undervoltage_run = 0;
|
|
ec_info->next_uv_time = 0;
|
|
for (index = 0; index < IOT_SG_STA_SEC_NODE_MAX; index++) {
|
|
if (sta_glb->node_list[index] != NULL) {
|
|
node_ec_info = &sta_glb->node_list[index]->ext_1.ec_info;
|
|
node_ec_info->min_va = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node_ec_info->min_vb = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node_ec_info->min_vc = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node_ec_info->undervoltage_cnt = 0;
|
|
node_ec_info->undervoltage = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_pulse_config_changed(
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *old,
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *new)
|
|
{
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (old->pulse_check_enable != new->pulse_check_enable) {
|
|
iot_sg_printf("ext ec: cfg pulse %lu %lu\n", new->pulse_check_enable,
|
|
new->threshold_pulse);
|
|
os_mem_set(&ec_info->next_pulse_time, 0,
|
|
sizeof(ec_info->next_pulse_time));
|
|
if (!new->pulse_check_enable) {
|
|
iot_sg_sta_ext_mf_stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_config_changed(
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *old,
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *new)
|
|
{
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
|
|
IOT_ASSERT(old && new);
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
|
|
ec_info->health_enable = new->health_check_enable;
|
|
ec_info->overvoltage_enable = new->overvoltage_enable;
|
|
ec_info->undervoltage_enable = new->undervoltage_enable;
|
|
ec_info->pulse_check_enable = new->pulse_check_enable;
|
|
iot_sg_sta_ext_ec_health_config_changed(old, new);
|
|
iot_sg_sta_ext_ec_overvoltage_config_changed(old, new);
|
|
iot_sg_sta_ext_ec_undervoltage_config_changed(old, new);
|
|
iot_sg_sta_ext_ec_pulse_config_changed(old, new);
|
|
}
|
|
|
|
uint32_t iot_sg_sta_ec_set_config(
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *cfg)
|
|
{
|
|
uint32_t ret = ERR_OK, length;
|
|
uint8_t addr[IOT_MAC_ADDR_LEN];
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t cfg_loacl = {0};
|
|
|
|
if (!ec_info) {
|
|
ret = ERR_NOSUPP;
|
|
goto out;
|
|
}
|
|
|
|
iot_sg_printf("ext ec: set cfg\n");
|
|
sta_glb->drv->get_login_addr(addr);
|
|
iot_mac_addr_cpy(cfg->addr, addr);
|
|
|
|
if (cfg->period_undervoltage == 0) {
|
|
cfg->period_undervoltage = 1;
|
|
}
|
|
if (cfg->period_overvoltage == 0) {
|
|
cfg->period_overvoltage = 1;
|
|
}
|
|
|
|
if(iot_sg_sta_flash_nw_edge_computing_cfg_get(&cfg_loacl)) {
|
|
os_mem_set(&cfg_loacl, 0xFF, sizeof(cfg_loacl));
|
|
}
|
|
|
|
length = sizeof(cfg->crc) + IOT_MAC_ADDR_LEN;
|
|
if (os_mem_cmp(cfg, &cfg_loacl, sizeof(*cfg) - length)) {
|
|
ret = iot_sg_sta_flash_nw_edge_computing_cfg_save(cfg);
|
|
if (ret == ERR_OK && ec_info) {
|
|
iot_sg_sta_ext_ec_config_changed(&cfg_loacl, cfg);
|
|
}
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_health_check()
|
|
{
|
|
iot_time_tm_t now = {0};
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
|
|
if (!ec_info->health_enable || iot_sg_sta_rtc_valid_check(0)) {
|
|
return;
|
|
}
|
|
|
|
if (ec_info->health_run) {
|
|
if (ec_info->health_complete_cnt >= iot_sg_sta_ext_get_node_cnt()) {
|
|
ec_info->health_run = 0;
|
|
}
|
|
} else {
|
|
iot_sg_sta_rtc_get(&now, 0);
|
|
if (!iot_sg_ext_ec_is_time_valid(ec_info->next_health_time)) {
|
|
iot_sg_ext_ec_get_next_run_datetime(&ec_info->next_health_time);
|
|
}
|
|
if (iot_rtc_delta_calc(&ec_info->next_health_time, &now) >= 0) {
|
|
iot_sg_ext_ec_get_next_run_datetime(&ec_info->next_health_time);
|
|
iot_sg_printf("ext ec: health %04d-%02d-%02d %02d:%02d:%02d\n",
|
|
now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min,
|
|
now.tm_sec);
|
|
ec_info->health_run = 1;
|
|
ec_info->health_complete_cnt = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_voltage_check()
|
|
{
|
|
uint32_t current = 0;
|
|
uint8_t meter_count = iot_sg_sta_ext_get_node_cnt();
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t ec_cfg = {0};
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (!ec_info) {
|
|
goto out;
|
|
}
|
|
|
|
if (!ec_info->overvoltage_run || !ec_info->undervoltage_run) {
|
|
current = (uint32_t)(os_boot_time64() / 1000);
|
|
if (iot_sg_sta_flash_nw_edge_computing_cfg_get(&ec_cfg)) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (ec_info->overvoltage_enable) {
|
|
if (!ec_info->overvoltage_run) {
|
|
if (!ec_info->next_ov_time) {
|
|
ec_info->next_ov_time = current;
|
|
}
|
|
if (ec_info->next_ov_time <= current) {
|
|
ec_info->next_ov_time += ec_cfg.period_overvoltage * 60;
|
|
ec_info->overvoltage_run = 1;
|
|
ec_info->ov_complete_cnt = 0;
|
|
}
|
|
} else if (ec_info->ov_complete_cnt >= meter_count) {
|
|
ec_info->overvoltage_run = 0;
|
|
}
|
|
}
|
|
|
|
if (ec_info->undervoltage_enable) {
|
|
if (!ec_info->undervoltage_run) {
|
|
if (!ec_info->next_uv_time) {
|
|
ec_info->next_uv_time = current;
|
|
}
|
|
if (ec_info->next_uv_time <= current) {
|
|
ec_info->next_uv_time += ec_cfg.period_undervoltage * 60;
|
|
ec_info->undervoltage_run = 1;
|
|
ec_info->uv_complete_cnt = 0;
|
|
}
|
|
} else if (ec_info->uv_complete_cnt >= meter_count) {
|
|
ec_info->undervoltage_run = 0;
|
|
}
|
|
}
|
|
out:
|
|
return;
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_check(void)
|
|
{
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (ec_info == NULL) {
|
|
return;
|
|
}
|
|
iot_sg_sta_ext_ec_health_check();
|
|
iot_sg_sta_ext_ec_voltage_check();
|
|
|
|
if (ec_info->health_run) {
|
|
iot_sg_sta_ext_ec_set_start_index(0);
|
|
} else if (ec_info->overvoltage_run || ec_info->undervoltage_run) {
|
|
iot_sg_sta_ext_ec_set_start_index((uint8_t)(ec_info->di_cnt - 2));
|
|
}
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_tm_update_handle(void)
|
|
{
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (ec_info == NULL) {
|
|
return;
|
|
}
|
|
|
|
iot_sg_printf("ext ec: tm update\n");
|
|
os_mem_set(&ec_info->next_health_time, 0,
|
|
sizeof(ec_info->next_health_time));
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_pulse_time_reset_handle(void)
|
|
{
|
|
iot_sg_sta_ext_ec_t *ec_info = p_sg_glb->desc.sta->ext_info.ec_info;
|
|
|
|
if (ec_info == NULL) {
|
|
return;
|
|
}
|
|
|
|
iot_sg_printf("ext ec: pulse tm reset\n");
|
|
os_mem_set(&ec_info->next_pulse_time, 0, sizeof(ec_info->next_pulse_time));
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_node_data_reset(iot_sg_sta_node_desc_t *node)
|
|
{
|
|
if (!node) {
|
|
return;
|
|
}
|
|
os_mem_set(&node->ext_1.ec_info, 0xFF, sizeof(node->ext_1.ec_info));
|
|
node->ext_1.ec_info.overvoltage_cnt = 0;
|
|
node->ext_1.ec_info.undervoltage_cnt = 0;
|
|
}
|
|
|
|
static iot_sg_sta_node_desc_t *iot_sg_sta_ext_ec_get_next_event_node(
|
|
uint8_t func)
|
|
{
|
|
uint8_t i = 0;
|
|
iot_sg_sta_node_desc_t *node = NULL;
|
|
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) {
|
|
continue;
|
|
}
|
|
switch (func) {
|
|
case IOT_SG_STA_EXT_EC_FUNC_ID_HEALTH:
|
|
{
|
|
if (sta_glb->node_list[i]->ext_1.ec_info.health) {
|
|
node = sta_glb->node_list[i];
|
|
goto out;
|
|
}
|
|
break;
|
|
}
|
|
case IOT_SG_STA_EXT_EC_FUNC_ID_OVERVOLTAGE:
|
|
{
|
|
if (sta_glb->node_list[i]->ext_1.ec_info.overvoltage) {
|
|
node = sta_glb->node_list[i];
|
|
goto out;
|
|
}
|
|
break;
|
|
}
|
|
case IOT_SG_STA_EXT_EC_FUNC_ID_UNDERVOLTAGE:
|
|
{
|
|
if (sta_glb->node_list[i]->ext_1.ec_info.undervoltage) {
|
|
node = sta_glb->node_list[i];
|
|
goto out;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
return node;
|
|
}
|
|
|
|
static uint32_t iot_sg_sta_ext_ec_report_health_event(
|
|
iot_sg_sta_node_desc_t *node)
|
|
{
|
|
uint32_t ret = ERR_OK, now = (uint32_t)(os_boot_time64() / 1000);
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
iot_sg_sta_drv_meter_ss_data_t data = {0};
|
|
|
|
if (!ec_info) {
|
|
ret = ERR_FAIL;
|
|
goto out;
|
|
}
|
|
event = &ec_info->health_evt_info;
|
|
if (event->busy) {
|
|
if (event->rpt_tm > now) {
|
|
ret = ERR_BUSY;
|
|
goto out;
|
|
}
|
|
event->send_cnt--;
|
|
if (!event->send_cnt) {
|
|
iot_sg_sta_ext_ec_event_ack_handle(event->seq, 1);
|
|
ret = ERR_TIMEOVER;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
iot_sg_data_print("ext ec: rpt health", node->entry.addr, IOT_MAC_ADDR_LEN);
|
|
ret = iot_sg_sta_flash_score_data_read(node->entry.addr, (uint8_t *)&data,
|
|
sizeof(data), IOT_SG_STA_METER_DATA_TYPE_EC);
|
|
if (data.score < IOT_SG_EXT_STATE_WEIGHT_SCORE_60) {
|
|
ret = iot_sg_sta_report_ec_health_event(
|
|
node->entry.addr, data.score, &data.bit_map);
|
|
if (ret == ERR_OK) {
|
|
iot_mac_addr_cpy(ec_info->health_evt_info.addr, node->entry.addr);
|
|
if (!event->busy) {
|
|
event->send_cnt = IOT_SG_STA_EXT_EC_EVENT_UPLOAD_RETRY_MAX;
|
|
event->busy = 1;
|
|
}
|
|
event->rpt_tm = now + IOT_SG_STA_EXT_EC_EVENT_UPLOAD_OVERTIME;
|
|
}
|
|
} else {
|
|
node->ext_1.ec_info.health = 0;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t iot_sg_sta_ext_ec_report_overvoltage(
|
|
iot_sg_sta_node_desc_t *node)
|
|
{
|
|
uint32_t ret = ERR_OK, now = (uint32_t)(os_boot_time64() / 1000);
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
|
|
if (!ec_info) {
|
|
ret = ERR_FAIL;
|
|
goto out;
|
|
}
|
|
event = &ec_info->ov_evt_info;
|
|
if (event->busy) {
|
|
if (event->rpt_tm > now) {
|
|
ret = ERR_BUSY;
|
|
goto out;
|
|
}
|
|
event->send_cnt--;
|
|
if (!event->send_cnt) {
|
|
iot_sg_sta_ext_ec_event_ack_handle(event->seq, 1);
|
|
ret = ERR_TIMEOVER;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
iot_sg_data_print("ext ec: rpt ov ", node->entry.addr, IOT_MAC_ADDR_LEN);
|
|
ret = iot_sg_sta_report_ec_overvoltage_event(node->entry.addr,
|
|
node->is_three_phase, node->ext_1.ec_info.max_va,
|
|
node->ext_1.ec_info.max_vb, node->ext_1.ec_info.max_vc);
|
|
if (ret == ERR_OK) {
|
|
iot_mac_addr_cpy(event->addr, node->entry.addr);
|
|
if (!event->busy) {
|
|
event->send_cnt = IOT_SG_STA_EXT_EC_EVENT_UPLOAD_RETRY_MAX;
|
|
event->busy = 1;
|
|
}
|
|
event->rpt_tm = now + IOT_SG_STA_EXT_EC_EVENT_UPLOAD_OVERTIME;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t iot_sg_sta_ext_ec_report_undervoltage(
|
|
iot_sg_sta_node_desc_t *node)
|
|
{
|
|
uint32_t ret = ERR_OK, now = (uint32_t)(os_boot_time64() / 1000);
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
|
|
if (!ec_info) {
|
|
ret = ERR_FAIL;
|
|
goto out;
|
|
}
|
|
event = &ec_info->uv_evt_info;
|
|
if (event->busy) {
|
|
if (event->rpt_tm > now) {
|
|
ret = ERR_BUSY;
|
|
goto out;
|
|
}
|
|
event->send_cnt--;
|
|
if (!event->send_cnt) {
|
|
iot_sg_sta_ext_ec_event_ack_handle(event->seq, 1);
|
|
ret = ERR_TIMEOVER;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
iot_sg_data_print("ext ec: rpt uv ", node->entry.addr, IOT_MAC_ADDR_LEN);
|
|
ret = iot_sg_sta_report_ec_undervoltage_event(node->entry.addr,
|
|
node->is_three_phase, node->ext_1.ec_info.min_va,
|
|
node->ext_1.ec_info.min_vb, node->ext_1.ec_info.min_vc);
|
|
if (ret == ERR_OK) {
|
|
iot_mac_addr_cpy(event->addr, node->entry.addr);
|
|
if (!event->busy) {
|
|
event->send_cnt = IOT_SG_STA_EXT_EC_EVENT_UPLOAD_RETRY_MAX;
|
|
event->busy = 1;
|
|
}
|
|
event->rpt_tm = now + IOT_SG_STA_EXT_EC_EVENT_UPLOAD_OVERTIME;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t iot_sg_sta_ext_ec_report_second_pulse()
|
|
{
|
|
uint32_t ret = ERR_OK, now = (uint32_t)(os_boot_time64() / 1000);
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
uint8_t addr[IOT_MAC_ADDR_LEN] = {0};
|
|
|
|
if (!ec_info) {
|
|
ret = ERR_FAIL;
|
|
goto out;
|
|
}
|
|
event = &ec_info->pulse_evt_info;
|
|
if (event->busy) {
|
|
if (event->rpt_tm > now) {
|
|
ret = ERR_BUSY;
|
|
goto out;
|
|
}
|
|
event->send_cnt--;
|
|
if (!event->send_cnt) {
|
|
iot_sg_sta_ext_ec_event_ack_handle(event->seq, 1);
|
|
ret = ERR_TIMEOVER;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
sta_glb->drv->get_login_addr(addr);
|
|
iot_sg_data_print("ext ec: rpt pulse ", addr, IOT_MAC_ADDR_LEN);
|
|
ret = iot_sg_sta_report_ec_second_pulse_event(addr,
|
|
(uint16_t)ec_info->pulse_err_value);
|
|
if (ret == ERR_OK) {
|
|
iot_mac_addr_cpy(event->addr, addr);
|
|
if (!event->busy) {
|
|
event->send_cnt = IOT_SG_STA_EXT_EC_EVENT_UPLOAD_RETRY_MAX;
|
|
event->busy = 1;
|
|
}
|
|
event->rpt_tm = now + IOT_SG_STA_EXT_EC_EVENT_UPLOAD_OVERTIME;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_pulse_check()
|
|
{
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_time_tm_t now = {0};
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
if (!ec_info->pulse_check_enable ||
|
|
iot_sg_sta_rtc_valid_check(0) != ERR_OK) {
|
|
return;
|
|
}
|
|
if (!ec_info->pulse_run) {
|
|
iot_sg_sta_rtc_get(&now, 0);
|
|
if (!iot_sg_ext_ec_is_time_valid(ec_info->next_pulse_time)) {
|
|
iot_sg_ext_ec_get_next_run_datetime(&ec_info->next_pulse_time);
|
|
}
|
|
if (iot_rtc_delta_calc(&ec_info->next_pulse_time, &now) >= 0) {
|
|
iot_sg_ext_ec_get_next_run_datetime(&ec_info->next_pulse_time);
|
|
iot_sg_printf("ext ec: pulse %04d-%02d-%02d %02d:%02d:%02d\n",
|
|
now.tm_year, now.tm_mon, now.tm_mday,
|
|
now.tm_hour, now.tm_min, now.tm_sec);
|
|
ec_info->pulse_run = 1;
|
|
}
|
|
}
|
|
if (ec_info->pulse_run) {
|
|
if (!iot_sg_sta_ext_mf_is_running()) {
|
|
IOT_ASSERT(IOT_SMART_GRID_EXT_MF_ENABLE);
|
|
if (!sta_glb->mf && iot_sg_sta_ext_mf_init()) {
|
|
return;
|
|
}
|
|
ec_info->pulse_event = 0;
|
|
ec_info->pulse_count = 0;
|
|
ec_info->pulse_err_value = 0;
|
|
iot_sg_sta_ext_mf_start_second_pulse_monitor(
|
|
iot_sg_sta_ext_ec_pulse_handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void iot_sg_ext_ec_event_func(void)
|
|
{
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_node_desc_t *node = NULL;
|
|
|
|
if (!ec_info || !p_sg_glb->plc_state.link_ready) {
|
|
return;
|
|
}
|
|
|
|
if (ec_info->health_enable && ec_info->health_event) {
|
|
node = iot_sg_sta_ext_ec_get_next_event_node(
|
|
IOT_SG_STA_EXT_EC_FUNC_ID_HEALTH);
|
|
if (!node) {
|
|
ec_info->health_event = 0;
|
|
} else {
|
|
iot_sg_sta_ext_ec_report_health_event(node);
|
|
}
|
|
}
|
|
|
|
if (ec_info->overvoltage_enable && ec_info->overvoltage_event) {
|
|
node = iot_sg_sta_ext_ec_get_next_event_node(
|
|
IOT_SG_STA_EXT_EC_FUNC_ID_OVERVOLTAGE);
|
|
if (!node) {
|
|
ec_info->overvoltage_event = 0;
|
|
} else {
|
|
iot_sg_sta_ext_ec_report_overvoltage(node);
|
|
}
|
|
}
|
|
|
|
if (ec_info->undervoltage_enable && ec_info->undervoltage_event) {
|
|
node = iot_sg_sta_ext_ec_get_next_event_node(
|
|
IOT_SG_STA_EXT_EC_FUNC_ID_UNDERVOLTAGE);
|
|
if (!node) {
|
|
ec_info->undervoltage_event = 0;
|
|
} else {
|
|
iot_sg_sta_ext_ec_report_undervoltage(node);
|
|
}
|
|
}
|
|
|
|
if (ec_info->pulse_check_enable && ec_info->pulse_event) {
|
|
iot_sg_sta_ext_ec_report_second_pulse();
|
|
}
|
|
}
|
|
|
|
void iot_sg_ext_ec_refresh_func(void)
|
|
{
|
|
iot_sg_sta_ext_ec_pulse_check();
|
|
iot_sg_ext_ec_event_func();
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_health_event_reset(uint8_t is_timeout)
|
|
{
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
iot_sg_sta_node_desc_t *node = NULL;
|
|
|
|
(void)is_timeout;
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
iot_sg_printf("ext ec: health evt reset\n");
|
|
event = &ec_info->health_evt_info;
|
|
node = iot_sg_sta_node_find_by_addr(event->addr);
|
|
if (node) {
|
|
node->ext_1.ec_info.health = 0;
|
|
}
|
|
os_mem_set(event, 0, sizeof(*event));
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_overvoltage_event_reset(uint8_t is_timeout)
|
|
{
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
iot_sg_sta_node_desc_t *node = NULL;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
iot_sg_printf("ext ec: ov evt reset\n");
|
|
event = &ec_info->ov_evt_info;
|
|
node = iot_sg_sta_node_find_by_addr(event->addr);
|
|
if (node) {
|
|
node->ext_1.ec_info.overvoltage = 0;
|
|
if (!is_timeout) {
|
|
node->ext_1.ec_info.overvoltage_cnt = 0;
|
|
node->ext_1.ec_info.max_va = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node->ext_1.ec_info.max_vb = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node->ext_1.ec_info.max_vc = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
}
|
|
}
|
|
os_mem_set(event, 0, sizeof(*event));
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_undervoltage_event_reset(uint8_t is_timeout)
|
|
{
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
iot_sg_sta_node_desc_t *node = NULL;
|
|
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
iot_sg_printf("ext ec: uv evt reset\n");
|
|
event = &ec_info->uv_evt_info;
|
|
node = iot_sg_sta_node_find_by_addr(event->addr);
|
|
if (node) {
|
|
node->ext_1.ec_info.undervoltage = 0;
|
|
if (!is_timeout) {
|
|
node->ext_1.ec_info.undervoltage_cnt = 0;
|
|
node->ext_1.ec_info.min_va = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node->ext_1.ec_info.min_vb = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
node->ext_1.ec_info.min_vc = IOT_SG_STA_EXT_EC_INVALID_VOLTAGE;
|
|
}
|
|
}
|
|
os_mem_set(event, 0, sizeof(*event));
|
|
}
|
|
|
|
static void iot_sg_sta_ext_ec_second_pulse_event_reset(uint8_t is_timeout)
|
|
{
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
|
|
(void)is_timeout;
|
|
if (!ec_info) {
|
|
return;
|
|
}
|
|
iot_sg_printf("ext ec: pulse evt reset\n");
|
|
event = &ec_info->pulse_evt_info;
|
|
ec_info->pulse_event = 0;
|
|
ec_info->pulse_err_value = 0;
|
|
os_mem_set(event, 0, sizeof(*event));
|
|
}
|
|
|
|
uint32_t iot_sg_sta_ext_ec_event_ack_handle(uint16_t seq, uint8_t is_timeout)
|
|
{
|
|
uint32_t ret = ERR_NOSUPP;
|
|
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
|
|
iot_sg_sta_ext_ec_t *ec_info = sta_glb->ext_info.ec_info;
|
|
iot_sg_sta_ext_ec_event_t *event = NULL;
|
|
|
|
if (!ec_info) {
|
|
goto out;
|
|
}
|
|
|
|
event = &ec_info->health_evt_info;
|
|
if (event->busy && seq == event->seq) {
|
|
iot_sg_sta_ext_ec_health_event_reset(is_timeout);
|
|
ret = ERR_OK;
|
|
goto out;
|
|
}
|
|
|
|
event = &ec_info->uv_evt_info;
|
|
if (event->busy && seq == event->seq) {
|
|
iot_sg_sta_ext_ec_undervoltage_event_reset(is_timeout);
|
|
ret = ERR_OK;
|
|
goto out;
|
|
}
|
|
|
|
event = &ec_info->ov_evt_info;
|
|
if (event->busy && seq == event->seq) {
|
|
iot_sg_sta_ext_ec_overvoltage_event_reset(is_timeout);
|
|
ret = ERR_OK;
|
|
goto out;
|
|
}
|
|
|
|
event = &ec_info->pulse_evt_info;
|
|
if (event->busy && seq == event->seq) {
|
|
iot_sg_sta_ext_ec_second_pulse_event_reset(is_timeout);
|
|
ret = ERR_OK;
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
#else
|
|
|
|
uint32_t iot_sg_sta_ext_ec_init()
|
|
{
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t iot_sg_sta_ec_set_config(
|
|
iot_sg_sta_flash_nw_edge_computing_cfg_info_t *cfg) {
|
|
(void)cfg;
|
|
return ERR_NOSUPP;
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_deinit()
|
|
{
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_check(void)
|
|
{
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_data_handle(uint16_t seq, uint8_t data_type,
|
|
uint8_t *resp_data, uint16_t resp_len, uint8_t *req_data, uint16_t req_len)
|
|
{
|
|
(void)seq;
|
|
(void)data_type;
|
|
(void)resp_data;
|
|
(void)resp_len;
|
|
(void)req_data;
|
|
(void)req_len;
|
|
}
|
|
|
|
uint8_t iot_sg_ext_ec_func(uint8_t *addr)
|
|
{
|
|
(void)addr;
|
|
return 1;
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_tm_update_handle(void)
|
|
{
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_pulse_time_reset_handle(void)
|
|
{
|
|
}
|
|
|
|
void iot_sg_sta_ext_ec_node_data_reset(iot_sg_sta_node_desc_t *node)
|
|
{
|
|
(void)node;
|
|
}
|
|
|
|
void iot_sg_ext_ec_refresh_func(void)
|
|
{
|
|
}
|
|
|
|
uint32_t iot_sg_sta_ext_ec_event_ack_handle(uint16_t seq, uint8_t is_timeout)
|
|
{
|
|
(void)seq;
|
|
(void)is_timeout;
|
|
return ERR_NOSUPP;
|
|
}
|
|
|
|
#endif /* IOT_SMART_GRID_EDGE_COMPUTING_ENABLE */
|