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

968 lines
30 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_timer_api.h"
#include "os_utils_api.h"
/* iot common header files */
#include "iot_app_api.h"
#include "iot_io_api.h"
#include "iot_oem_api.h"
#include "iot_module_api.h"
#include "iot_dbglog_api.h"
/* smart grid internal header files */
#include "iot_sg.h"
#include "iot_sg_sta.h"
#include "iot_sg_sta_conn_less.h"
#include "proto_645_vendor.h"
#if (IOT_SMART_GRID_ENABLE && IOT_SMART_GRID_CONN_LESS_PLC)
/* define secondary node black listed duration. unit is 1s */
#define IOT_SG_STA_CONN_LESS_NODE_BL_DUR (5 * 60)
/* define max retry count of connectionless meter reading */
#define IOT_SG_STA_CONN_LESS_READ_MAX_CNT 1
/* define meter reading interval, uint is 1ms */
#define IOT_SG_STA_CONN_LESS_READ_INTER 60
/* define brm connless message retry cnt */
#define IOT_SG_STA_BRM_CONN_LESS_RETRY_CNT 1
void iot_sg_sta_conn_less_data_push(uint8_t *addr, uint16_t seq,
uint8_t *data, uint32_t len, uint8_t type)
{
uint8_t dst_addr[IOT_MAC_ADDR_LEN];
uint16_t total_size, payload_size;
proto_conn_less_hdr_t *rsp_hdr;
proto_conn_less_push_data_t *rsp;
iot_pkt_t *plc_pkt;
payload_size = (uint16_t)len;
total_size = sizeof(*rsp_hdr) + sizeof(*rsp) + payload_size;
iot_set_bcast_mac(dst_addr);
plc_pkt = iot_plc_alloc_conn_less_msdu(p_sg_glb->plc_app_h,
IOT_PLC_MSG_TYPE_CONN_LESS_DATA, dst_addr, p_sg_glb->plc_state.addr,
CONN_LESS_APP_PRIO_METER_READ, total_size, IOT_PLC_MAX_RETRY_CNT);
if (plc_pkt) {
/* fill in header */
rsp_hdr = (proto_conn_less_hdr_t *)iot_pkt_block_ptr(plc_pkt,
IOT_PKT_BLOCK_TAIL);
rsp_hdr->id = CONN_LESS_APP_ID_DATA_PUSH;
rsp_hdr->port = CONN_LESS_APP_PORT;
rsp = (proto_conn_less_push_data_t *)(rsp_hdr + 1);
rsp->seq = seq;
rsp->data_type = type;
rsp->data_len = payload_size;
rsp->dir = CONN_LESS_APP_DIR_SLAVE;
iot_mac_addr_cpy(rsp->addr, addr);
/* fill in payload */
if (data && len) {
os_mem_cpy(rsp->data, data, rsp->data_len);
}
iot_pkt_put(plc_pkt, total_size);
iot_sg_send_msdu(plc_pkt, IOT_SG_LINK_TYPE_PLC_CONN_LESS);
} else {
iot_sg_printf("%s err\n", __FUNCTION__);
}
}
static uint32_t iot_sg_sta_conn_less_push_data_handle(iot_pkt_t *pkt,
proto_conn_less_hdr_t *hdr)
{
uint8_t addr[IOT_MAC_ADDR_LEN];
uint16_t seq;
uint32_t ret = ERR_OK, tmp, total_len, reason;
iot_pkt_t *drv_pkt;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_drv_t *drv = sta_glb->drv;
proto_conn_less_push_data_t *req = (proto_conn_less_push_data_t *)(hdr + 1);
if (drv->push_data == NULL) {
reason = 1;
ret = ERR_NOSUPP;
goto drop;
}
/* check header length */
tmp = sizeof(*req) + sizeof(*hdr);
total_len = iot_pkt_block_len(pkt, IOT_PKT_BLOCK_DATA);
if (tmp > total_len) {
reason = 2;
ret = ERR_INVAL;
goto drop;
}
if (req->data_len > (total_len - tmp)) {
reason = 3;
ret = ERR_INVAL;
goto drop;
}
seq = req->seq;
if (seq == sta_glb->seq_last_push) {
reason = 4;
ret = ERR_INVAL;
goto drop;
}
iot_mac_addr_cpy(addr, req->addr);
if (drv->headroom <= tmp) {
iot_pkt_set_data(pkt, req->data);
iot_pkt_set_tail(pkt, (req->data + req->data_len));
drv->push_data(pkt, (uint8_t)req->data_type, 0, addr, seq);
} else {
tmp = req->data_len;
drv_pkt = iot_pkt_alloc(tmp + drv->headroom, IOT_SMART_GRID_MID);
if (drv_pkt == NULL) {
ret = ERR_NOMEM;
reason = 5;
goto drop;
}
iot_pkt_reserve(drv_pkt, drv->headroom);
os_mem_cpy(iot_pkt_put(drv_pkt, tmp), req->data, tmp);
drv->push_data(drv_pkt, (uint8_t)req->data_type, 0, addr, seq);
iot_pkt_free(pkt);
}
sta_glb->seq_last_push = seq;
goto out;
drop:
iot_pkt_free(pkt);
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
out:
return ret;
}
uint32_t iot_sg_sta_conn_less_sec_check(uint8_t *data, uint32_t len)
{
uint32_t ret = ERR_OK;
uint8_t reason = 0;
proto_conn_less_hdr_t *hdr = NULL;
proto_conn_less_mr_t *mr_req;
proto_conn_less_push_data_t *push_req;
if (sizeof(proto_conn_less_hdr_t) >= len) {
reason = 1;
ret = ERR_INVAL;
goto drop;
}
hdr = (proto_conn_less_hdr_t *)data;
len -= sizeof(*hdr);
switch (hdr->id) {
case CONN_LESS_APP_ID_METER_R:
{
mr_req = (proto_conn_less_mr_t *)(hdr + 1);
if (sizeof(*mr_req) > len) {
reason = 2;
ret = ERR_INVAL;
goto drop;
}
len -= sizeof(*mr_req);
if (mr_req->data_len > len) {
reason = 3;
ret = ERR_INVAL;
goto drop;
}
if (mr_req->dir != CONN_LESS_APP_DIR_MASTER) {
reason = 4;
ret = ERR_INVAL;
goto drop;
}
break;
}
case CONN_LESS_APP_ID_DATA_PUSH:
{
push_req = (proto_conn_less_push_data_t *)(hdr + 1);
if (sizeof(*push_req) > len) {
reason = 5;
ret = ERR_INVAL;
goto drop;
}
len -= sizeof(*push_req);
if (push_req->data_len > len) {
reason = 6;
ret = ERR_INVAL;
goto drop;
}
if (push_req->dir != CONN_LESS_APP_DIR_MASTER) {
reason = 7;
ret = ERR_INVAL;
goto drop;
}
break;
}
case CONN_LESS_APP_ID_CORRECT_TIME:
case CONN_LESS_APP_ID_TSFM_INFO_RPT:
break;
default:
reason = 8;
ret = ERR_NOSUPP;
goto drop;
}
goto out;
drop:
iot_sg_printf("%s err %lu id %lu\n", __FUNCTION__, reason,
(hdr ? hdr->id : 0));
out:
return ret;
}
uint8_t iot_sg_sta_conn_less_sn_cmp(uint8_t *dst_hdr, uint8_t *src_hdr)
{
uint8_t ret = 0;
proto_conn_less_hdr_t *hdr, *hdr_queue;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
hdr = (proto_conn_less_hdr_t *)src_hdr;
hdr_queue = (proto_conn_less_hdr_t *)dst_hdr;
iot_plc_msdu_recv_t *old_msdu = (iot_plc_msdu_recv_t *)(dst_hdr -
sizeof(iot_plc_msdu_recv_t));
iot_plc_msdu_recv_t *in_msdu = (iot_plc_msdu_recv_t *)(src_hdr -
sizeof(iot_plc_msdu_recv_t));
if ((iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_HLJ)
&& IOT_DEV_TEST_CCO_MODE
&& !iot_mac_addr_valid(sta_glb->mr.last_conn_less_mr_addr)
&& iot_mac_addr_cmp(old_msdu->src, in_msdu->src)) {
ret = 1;
iot_sg_printf("%s from same cco\n", __FUNCTION__);
goto out;
}
if (hdr->id != hdr_queue->id)
goto out;
switch (hdr->id) {
case CONN_LESS_APP_ID_METER_R:
{
proto_conn_less_mr_t *req, *req_queue;
req = (proto_conn_less_mr_t *)(hdr + 1);
req_queue = (proto_conn_less_mr_t *)(hdr_queue + 1);
if (req_queue->seq == req->seq
&& iot_mac_addr_cmp(old_msdu->src, in_msdu->src)) {
ret = 1;
}
break;
}
case CONN_LESS_APP_ID_DATA_PUSH:
{
proto_conn_less_push_data_t *req, *req_queue;
req = (proto_conn_less_push_data_t *)(hdr + 1);
req_queue = (proto_conn_less_push_data_t *)(hdr_queue + 1);
if (req_queue->seq == req->seq
&& iot_mac_addr_cmp(old_msdu->src, in_msdu->src)) {
ret = 1;
}
break;
}
default:
break;
}
out:
return ret;
}
/* check if exist is meter read request data in the cache. */
static uint32_t iot_sg_sta_conn_less_mr_cache_check(uint16_t seq,
uint8_t *src_addr, uint8_t link_type, int8_t ppm, uint8_t is_rf)
{
uint8_t *data;
uint32_t ret = ERR_OK, len;
uint64_t elapse_t, cur_t;
iot_pkt_t *new_pkt;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_plc_app_h handle;
uint8_t tx_link_type = IOT_PLC_TX_LINK_TYPE_HPLC;
if (is_rf) {
tx_link_type = IOT_PLC_TX_LINK_TYPE_RF;
}
if (sta_glb->mr.last_conn_less_mr_valid &&
sta_glb->mr.last_mr_seq == seq
&& sta_glb->mr.last_mr_data_pkt
&& iot_mac_addr_cmp(sta_glb->mr.last_conn_less_src, src_addr)) {
cur_t = os_boot_time64();
elapse_t = cur_t - sta_glb->mr.last_mr_ts;
if (elapse_t <= IOT_SG_STA_LAST_MR_CACHE_LIFE) {
if (link_type == IOT_SG_LINK_TYPE_PLC_BRM) {
handle = p_sg_glb->brm_app_h;
} else {
handle = p_sg_glb->plc_app_h;
}
data = iot_pkt_data(sta_glb->mr.last_mr_data_pkt);
len = iot_pkt_data_len(sta_glb->mr.last_mr_data_pkt);
new_pkt = iot_plc_alloc_conn_less_msdu_ext(handle,
IOT_PLC_MSG_TYPE_CONN_LESS_DATA, src_addr,
p_sg_glb->plc_state.addr, CONN_LESS_APP_PRIO_METER_READ,
(uint16_t)len, IOT_PLC_MAX_RETRY_CNT, ppm, 1, tx_link_type);
if (!new_pkt) {
goto out;
}
os_mem_cpy(iot_pkt_tail(new_pkt), data, len);
iot_pkt_put(new_pkt, len);
iot_sg_send_msdu(new_pkt, link_type);
ret = ERR_EXIST;
}
}
out:
return ret;
}
uint32_t iot_sg_sta_conn_less_queue_cache_check(iot_pkt_t *pkt,
uint8_t link_type)
{
uint32_t ret = ERR_OK;
int8_t ppm = 0;
proto_conn_less_hdr_t *hdr;
proto_conn_less_mr_t *req;
iot_plc_msdu_recv_t *msdu;
msdu = (iot_plc_msdu_recv_t *)(iot_pkt_data(pkt) - sizeof(*msdu));
hdr = (proto_conn_less_hdr_t *)iot_pkt_data(pkt);
switch (hdr->id) {
case CONN_LESS_APP_ID_METER_R:
{
req = (proto_conn_less_mr_t *)(hdr + 1);
if (req->dir == PROTO_645_DIR_MASTER) {
ppm = -req->option.dl_ppm_desc.value;
iot_sg_printf("%s ppm %d\n", __FUNCTION__, ppm);
}
ret = iot_sg_sta_conn_less_mr_cache_check(req->seq, msdu->src,
link_type, ppm, (uint8_t)msdu->is_rf);
break;
}
default:
break;
}
return ret;
}
uint32_t iot_sg_sta_conn_less_get_pm_addr(iot_pkt_t *pkt,
uint8_t *addr)
{
uint8_t *ser_addr;
uint32_t ret = ERR_FAIL;
proto_conn_less_hdr_t *hdr;
proto_conn_less_mr_t *req;
proto_645_header_t *hdr_645;
proto_69845_frame_head_info_t *hdr_69845;
hdr = (proto_conn_less_hdr_t *)iot_pkt_data(pkt);
if (hdr->id == CONN_LESS_APP_ID_METER_R) {
req = (proto_conn_less_mr_t *)(hdr + 1);
switch (req->data_type) {
case IOT_SG_STA_DATA_TYPE_645_97:
case IOT_SG_STA_DATA_TYPE_645_07:
{
hdr_645 = proto_645_format_check(req->data, req->data_len,
PROTO_645_DIR_MASTER);
if (hdr_645 && proto_645_pm_addr_valid(hdr_645->addr)) {
iot_mac_addr_cpy(addr, hdr_645->addr);
ret = ERR_OK;
}
break;
}
case IOT_SG_STA_DATA_TYPE_69845:
{
hdr_69845 = proto_69845_sanity_check(req->data,
(uint16_t)req->data_len);
if (hdr_69845) {
ser_addr = proto_69845_get_ser_addr(hdr_69845);
iot_mac_addr_cpy(addr, ser_addr);
ret = ERR_OK;
}
break;
}
case IOT_SG_STA_DATA_TYPE_TRANS:
{
hdr_645 = proto_645_format_check(req->data, req->data_len,
PROTO_645_DIR_MASTER);
if (hdr_645) {
if (proto_645_pm_addr_valid(hdr_645->addr)) {
iot_mac_addr_cpy(addr, hdr_645->addr);
ret = ERR_OK;
}
} else {
hdr_69845 = proto_69845_sanity_check(req->data,
(uint16_t)req->data_len);
if (hdr_69845) {
ser_addr = proto_69845_get_ser_addr(hdr_69845);
iot_mac_addr_cpy(addr, ser_addr);
ret = ERR_OK;
}
}
break;
}
default:
break;
}
}
return ret;
}
static uint32_t iot_sg_sta_conn_less_meter_read(iot_pkt_t *pkt,
proto_conn_less_hdr_t *hdr)
{
uint32_t ret = ERR_OK;
uint8_t reason = 0, addr[IOT_MAC_ADDR_LEN];
uint8_t user_type = iot_sg_sta_get_user_type();
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
proto_conn_less_mr_t *mr_req = (proto_conn_less_mr_t *)(hdr + 1);
if ((user_type == USER_TYPE_STATE_GRID_HLJ)
&& IOT_DEV_TEST_CCO_MODE
&& iot_mac_addr_valid(sta_glb->mr.last_conn_less_mr_addr)
&& (iot_sg_sta_conn_less_get_pm_addr(sta_glb->req.pkt,
addr) == ERR_OK)) {
/* check high byte in address */
if (addr[3] != sta_glb->mr.last_conn_less_mr_addr[3]
|| addr[4] != sta_glb->mr.last_conn_less_mr_addr[4]
|| addr[5] != sta_glb->mr.last_conn_less_mr_addr[5]) {
reason = 1;
ret = ERR_FAIL;
goto drop;
}
}
if (mr_req->retry_cnt) {
sta_glb->mr.max_retry = mr_req->retry_cnt;
sta_glb->mr.timeout_retry = 1;
} else {
if ((user_type == USER_TYPE_STATE_GRID_HLJ)
&& IOT_DEV_TEST_CCO_MODE) {
sta_glb->mr.max_retry = 1;
sta_glb->mr.timeout_retry = 1;
} else {
sta_glb->mr.max_retry = 0;
sta_glb->mr.timeout_retry = 0;
}
}
sta_glb->mr.nack_retry = 0;
sta_glb->mr.mr_interval = 100;
if ((user_type == USER_TYPE_STATE_GRID_HLJ)
&& IOT_DEV_TEST_CCO_MODE) {
sta_glb->mr.mr_timeout = 1300;
} else {
sta_glb->mr.mr_timeout = mr_req->mr_timeout * 100;
}
sta_glb->mr.read_ack = 0;
sta_glb->mr.retry_cnt = 0;
sta_glb->mr.frame_idx = 0;
sta_glb->mr.frame_cnt = 0;
sta_glb->mr.mr_baud = 0;
sta_glb->mr.data_type = mr_req->data_type;
sta_glb->mr.mr_interval = IOT_SG_STA_CONN_LESS_READ_INTER;
switch (mr_req->data_type) {
case GW_APP_DATA_TYPE_TRANSPARENT:
{
ret = iot_sg_sta_parse_frame(mr_req->data, (uint16_t)mr_req->data_len);
if (ret == ERR_OK)
break;
}
case GW_APP_DATA_TYPE_69845:
{
if (mr_req->data_len > IOT_SG_STA_MAX_MR_MSG_LEN) {
reason = 2;
ret = ERR_NOMEM;
goto drop;
}
sta_glb->mr.frame_data[0] = mr_req->data;
sta_glb->mr.frame_len[0] = (uint16_t)mr_req->data_len;
sta_glb->mr.frame_cnt = 1;
break;
}
case GW_APP_DATA_TYPE_645_1997:
case GW_APP_DATA_TYPE_645_2007:
{
ret = iot_sg_sta_parse_frame(mr_req->data, (uint16_t)mr_req->data_len);
if (ret) {
reason = 3;
goto drop;
}
break;
}
default:
reason = 4;
ret = ERR_FAIL;
goto drop;
}
/* trigger the first pending frame */
ret = iot_sg_sta_issue_frame();
if (ret == ERR_PENDING) {
sta_glb->mr.meter_read_on = 1;
} else if (ret) {
reason = 5;
goto drop;
}
goto out;
drop:
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
out:
if (sta_glb->mr.meter_read_on == 0) {
/* for pending case, the pkt will be freed in
* iot_sg_sta_meter_read_done_intern function.
*/
iot_pkt_free(pkt);
}
return ret;
}
void iot_sg_sta_conn_less_mr_done(uint8_t data_type, uint8_t done_src,
iot_pkt_t *rsp_pkt)
{
uint8_t *data, addr[IOT_MAC_ADDR_LEN], dev_addr[IOT_MAC_ADDR_LEN];
uint16_t len;
uint32_t ret, new_pkt, size;
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
iot_sg_sta_mr_stats_t *mr_stats = &sta_glb->mr.mr_info;
proto_conn_less_hdr_t *req_hdr, *rsp_hdr;
proto_conn_less_mr_t *req, *rsp = NULL;
iot_plc_msdu_recv_t *msdu;
iot_pkt_t *req_pkt = sta_glb->req.pkt;
iot_pkt_t *plc_pkt = NULL;
iot_plc_app_h handle;
uint8_t retry_cnt;
int8_t ppm = 0;
uint8_t tx_link_type = IOT_PLC_TX_LINK_TYPE_HPLC;
if (sta_glb->req.link_type == IOT_SG_LINK_TYPE_APP) {
if (rsp_pkt) {
data = iot_pkt_data(rsp_pkt);
len = (uint16_t)iot_pkt_data_len(rsp_pkt);
} else {
data = NULL;
len = 0;
}
iot_sg_sta_handle_mr_resp(data_type, data, len);
if (rsp_pkt)
iot_pkt_free(rsp_pkt);
goto next_req;
} else if (sta_glb->req.link_type == IOT_SG_LINK_TYPE_CUS) {
iot_sg_sta_handle_cus_mr_resp(rsp_pkt);
goto next_req;
}
data = iot_pkt_data(req_pkt);
msdu = (iot_plc_msdu_recv_t *)(data - sizeof(*msdu));
req_hdr = (proto_conn_less_hdr_t *)data;
req = (proto_conn_less_mr_t *)(req_hdr + 1);
if (rsp_pkt == NULL) {
if (sta_glb->mr.timeout_retry) {
if (sta_glb->mr.retry_cnt < sta_glb->mr.max_retry) {
sta_glb->mr.retry_cnt++;
goto re_issue;
}
}
sta_glb->drv->get_device_addr(dev_addr);
if (done_src == IOT_SG_STA_MR_DONE_BY_DRIVE
&& (sta_glb->req.link_type == IOT_SG_LINK_TYPE_PLC_CONN_LESS)
&& (iot_sg_sta_conn_less_get_pm_addr(req_pkt, addr) == ERR_OK)
&& !iot_sg_sta_node_find_by_addr(addr)
&& !iot_mac_addr_cmp(dev_addr, addr)
&& !iot_mac_addr_cmp(addr, proto_645_any_addr)) {
iot_sg_sta_bl_node_add(addr, IOT_SG_STA_CONN_LESS_NODE_BL_DUR);
goto done;
}
goto issue_next_frame;
}
if (req->dir == CONN_LESS_APP_DIR_MASTER) {
ppm = -req->option.dl_ppm_desc.value;
iot_sg_printf("%s ppm value %d\n", __FUNCTION__, ppm);
}
if (msdu->is_rf) {
tx_link_type = IOT_PLC_TX_LINK_TYPE_RF;
}
if (sta_glb->mr.read_rsp) {
new_pkt = 0;
plc_pkt = sta_glb->mr.read_rsp;
size = iot_pkt_data_len(rsp_pkt);
rsp_hdr = (proto_conn_less_hdr_t *)sta_glb->mr.app_hdr;
rsp = (proto_conn_less_mr_t*)(rsp_hdr + 1);
if (size > iot_pkt_tail_len(plc_pkt)) {
/* no enough room left, calculate required size */
size += sizeof(*rsp_hdr) + sizeof(*rsp) + rsp->data_len;
if (size > PROTO_CONN_LESS_MR_RESPONSE_MAX_SIZE) {
iot_counter_inc(mr_stats->mr_err_cnts[\
IOT_SG_STA_MR_ERR_CON_NMEM_3]);
iot_sg_printf("%s size over, seq %lu ack %04x\n", __FUNCTION__,
req->seq, rsp->option.up_ack_bm);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_WARN,
IOT_SG_STA_MR_ERR_CON_NMEM_3_ID, 2, req->seq,
rsp->option.up_ack_bm);
goto done;
}
/* allocate new packet */
if (sta_glb->req.link_type == IOT_SG_LINK_TYPE_PLC_BRM) {
retry_cnt = IOT_SG_STA_BRM_CONN_LESS_RETRY_CNT;
handle = p_sg_glb->brm_app_h;
} else {
retry_cnt = IOT_PLC_MAX_RETRY_CNT;
handle = p_sg_glb->plc_app_h;
}
plc_pkt = iot_plc_alloc_conn_less_msdu_ext(handle,
IOT_PLC_MSG_TYPE_CONN_LESS_DATA, msdu->src,
p_sg_glb->plc_state.addr, CONN_LESS_APP_PRIO_METER_READ,
(uint16_t)size, retry_cnt, ppm, 1, tx_link_type);
if (plc_pkt == NULL) {
iot_counter_inc(mr_stats->mr_err_cnts[ \
IOT_SG_STA_MR_ERR_CON_NMEM_2]);
iot_sg_printf("%s mem expand err seq %lu ack %04x\n",
__FUNCTION__, req->seq, rsp->option.up_ack_bm);
iot_dbglog_input(IOT_SMART_GRID_MID, DBGLOG_WARN,
IOT_SG_STA_MR_ERR_CON_NMEM_2_ID, 2, req->seq,
rsp->option.up_ack_bm);
goto done;
}
/* copy data from old pkt to new pkt */
size = sizeof(*rsp_hdr) + sizeof(*rsp) + rsp->data_len;
os_mem_cpy(iot_pkt_tail(plc_pkt), sta_glb->mr.app_hdr, size);
sta_glb->mr.app_hdr = iot_pkt_tail(plc_pkt);
iot_pkt_put(plc_pkt, size);
iot_pkt_free(sta_glb->mr.read_rsp);
sta_glb->mr.read_rsp = plc_pkt;
rsp_hdr = (proto_conn_less_hdr_t *)sta_glb->mr.app_hdr;
rsp = (proto_conn_less_mr_t *)(rsp_hdr + 1);
}
} else {
new_pkt = 1;
/* use first meter read response to estimate the required data len */
size = iot_pkt_data_len(rsp_pkt) * sta_glb->mr.frame_cnt;
if (size > IOT_SG_STA_RESPONSE_MAX_SIZE)
size = IOT_SG_STA_RESPONSE_MAX_SIZE;
size += sizeof(*rsp_hdr) + sizeof(*rsp);
if (sta_glb->req.link_type == IOT_SG_LINK_TYPE_PLC_BRM) {
retry_cnt = IOT_SG_STA_BRM_CONN_LESS_RETRY_CNT;
handle = p_sg_glb->brm_app_h;
} else {
retry_cnt = IOT_PLC_MAX_RETRY_CNT;
handle = p_sg_glb->plc_app_h;
}
plc_pkt = iot_plc_alloc_conn_less_msdu_ext(handle,
IOT_PLC_MSG_TYPE_CONN_LESS_DATA, msdu->src,
p_sg_glb->plc_state.addr, CONN_LESS_APP_PRIO_METER_READ,
(uint16_t)size, retry_cnt, ppm, 1, tx_link_type);
if (plc_pkt == NULL) {
iot_pkt_free(rsp_pkt);
goto done;
}
sta_glb->mr.read_rsp = plc_pkt;
}
/* save the response data */
data = iot_pkt_tail(plc_pkt);
if (new_pkt) {
sta_glb->mr.app_hdr = data;
rsp_hdr = (proto_conn_less_hdr_t *)data;
rsp_hdr->id = req_hdr->id;
rsp_hdr->port = CONN_LESS_APP_PORT;
rsp = (proto_conn_less_mr_t *)(rsp_hdr + 1);
rsp->seq = req->seq;
rsp->data_type = req->data_type;
rsp->dir = CONN_LESS_APP_DIR_SLAVE;
rsp->data_len = 0;
rsp->option.up_ack_bm = 0;
iot_pkt_put(plc_pkt, sizeof(*rsp_hdr) + sizeof(*rsp));
}
rsp->option.up_ack_bm |= (1 << sta_glb->mr.frame_idx);
os_mem_cpy(rsp->data + rsp->data_len, iot_pkt_data(rsp_pkt),
iot_pkt_data_len(rsp_pkt));
iot_pkt_put(plc_pkt, iot_pkt_data_len(rsp_pkt));
rsp->data_len += iot_pkt_data_len(rsp_pkt);
iot_pkt_free(rsp_pkt);
issue_next_frame:
sta_glb->mr.retry_cnt = 0;
sta_glb->mr.frame_idx++;
re_issue:
ret = iot_sg_sta_issue_frame();
if (ret == ERR_PENDING) {
/* do nothing */
goto out;
}
done:
if (sta_glb->mr.read_rsp) {
if ((iot_sg_sta_get_user_type() == USER_TYPE_STATE_GRID_HLJ)
&& IOT_DEV_TEST_CCO_MODE
&& (iot_sg_sta_conn_less_get_pm_addr(req_pkt, addr) == ERR_OK)) {
iot_mac_addr_cpy(sta_glb->mr.last_conn_less_mr_addr, addr);
}
iot_sg_send_msdu(plc_pkt, sta_glb->req.link_type);
if (!rsp) {
rsp_hdr = (proto_conn_less_hdr_t *)sta_glb->mr.app_hdr;
rsp = (proto_conn_less_mr_t *)(rsp_hdr + 1);
}
size = rsp->data_len + sizeof(*rsp) + sizeof(*rsp_hdr);
/* cache the latest meter reading data */
if (size <= IOT_SG_STA_LAST_RESPONSE_MAX_SIZE) {
if (sta_glb->mr.last_mr_data_pkt) {
iot_pkt_free(sta_glb->mr.last_mr_data_pkt);
sta_glb->mr.last_mr_data_pkt = NULL;
}
sta_glb->mr.last_mr_data_pkt = iot_pkt_alloc(size,
IOT_SMART_GRID_MID);
if (sta_glb->mr.last_mr_data_pkt) {
sta_glb->mr.last_mr_seq = rsp->seq;
sta_glb->mr.last_conn_less_mr_valid = 1;
sta_glb->mr.last_mr_valid = 0;
sta_glb->mr.last_crtl_mr_valid = 0;
sta_glb->mr.last_mr_ts = os_boot_time64();
iot_mac_addr_cpy(sta_glb->mr.last_conn_less_src, msdu->src);
os_mem_cpy(iot_pkt_put(sta_glb->mr.last_mr_data_pkt,
size), sta_glb->mr.app_hdr, size);
}
}
sta_glb->mr.read_rsp = NULL;
sta_glb->mr.app_hdr = NULL;
}
next_req:
/* mark current meter read done */
sta_glb->mr.meter_read_on = 0;
/* trigger next request in the queue */
iot_sg_sta_start_next_app_other();
out:
return;
}
static void iot_sg_sta_gw_conn_less_correct_time(iot_pkt_t *pkt,
proto_conn_less_hdr_t *hdr)
{
uint32_t len;
uint8_t reason = 0;
len = iot_pkt_data_len(pkt);
iot_sg_sta_global_t *sta_glb = p_sg_glb->desc.sta;
proto_conn_less_correct_time_t *ct_req =
(proto_conn_less_correct_time_t *)(hdr + 1);
if (len < sizeof(*hdr)) {
reason = 1;
goto out;
}
len -= sizeof(*hdr);
if (len < sizeof(*ct_req) + ct_req->len) {
reason = 2;
goto out;
}
iot_pkt_set_data(pkt, ct_req->data);
iot_pkt_set_tail(pkt, ct_req->data + ct_req->len);
sta_glb->drv->correct_time(pkt, 0);
out:
if (reason) {
iot_sg_printf("%s err %lu\n", __FUNCTION__, reason);
}
return;
}
uint32_t iot_sg_sta_handle_conn_less(iot_pkt_t *pkt)
{
uint32_t ret = ERR_OK;
proto_conn_less_hdr_t *hdr;
hdr = (proto_conn_less_hdr_t *)iot_pkt_block_ptr(pkt, IOT_PKT_BLOCK_DATA);
if (iot_sg_sta_power_off_check()) {
/* when sta is power off, sta won't handle any message */
iot_pkt_free(pkt);
goto out;
}
switch (hdr->id) {
case CONN_LESS_APP_ID_METER_R:
ret = iot_sg_sta_conn_less_meter_read(pkt, hdr);
break;
case CONN_LESS_APP_ID_DATA_PUSH:
ret = iot_sg_sta_conn_less_push_data_handle(pkt, hdr);
break;
case CONN_LESS_APP_ID_CORRECT_TIME:
iot_sg_sta_gw_conn_less_correct_time(pkt, hdr);
break;
default:
iot_pkt_free(pkt);
ret = ERR_NOSUPP;
break;
}
out:
return ret;
}
static void iot_sg_sta_brm_recv(void *param, iot_pkt_t *pkt)
{
(void)param;
/* deliver the message to smart grid task for handling */
iot_task_msg_t *t_msg = iot_task_alloc_msg(p_sg_glb->task_h);
if (t_msg) {
iot_sg_msg_t *msg = (iot_sg_msg_t *)t_msg;
msg->data = pkt;
t_msg->type = IOT_SG_MSG_TYPE_BRM;
t_msg->id = IOT_SG_MSG_ID_PLC_MSG;
iot_task_queue_msg(p_sg_glb->task_h, t_msg, IOT_SG_MSG_QUEUE_LP);
}
}
uint32_t iot_sg_sta_brm_init(void)
{
iot_plc_app_t brm_app = { 0 };
if (IOT_BRM_ENABLE)
return ERR_OK;
brm_app.app_id = IOT_BRM_APP_ID;
brm_app.param = NULL;
brm_app.prio = 0;
brm_app.recv = iot_sg_sta_brm_recv;
p_sg_glb->brm_app_h = iot_plc_register_app(&brm_app);
if (p_sg_glb->brm_app_h == NULL) {
return ERR_BUSY;
}
return ERR_OK;
}
uint8_t iot_sg_sta_conn_eless_proto_change(uint8_t proto)
{
uint8_t rpt_proto = CONN_LESS_PROTO_TYPE_TRANSPARENT;
switch (proto) {
case IOT_SG_STA_DATA_TYPE_69845:
{
rpt_proto = CONN_LESS_PROTO_TYPE_69845;
break;
}
case IOT_SG_STA_DATA_TYPE_645_97:
{
rpt_proto = CONN_LESS_PROTO_TYPE_645_1997;
break;
}
case IOT_SG_STA_DATA_TYPE_645_07:
{
rpt_proto = CONN_LESS_PROTO_TYPE_645_2007;
break;
}
default:
break;
}
return rpt_proto;
}
void iot_sg_sta_tsfm_info_rpt(iot_sg_sta_tsfm_info_rpt_t *tsfm_info)
{
uint8_t dst_addr[IOT_MAC_ADDR_LEN];
uint16_t total_size;
proto_conn_less_hdr_t *rsp_hdr;
proto_conn_less_tsfm_info_rpt_t *rpt;
iot_pkt_t *plc_pkt;
total_size = sizeof(*rsp_hdr) + sizeof(*rpt);
iot_set_bcast_mac(dst_addr);
plc_pkt = iot_plc_alloc_conn_less_msdu(p_sg_glb->brm_app_h,
IOT_PLC_MSG_TYPE_CONN_LESS_DATA, dst_addr, p_sg_glb->plc_state.addr,
CONN_LESS_APP_PRIO_METER_READ, total_size, IOT_PLC_MAX_RETRY_CNT);
if (plc_pkt) {
/* fill in header */
rsp_hdr = (proto_conn_less_hdr_t *)iot_pkt_block_ptr(plc_pkt,
IOT_PKT_BLOCK_TAIL);
rsp_hdr->id = CONN_LESS_APP_ID_TSFM_INFO_RPT;
rsp_hdr->port = CONN_LESS_APP_PORT;
rpt = (proto_conn_less_tsfm_info_rpt_t *)(rsp_hdr + 1);
rpt->ver = CONN_LESS_APP_PROTO_VERSION;
rpt->pro_type = tsfm_info->pro_type;
rpt->dev_type = tsfm_info->dev_type;
rpt->phase_1 = tsfm_info->phase_1;
rpt->phase_2 = tsfm_info->phase_2;
rpt->phase_3 = tsfm_info->phase_3;
iot_mac_addr_cpy(rpt->sta_mac, tsfm_info->sta_mac);
iot_mac_addr_cpy(rpt->cco_mac, tsfm_info->cco_mac);
iot_mac_addr_cpy(rpt->tsfm_mac, tsfm_info->tsfm_mac);
iot_pkt_put(plc_pkt, total_size);
iot_sg_send_msdu(plc_pkt, IOT_SG_LINK_TYPE_PLC_CONN_LESS);
} else {
iot_sg_printf("%s err\n", __FUNCTION__);
}
}
#else /* IOT_SMART_GRID_ENABLE && IOT_SMART_GRID_CONN_LESS_PLC */
void iot_sg_sta_conn_less_data_push(uint8_t *addr, uint16_t seq,
uint8_t *data, uint32_t len, uint8_t type)
{
(void)addr;
(void)seq;
(void)data;
(void)len;
(void)type;
}
uint32_t iot_sg_sta_conn_less_sec_check(uint8_t *data, uint32_t len)
{
(void)len;
(void)data;
return ERR_OK;
}
uint8_t iot_sg_sta_conn_less_sn_cmp(uint8_t *dst_hdr, uint8_t *src_hdr)
{
(void)dst_hdr;
(void)src_hdr;
return ERR_OK;
}
void iot_sg_sta_conn_less_mr_done(uint8_t data_type, uint8_t done_src,
iot_pkt_t *rsp_pkt)
{
(void)done_src;
(void)data_type;
if (rsp_pkt) {
iot_pkt_free(rsp_pkt);
}
return;
}
uint32_t iot_sg_sta_conn_less_queue_cache_check(iot_pkt_t *pkt,
uint8_t link_type)
{
(void)pkt;
(void)link_type;
return ERR_OK;
}
uint32_t iot_sg_sta_conn_less_get_pm_addr(iot_pkt_t *pkt,
uint8_t *addr)
{
(void)pkt;
(void)addr;
return ERR_NOSUPP;
}
uint32_t iot_sg_sta_handle_conn_less(iot_pkt_t *pkt)
{
if(pkt)
iot_pkt_free(pkt);
return ERR_OK;
}
uint32_t iot_sg_sta_brm_init(void)
{
return ERR_OK;
}
uint8_t iot_sg_sta_conn_eless_proto_change(uint8_t proto)
{
(void)proto;
return CONN_LESS_PROTO_TYPE_TRANSPARENT;
}
void iot_sg_sta_tsfm_info_rpt(iot_sg_sta_tsfm_info_rpt_t *tsfm_info)
{
(void)tsfm_info;
}
#endif /* IOT_SMART_GRID_ENABLE && IOT_SMART_GRID_CONN_LESS_PLC */