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

878 lines
29 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
/* os_shim header files */
#include "os_types_api.h"
#include "os_utils_api.h"
/* iot common header files */
#include "iot_io_api.h"
#include "iot_oem_api.h"
#include "iot_utils_api.h"
/* smart grid internal header files */
#include "iot_sg_fr.h"
#include "iot_sg.h"
#include "iot_sg_sta.h"
#include "iot_sg_sta_nw.h"
#include "iot_sg_sta_ext.h"
#include "proto_645.h"
#include "proto_69845.h"
#include "iot_oem_api.h"
/* define extend function read load data default min interval time,
* uint is 1min.
*/
#define IOT_SG_STA_EXT_NW_LC_MIN_INTER (15)
/*define extend function NW load curve di max count */
#define IOT_SG_STA_EXT_NW_LC_DI_MAX_CNT (16)
/* Maximum effective interval between next exec time and start time */
#define IOT_SG_STA_EXT_NW_LC_NEXT_TM_INTER_MAX (3600)
/* define extend function load curve tm reset min delta time, uint is 1s */
#define IOT_SG_STA_EXT_NW_LC_TM_MIN_DELTA_TIME (60)
/* define multi di meter data lr frame max di number */
#define IOT_SG_STA_EXT_NW_MULTI_DI_MAX_NUM (5)
#if (PLC_SUPPORT_STA_ROLE && IOT_NW_APP_ENABLE)
static const uint32_t nw_lc_di_table[IOT_SG_STA_EXT_NW_LC_DI_MAX_CNT] = {
PROTO_645_2007_DI_V_ALL,
PROTO_645_2007_DI_I_ALL,
PROTO_645_2007_DI_I_N,
PROTO_645_2007_DI_P_ALL,
PROTO_645_2007_DI_Q_ALL,
PROTO_645_2007_DI_PF_ALL,
PROTO_645_2007_DI_EPT_POS_SUM,
PROTO_645_2007_DI_EPT_NEG_SUM,
PROTO_645_2007_DI_EQT_POS_SUM,
PROTO_645_2007_DI_EQT_NEG_SUM,
PROTO_645_2007_DI_EQT_QRT1_SUM,
PROTO_645_2007_DI_EQT_QRT2_SUM,
PROTO_645_2007_DI_EQT_QRT3_SUM,
PROTO_645_2007_DI_EQT_QRT4_SUM,
PROTO_645_2007_DI_EPT_DEMAND,
PROTO_645_2007_DI_EQT_DEMAND,
};
void iot_sg_sta_ext_nw_lc_reset(void)
{
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
ext_info->lc_info_nw.di_idx = 0;
ext_info->lc_info_nw.timeout_cnt = 0;
ext_info->lc_info_nw.repeat_cnt = 0;
ext_info->lc_info_nw.flag_resp = 0;
ext_info->lc_info_nw.flag_multi_resp = 0;
ext_info->lc_info_nw.last_di_idx = 0;
ext_info->lc_info_nw.state = IOT_SG_STA_EXT_LC_STATE_IDLE;
}
uint32_t iot_sg_sta_ext_nw_lc_interval_save(uint8_t interval)
{
uint8_t task_type = IOT_SG_STA_METER_NW_CFG_SINGLE;
uint8_t reason = 0, i, *addr = NULL;
uint32_t ret = ERR_FAIL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_flash_nw_task_cfg_info_t *cfg;
iot_pkt_t *cfg_pkt = NULL;
if (!interval || (interval > 60) || (60 % interval)) {
reason = 1;
goto out;
}
cfg_pkt = iot_pkt_alloc(sizeof(*cfg), IOT_SMART_GRID_MID);
if (!cfg_pkt) {
reason = 2;
goto out;
}
cfg = (iot_sg_sta_flash_nw_task_cfg_info_t *)
iot_pkt_put(cfg_pkt, sizeof(*cfg));
if (sta_glb->drv->drv_id == IOT_SG_STA_DRV_ID_645_PM) {
addr = p_sg_glb->plc_state.addr;
}
for (; task_type < IOT_SG_STA_METER_NW_CFG_CNT; task_type++) {
if (iot_sg_sta_flash_nw_task_cfg_get(cfg, task_type, addr) == ERR_OK) {
if (cfg->di_info[0].interval == interval) {
continue;
}
}
iot_mac_addr_cpy(cfg->mac_addr, p_sg_glb->plc_state.addr);
cfg->flag_start = 1;
cfg->di_cnt = IOT_SG_STA_EXT_NW_LC_DI_MAX_CNT;
for (i = 0; i < cfg->di_cnt; i++) {
cfg->di_info[i].interval = interval;
cfg->di_info[i].di = nw_lc_di_table[i];
}
if (iot_sg_sta_flash_nw_task_cfg_save(cfg, task_type) != ERR_OK) {
reason = 3;
goto out;
}
}
ret = ERR_OK;
out:
if (cfg_pkt) {
iot_pkt_free(cfg_pkt);
}
if (reason) {
iot_sg_printf("%s err %d\n", __FUNCTION__, reason);
}
return ret;
}
static uint32_t iot_sg_sta_ext_nw_lc_di_update(
iot_sg_sta_flash_nw_task_cfg_info_t *cfg)
{
uint8_t interval, min_di_cnt;
uint32_t ret = ERR_FAIL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
iot_sg_sta_ext_lc_info_nw_t *lc_info = &ext_info->lc_info_nw;
if (!cfg) {
goto out;
}
min_di_cnt = min(cfg->di_cnt, IOT_SG_STA_FLASH_NW_CFG_DI_MAX_CNT);
for (; lc_info->di_idx < min_di_cnt; lc_info->di_idx++) {
interval = cfg->di_info[lc_info->di_idx].interval;
if (!interval) {
continue;
} else {
ret = ERR_OK;
goto out;
}
}
out:
return ret;
}
static void iot_sg_sta_ext_nw_lc_data_save(uint8_t *addr, iot_time_tm_t *tm)
{
uint8_t reason = 0;
uint16_t index;
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
iot_sg_sta_ext_meter_data_t *meter = &ext_info->meter_data;
iot_sg_meter_lc_uint_nw_data_t *unit_data;
iot_pkt_t *pkt = NULL;
iot_time_tm_t cache_tm = {0};
iot_sg_printf("%s addr %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
iot_sg_printf("%s time %lu-%lu-%lu %lu:%lu:%lu\n", __FUNCTION__,
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min,
tm->tm_sec);
pkt = iot_pkt_alloc(sizeof(*unit_data), IOT_SMART_GRID_MID);
if (!pkt) {
reason = 1;
goto out;
}
unit_data = (iot_sg_meter_lc_uint_nw_data_t *)
iot_pkt_put(pkt, sizeof(*unit_data));
ret = iot_sg_sta_flash_unit_data_find_by_time(addr,
&index, tm, (uint8_t*)unit_data, sizeof(*unit_data),
IOT_SG_STA_METER_DATA_TYPE_NW_TASK, 1);
if (ret == ERR_OK) {
cache_tm.tm_year = (uint16_t)(unit_data->year + 2000);
cache_tm.tm_mon = (uint8_t)unit_data->month;
cache_tm.tm_mday = (uint8_t)unit_data->day;
cache_tm.tm_hour = (uint8_t)unit_data->hour;
cache_tm.tm_min = (uint8_t)unit_data->minute;
if (iot_rtc_delta_calc(&cache_tm, tm) != 0) {
index++;
}
}
if (index >= IOT_SG_STA_METER_NW_LC_CNT) {
index = 0;
}
unit_data->year = (uint32_t)(tm->tm_year - 2000);
unit_data->month = (uint32_t)(tm->tm_mon);
unit_data->day = (uint32_t)(tm->tm_mday);
unit_data->hour = (uint32_t)(tm->tm_hour);
unit_data->minute = (uint32_t)(tm->tm_min);
os_mem_cpy(&unit_data->v, &meter->v, sizeof(meter->v));
os_mem_cpy(&unit_data->i, &meter->a, sizeof(meter->a));
os_mem_cpy(unit_data->n, meter->gnd_a, sizeof(meter->gnd_a));
os_mem_cpy(&unit_data->active_power, &meter->ap, sizeof(meter->ap));
os_mem_cpy(&unit_data->reactive_power, &meter->rp, sizeof(meter->rp));
os_mem_cpy(&unit_data->apparent_power, &meter->atp, sizeof(meter->atp));
os_mem_cpy(&unit_data->power_factor, &meter->pf, sizeof(meter->pf));
os_mem_cpy(&unit_data->phase_angle, &meter->phase_angle,
sizeof(meter->phase_angle));
os_mem_cpy(&unit_data->v_waveform_dis, &meter->v_waveform_dis,
sizeof(meter->v_waveform_dis));
os_mem_cpy(&unit_data->i_waveform_dis, &meter->i_waveform_dis,
sizeof(meter->i_waveform_dis));
os_mem_cpy(&unit_data->a_v_hc, &meter->a_v_hc, sizeof(meter->a_v_hc));
os_mem_cpy(&unit_data->b_v_hc, &meter->b_v_hc, sizeof(meter->b_v_hc));
os_mem_cpy(&unit_data->c_v_hc, &meter->c_v_hc, sizeof(meter->c_v_hc));
os_mem_cpy(&unit_data->a_i_hc, &meter->a_i_hc, sizeof(meter->a_i_hc));
os_mem_cpy(&unit_data->b_i_hc, &meter->b_i_hc, sizeof(meter->b_i_hc));
os_mem_cpy(&unit_data->c_i_hc, &meter->c_i_hc, sizeof(meter->c_i_hc));
os_mem_cpy(&unit_data->freq, &meter->freq, sizeof(meter->freq));
os_mem_cpy(unit_data->average_p, meter->average_p,
sizeof(meter->average_p));
os_mem_cpy(unit_data->cur_demand.ap_demand, meter->ept_demand,
sizeof(meter->ept_demand));
os_mem_cpy(unit_data->cur_demand.rp_demand, meter->eqt_demand,
sizeof(meter->eqt_demand));
os_mem_cpy(unit_data->at_demand, meter->at_demand,
sizeof(meter->at_demand));
os_mem_cpy(unit_data->temperature, meter->temperature,
sizeof(meter->temperature));
os_mem_cpy(unit_data->clock_battery_v, meter->clock_battery_v,
sizeof(meter->clock_battery_v));
os_mem_cpy(unit_data->mr_battery_v, meter->mr_battery_v,
sizeof(meter->mr_battery_v));
os_mem_cpy(unit_data->work_time, meter->work_time,
sizeof(meter->work_time));
os_mem_cpy(unit_data->energy_t.ept_pos_t, meter->pae.total,
sizeof(meter->pae.total));
os_mem_cpy(unit_data->energy_t.ept_neg_t, meter->nae.total,
sizeof(meter->nae.total));
os_mem_cpy(unit_data->energy_t.cre1_t, meter->cre1.total,
sizeof(meter->cre1.total));
os_mem_cpy(unit_data->energy_t.cre2_t, meter->cre2.total,
sizeof(meter->cre2.total));
os_mem_cpy(unit_data->qr_energy_t.re_1st_et, meter->re_1st.total,
sizeof(meter->re_1st.total));
os_mem_cpy(unit_data->qr_energy_t.re_2st_et, meter->re_2st.total,
sizeof(meter->re_2st.total));
os_mem_cpy(unit_data->qr_energy_t.re_3st_et, meter->re_3st.total,
sizeof(meter->re_3st.total));
os_mem_cpy(unit_data->qr_energy_t.re_4st_et, meter->re_4st.total,
sizeof(meter->re_4st.total));
if (iot_sg_sta_flash_unit_data_save(addr, index, (uint8_t*)unit_data,
sizeof(*unit_data), IOT_SG_STA_METER_DATA_TYPE_NW_TASK) == ERR_OK) {
iot_sg_sta_flash_unit_data_check(addr, index, tm,
IOT_SG_STA_METER_DATA_TYPE_NW_TASK);
} else {
reason = 2;
}
out:
if (reason) {
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
}
if (pkt) {
iot_pkt_free(pkt);
}
}
void iot_sg_sta_ext_nw_tm_update(iot_sg_sta_node_desc_t *node)
{
int64_t interval = IOT_SG_STA_EXT_NW_LC_MIN_INTER, delta;
iot_time_tm_t curr_tm = { 0 };
if (iot_sg_sta_get_user_type() != USER_TYPE_SOUTHEN_POWER_GRID_SHENZHEN) {
iot_sg_sta_rtc_get(&curr_tm, 0);
delta = iot_rtc_delta_calc(&curr_tm, &node->ext.lr_info.tm);
delta = IOT_ABS(delta);
if (delta > IOT_SG_STA_EXT_NW_LC_TM_MIN_DELTA_TIME) {
os_mem_set(&node->ext.lr_info.tm, 0x0, sizeof(iot_time_tm_t));
}
} else {
if (iot_sg_sta_ext_node_tm_check(&node->ext.lr_info.tm,
interval * 60)) {
os_mem_set(&node->ext.lr_info.tm, 0x0, sizeof(iot_time_tm_t));
}
}
}
static uint8_t iot_sg_sta_ext_multi_di_read_check(iot_sg_sta_node_desc_t *node)
{
uint8_t multi_di_read = 0;
if (!node->ext.lr_info.multi_di_detect_done ||
node->ext.lr_info.multi_di_supported) {
multi_di_read = 1;
}
return multi_di_read;
}
static uint32_t iot_sg_sta_ext_multi_di_unit_data_handle(uint32_t di,
uint8_t *data, uint8_t len)
{
uint8_t reason = 0;
uint32_t ret = ERR_FAIL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
iot_sg_sta_ext_meter_data_t *meter = &ext_info->meter_data;
switch (di) {
case PROTO_645_2007_DI_V_ALL:
{
if (len < sizeof(meter->v.a)) {
reason = 1;
goto drop;
}
len = iot_sg_ext_get_min_data_len(len, sizeof(meter->v),
sizeof(meter->v.a));
os_mem_cpy(&meter->v, data, len);
break;
}
case PROTO_645_2007_DI_I_ALL:
{
if (len < sizeof(meter->a.a)) {
reason = 2;
goto drop;
}
len = iot_sg_ext_get_min_data_len(len, sizeof(meter->a),
sizeof(meter->a.a));
os_mem_cpy(&meter->a, data, len);
break;
}
case PROTO_645_2007_DI_P_ALL:
{
if (len < sizeof(meter->ap.total)) {
reason = 3;
goto drop;
}
len = iot_sg_ext_get_min_data_len(len, sizeof(meter->ap),
sizeof(meter->ap.total));
os_mem_cpy(&meter->ap, data, len);
break;
}
case PROTO_645_2007_DI_Q_ALL:
{
if (len < sizeof(meter->rp.total)) {
reason = 4;
goto drop;
}
len = iot_sg_ext_get_min_data_len(len, sizeof(meter->rp),
sizeof(meter->rp.total));
os_mem_cpy(&meter->rp, data, len);
break;
}
case PROTO_645_2007_DI_PF_ALL:
{
if (len < sizeof(meter->pf.total)) {
reason = 5;
goto drop;
}
len = iot_sg_ext_get_min_data_len(len, sizeof(meter->pf),
sizeof(meter->pf.total));
os_mem_cpy(&meter->pf, data, len);
break;
}
case PROTO_645_2007_DI_EPT_POS_SUM:
{
if (len < sizeof(meter->pae.total)) {
reason = 6;
goto drop;
}
os_mem_cpy(meter->pae.total, data, sizeof(meter->pae.total));
break;
}
case PROTO_645_2007_DI_EPT_NEG_SUM:
{
if (len < sizeof(meter->nae.total)) {
reason = 7;
goto drop;
}
os_mem_cpy(meter->nae.total, data, sizeof(meter->nae.total));
break;
}
case PROTO_645_2007_DI_EQT_POS_SUM:
{
if (len < sizeof(meter->cre1.total)) {
reason = 8;
goto drop;
}
os_mem_cpy(meter->cre1.total, data, sizeof(meter->cre1.total));
break;
}
case PROTO_645_2007_DI_EQT_NEG_SUM:
{
if (len < sizeof(meter->cre2.total)) {
reason = 9;
goto drop;
}
os_mem_cpy(meter->cre2.total, data, sizeof(meter->cre2.total));
break;
}
case PROTO_645_2007_DI_EQT_QRT1_SUM:
{
if (len < sizeof(meter->re_1st.total)) {
reason = 10;
goto drop;
}
os_mem_cpy(meter->re_1st.total, data, sizeof(meter->re_1st.total));
break;
}
case PROTO_645_2007_DI_EQT_QRT2_SUM:
{
if (len < sizeof(meter->re_2st.total)) {
reason = 11;
goto drop;
}
os_mem_cpy(meter->re_2st.total, data, sizeof(meter->re_2st.total));
break;
}
case PROTO_645_2007_DI_EQT_QRT3_SUM:
{
if (len < sizeof(meter->re_3st.total)) {
reason = 12;
goto drop;
}
os_mem_cpy(meter->re_3st.total, data, sizeof(meter->re_3st.total));
break;
}
case PROTO_645_2007_DI_EQT_QRT4_SUM:
{
if (len < sizeof(meter->re_4st.total)) {
reason = 13;
goto drop;
}
os_mem_cpy(meter->re_4st.total, data, sizeof(meter->re_4st.total));
break;
}
case PROTO_645_2007_DI_EPT_DEMAND:
{
if (len < sizeof(meter->ept_demand)) {
reason = 14;
goto drop;
}
os_mem_cpy(meter->ept_demand, data, sizeof(meter->ept_demand));
break;
}
case PROTO_645_2007_DI_EQT_DEMAND:
{
if (len < sizeof(meter->eqt_demand)) {
reason = 15;
goto drop;
}
os_mem_cpy(meter->eqt_demand, data, sizeof(meter->eqt_demand));
break;
}
case PROTO_645_2007_DI_I_N:
{
if (len < sizeof(meter->gnd_a)) {
reason = 16;
goto drop;
}
os_mem_cpy(meter->gnd_a, data, sizeof(meter->gnd_a));
break;
}
default:
reason = 17;
goto drop;
}
ret = ERR_OK;
goto out;
drop:
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
out:
return ret;
}
static uint32_t iot_sg_sta_ext_multi_di_read_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, len, di_cnt, unit_data_len, i;
uint32_t rsp_di, ret = ERR_INVAL;
proto_645_header_t *resp_hdr, *req_hdr;
proto_645_07_nw_multi_di_read_rsp_unit_t *rsp_unit;
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 drop;
}
if ((req_data == NULL) || !req_len) {
reason = 2;
goto drop;
}
if ((resp_data == NULL) || !resp_len) {
ret = ERR_TIMEOVER;
reason = 3;
goto drop;
}
if (iot_sg_ext_read_645_nack_check(req_data, req_len, resp_data, resp_len,
ext_info->addr) == ERR_OK) {
iot_sg_printf("%s nack\n", __FUNCTION__);
ret = ERR_OK;
goto out;
}
if (proto_645_check_di_fn_match(req_data, req_len,
resp_data, resp_len)) {
reason = 4;
goto drop;
}
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 drop;
}
if ((resp_hdr->control.ack != PROTO_645_ACK_NORMAL)
|| (resp_hdr->control.dir != PROTO_645_DIR_SLAVE)) {
reason = 6;
goto drop;
}
if (!iot_mac_addr_cmp(ext_info->addr, resp_hdr->addr)) {
reason = 7;
goto drop;
}
if (resp_hdr->len < PROTO_645_2007_DI_LEN) {
reason = 8;
goto drop;
}
proto_645_sub33_handle(resp_hdr->data, resp_hdr->len);
rsp_di = proto_645_2007_byte_to_di(resp_hdr->data);
iot_sg_printf("%s resp id %08x\n", __FUNCTION__, rsp_di);
if ((rsp_di & 0xffffff00) != PROTO_645_2007_DI_NW_MULTI_READ) {
reason = 9;
goto drop;
}
di_cnt = (uint8_t)(rsp_di & 0x000000ff);
di_cnt = iot_bcd_to_byte(di_cnt);
if (!di_cnt) {
reason = 10;
goto drop;
}
data = &resp_hdr->data[PROTO_645_2007_DI_LEN];
len = resp_hdr->len - PROTO_645_2007_DI_LEN;
for (i = 0; i < di_cnt; i++) {
if (len < sizeof(*rsp_unit)) {
reason = 11;
goto drop;
}
len -= sizeof(*rsp_unit);
rsp_unit = (proto_645_07_nw_multi_di_read_rsp_unit_t *)data;
if (rsp_unit->len < PROTO_645_2007_DI_LEN) {
reason = 12;
goto drop;
}
unit_data_len = rsp_unit->len - PROTO_645_2007_DI_LEN;
if (len < unit_data_len) {
reason = 13;
goto drop;
}
len -= unit_data_len;
if (unit_data_len) {
rsp_di = proto_645_2007_byte_to_di(rsp_unit->di);
if (iot_sg_sta_ext_multi_di_unit_data_handle(rsp_di,
rsp_unit->di_data, unit_data_len) == ERR_OK) {
ext_info->lc_info_nw.flag_multi_resp = 1;
ret= ERR_OK;
}
}
data = rsp_unit->di_data + unit_data_len;
if (len && (i < di_cnt - 1)) {
/* skip separator */
data++;
len--;
}
}
goto out;
drop:
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
out:
return ret;
}
void iot_sg_sta_ext_nw_lc_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)
{
uint32_t ret;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
iot_sg_sta_node_desc_t *node = iot_sg_sta_node_find_by_addr(ext_info->addr);
if (data_type != IOT_SG_STA_DATA_TYPE_645_07) {
return;
}
if (node && iot_sg_sta_ext_multi_di_read_check(node)) {
ret = iot_sg_sta_ext_multi_di_read_data_handle(seq, data_type,
resp_data, resp_len, req_data, req_len);
} else {
ret = iot_sg_ext_read_645_07_data_handle(seq, data_type, resp_data,
resp_len, req_data, req_len, NULL);
}
if (ret == ERR_OK || ret == ERR_TIMEOVER) {
if (ret == ERR_OK) {
ext_info->lc_info_nw.flag_resp = 1;
}
ext_info->lc_info_nw.timeout_cnt = 0;
iot_sg_sta_ext_sm_stop_action();
iot_sg_sta_ext_sm_next_action(IOT_SG_STA_EXT_SM_MIN_DELAY);
}
}
static iot_time_tm_t iot_sg_sta_ext_nw_get_next_lr_ts(iot_time_tm_t current_tm,
uint16_t period)
{
iot_time_tm_t start_tm = {0}, next_tm = {0};
if (iot_sg_sta_get_user_type() == USER_TYPE_SOUTHEN_POWER_GRID_SHENZHEN) {
start_tm.tm_year = 2000;
start_tm.tm_mon = 1;
start_tm.tm_mday = 1;
next_tm = iot_sg_ext_get_next_lr_ts(start_tm, period, current_tm);
} else {
os_mem_cpy(&start_tm, &current_tm, sizeof(iot_time_tm_t));
/* lc interval is T min. station read data from the meter at
* (0 + nT) min per hour, n = 1,2,3...
*/
start_tm.tm_min = 0;
start_tm.tm_sec = 0;
next_tm = iot_sg_ext_get_next_lr_ts(start_tm, period, current_tm);
if (IOT_SG_STA_EXT_NW_LC_NEXT_TM_INTER_MAX <
iot_rtc_delta_calc(&start_tm, &next_tm)) {
/* If the interval greater than
* IOT_SG_STA_EXT_NW_LC_NEXT_TM_INTER_Max,It`s judged that the next
* execution time is invalid.
*/
os_mem_set(&next_tm, 0, sizeof(iot_time_tm_t));
}
}
return next_tm;
}
iot_pkt_t *iot_sg_sta_ext_multi_di_msg_build(uint8_t *addr,
iot_sg_sta_flash_nw_task_cfg_info_t *cfg)
{
uint32_t di;
uint8_t di_cnt, i, *data, data_len, separator = 0xbb, idx = 0;
iot_pkt_t *pkt = NULL, *pkt_buff = NULL;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
iot_sg_sta_ext_lc_info_nw_t *lc_info = &ext_info->lc_info_nw;
IOT_ASSERT(cfg->di_cnt > lc_info->di_idx);
di_cnt = cfg->di_cnt - lc_info->di_idx;
if (di_cnt > IOT_SG_STA_EXT_NW_MULTI_DI_MAX_NUM) {
di_cnt = IOT_SG_STA_EXT_NW_MULTI_DI_MAX_NUM;
}
data_len = PROTO_645_2007_DI_LEN * di_cnt +
sizeof(separator) * (di_cnt - 1);
pkt_buff = iot_pkt_alloc(data_len, IOT_SMART_GRID_MID);
if (!pkt_buff) {
goto out;
}
data = iot_pkt_put(pkt_buff, data_len);
/* fill di from di_buff */
for (i = 0; i < di_cnt; i++) {
if (i != 0) {
*data = separator;
data += sizeof(separator);
}
idx = lc_info->di_idx + i;
proto_645_2007_di_to_byte(cfg->di_info[idx].di, data);
data += PROTO_645_2007_DI_LEN;
}
lc_info->di_idx = idx;
di = PROTO_645_2007_DI_NW_MULTI_READ;
di_cnt = iot_byte_to_bcd(di_cnt);
di |= di_cnt;
pkt = proto_645_build_msg(addr, iot_pkt_data(pkt_buff), data_len,
di, PROTO_645_DIR_MASTER, PROTO_645_ACK_NORMAL,
PROTO_645_2007_FN_READ_DATA, PROTO_645_2007_ID,
PROTO_645_FOLLOW_INVALID);
iot_pkt_free(pkt_buff);
out:
return pkt;
}
uint8_t iot_sg_sta_ext_nw_lc_func(uint8_t *addr)
{
uint32_t ret;
uint16_t timeout, period = IOT_SG_STA_EXT_NW_LC_MIN_INTER * 60;
uint8_t last_state, complete = 0, flag_new = 0, *plc_addr = NULL;
uint8_t task_type = IOT_SG_STA_METER_NW_CFG_SINGLE;
uint8_t user_type = iot_sg_sta_get_user_type();
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_ext_info_t *ext_info = &sta_glb->ext_info;
iot_sg_sta_ext_lc_info_nw_t *lc_info = &ext_info->lc_info_nw;
iot_sg_sta_node_desc_t *node = iot_sg_sta_node_find_by_addr(addr);
iot_sg_sta_flash_nw_task_cfg_info_t *cfg;
iot_time_tm_t tm = {0};
iot_pkt_t *pkt = NULL, *pkt_cfg = NULL;
last_state = lc_info->state;
if (!node) {
goto done;
}
if (user_type != USER_TYPE_SOUTHEN_POWER_GRID_SHENZHEN) {
/* NW Load curve start after RTC Synchronized */
if (iot_sg_sta_rtc_get(&tm, 1)) {
goto done;
}
} else {
if (iot_sg_sta_rtc_get(&tm, 0)) {
goto done;
}
}
pkt_cfg = iot_pkt_alloc(sizeof(*cfg), IOT_SMART_GRID_MID);
if (!pkt_cfg) {
goto done;
}
cfg = (iot_sg_sta_flash_nw_task_cfg_info_t *)
iot_pkt_put(pkt_cfg, sizeof(*cfg));
if (node->is_three_phase) {
task_type = IOT_SG_STA_METER_NW_CFG_3P;
}
if (user_type != USER_TYPE_SOUTHEN_POWER_GRID_SHENZHEN &&
sta_glb->drv->drv_id == IOT_SG_STA_DRV_ID_645_PM) {
plc_addr = p_sg_glb->plc_state.addr;
}
if (iot_sg_sta_flash_nw_task_cfg_get(cfg, task_type, plc_addr) != ERR_OK) {
if (user_type != USER_TYPE_SOUTHEN_POWER_GRID_SHENZHEN) {
iot_sg_sta_ext_nw_lc_interval_save(IOT_SG_STA_EXT_NW_LC_MIN_INTER);
}
goto done;
}
if (!cfg->flag_start) {
if (node->ext.lr_info.tm.tm_year) {
os_mem_set(&node->ext.lr_info.tm, 0x0, sizeof(iot_time_tm_t));
}
goto done;
}
if (user_type != USER_TYPE_SOUTHEN_POWER_GRID_SHENZHEN) {
/* All DI of the NW adopt the same collect interval. */
period = cfg->di_info[0].interval * 60;
}
switch (lc_info->state) {
case IOT_SG_STA_EXT_LC_STATE_IDLE:
{
if (!node->ext.lr_info.tm.tm_year && !node->ext.lr_info.tm.tm_mon
&& !node->ext.lr_info.tm.tm_mday && !node->ext.lr_info.tm.tm_hour
&& !node->ext.lr_info.tm.tm_min && !node->ext.lr_info.tm.tm_sec) {
/* load read load curve data time stamp */
node->ext.lr_info.tm = iot_sg_sta_ext_nw_get_next_lr_ts(tm, period);
goto done;
} else if (iot_rtc_delta_calc(&node->ext.lr_info.tm, &tm) >= 0) {
if (iot_sg_sta_ext_nw_lc_di_update(cfg) != ERR_OK) {
goto done;
}
/* when current tm is greater than or equal to next tm of
* reading load curve data, start read load curve data.
*/
lc_info->state = IOT_SG_STA_EXT_LC_STATE_SEND;
lc_info->di_idx = 0;
flag_new = 1;
goto send;
} else {
goto done;
}
break;
}
case IOT_SG_STA_EXT_LC_STATE_WAIT:
{
if (!lc_info->timeout_cnt) {
if (!node->ext.lr_info.multi_di_detect_done) {
node->ext.lr_info.multi_di_detect_done = 1;
if (lc_info->flag_multi_resp) {
lc_info->flag_multi_resp = 0;
node->ext.lr_info.multi_di_supported = 1;
} else {
node->ext.lr_info.multi_di_supported = 0;
lc_info->last_di_idx = 0;
lc_info->di_idx = 0;
flag_new = 1;
goto send;
}
}
if (lc_info->flag_resp) {
lc_info->repeat_cnt = 0;
}
if (!lc_info->repeat_cnt) {
lc_info->di_idx++;
if (iot_sg_sta_ext_nw_lc_di_update(cfg) != ERR_OK) {
iot_sg_sta_ext_nw_lc_data_save(addr, &node->ext.lr_info.tm);
node->ext.lr_info.tm =
iot_sg_sta_ext_nw_get_next_lr_ts(tm, period);
goto done;
} else {
flag_new = 1;
}
} else {
lc_info->repeat_cnt--;
if (iot_sg_sta_ext_multi_di_read_check(node)) {
lc_info->di_idx = lc_info->last_di_idx;
}
}
lc_info->state = IOT_SG_STA_EXT_LC_STATE_SEND;
goto send;
} else {
lc_info->timeout_cnt--;
}
break;
}
case IOT_SG_STA_EXT_LC_STATE_SEND:
{
send:
if (lc_info->di_idx >= IOT_SG_STA_FLASH_NW_CFG_DI_MAX_CNT) {
goto done;
}
if (iot_sg_sta_ext_multi_di_read_check(node)) {
lc_info->last_di_idx = lc_info->di_idx;
lc_info->flag_multi_resp = 0;
pkt = iot_sg_sta_ext_multi_di_msg_build(addr, cfg);
} else {
pkt = proto_645_build_mr_msg(PROTO_645_2007_ID, addr,
cfg->di_info[lc_info->di_idx].di);
}
if (pkt) {
timeout = (IOT_SG_STA_EXT_READ_DATA_TIMEOUT *
IOT_SG_STA_EXT_SM_DELAY / 100);
timeout = min(timeout, IOT_SG_STA_EXT_DRV_READ_TIMEOUT);
ret = iot_sg_sta_add_mr_req(IOT_SG_STA_MR_SRC_ID_NW_LC,
addr, 0, node->data_type, iot_pkt_data(pkt),
(uint16_t)iot_pkt_data_len(pkt), timeout);
if (ret == ERR_OK) {
iot_sg_printf("%s addr %02x:%02x:%02x:%02x:%02x:%02x idx %lu\n",
__FUNCTION__, addr[0], addr[1], addr[2], addr[3], addr[4],
addr[5], lc_info->di_idx);
lc_info->state = IOT_SG_STA_EXT_LC_STATE_WAIT;
lc_info->timeout_cnt = IOT_SG_STA_EXT_READ_DATA_TIMEOUT;
if (flag_new) {
lc_info->repeat_cnt = 1;
}
lc_info->flag_resp = 0;
}
iot_pkt_free(pkt);
}
break;
}
default:
IOT_ASSERT(0);
break;
}
goto out;
done:
complete = 1;
out:
if (pkt_cfg) {
iot_pkt_free(pkt_cfg);
}
if (last_state != lc_info->state) {
iot_sg_printf("%s addr %02x:%02x:%02x:%02x:%02x:%02x state %lu to %lu\n"
, __FUNCTION__, addr[0], addr[1], addr[2], addr[3], addr[4],
addr[5], last_state, lc_info->state);
}
return complete;
}
#endif /* PLC_SUPPORT_STA_ROLE && IOT_NW_APP_ENABLE */