878 lines
29 KiB
C
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, ¤t_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 */
|