968 lines
30 KiB
C
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 */
|
|
|