Files
kunlun/app/smart_grid/sta/iot_sg_sta_ext_ec.c

1904 lines
60 KiB
C
Raw Normal View History

2024-09-28 14:24:04 +08:00
/****************************************************************************
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 */