369 lines
12 KiB
C
369 lines
12 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.
|
|
*
|
|
* ****************************************************************************/
|
|
|
|
/* iot common header files */
|
|
#include "iot_io_api.h"
|
|
#include "iot_errno_api.h"
|
|
#include "iot_plc_msg_api.h"
|
|
#include "iot_addr_hash_table_api.h"
|
|
#include "iot_sg_ext_api.h"
|
|
|
|
/* brm internal header files */
|
|
#include "iot_brm_common.h"
|
|
#include "iot_brm_tsfm.h"
|
|
|
|
/* protocol header file */
|
|
#include "proto_conn_less.h"
|
|
|
|
#if (IOT_BRM_ENABLE)
|
|
|
|
/* define the maximum number of address information to temporary storage */
|
|
#define IOT_BRM_TSFM_ADDR_LIST_MAX 256
|
|
/* define address information listed hash table size */
|
|
#define IOT_BRM_TSFM_HASH_TABLE_SIZE 6
|
|
/* define collect timeout, unit is 1s */
|
|
#define IOT_BRM_TSFM_COLLECT_TIMEOUT 1800
|
|
|
|
/* hardware tsfm identification information descriptor */
|
|
typedef struct _iot_brm_tsfm_info_desc {
|
|
/* hash table entry */
|
|
iot_addr_hash_entry_t entry;
|
|
/* rx snr of this node */
|
|
int8_t snr;
|
|
/* node protocol type, see GW_APP_DATA_TYPE_XXX */
|
|
uint8_t pro_type : 4,
|
|
/* node device type, see GW_APP_ID_INFO_DEV_TYPE_XXX */
|
|
dev_type : 4;
|
|
/* node first physical phase line, see GW_APP_DATA_PHASE_XXX */
|
|
uint8_t phase_1 : 2,
|
|
/* node second physical phase line, see GW_APP_DATA_PHASE_XXX */
|
|
phase_2 : 2,
|
|
/* node third physical phase line, see GW_APP_DATA_PHASE_XXX */
|
|
phase_3 : 2,
|
|
/* reserve for future */
|
|
reserve : 2;
|
|
} iot_brm_tsfm_info_desc_t;
|
|
|
|
/* node list descriptor */
|
|
typedef struct _iot_brm_tsfm_node_list {
|
|
/* tsfm node info hash table */
|
|
iot_addr_hash_table_h node_table;
|
|
/* pointer to the node info in the hash tsfm info */
|
|
iot_brm_tsfm_info_desc_t *entry[IOT_BRM_TSFM_ADDR_LIST_MAX];
|
|
/* node cnt */
|
|
uint16_t node_cnt;
|
|
} iot_brm_tsfm_node_list_t;
|
|
|
|
/* hardware tsfm recognition global descriptor */
|
|
typedef struct _iot_brm_tsfm_global {
|
|
/* node list structure */
|
|
iot_brm_tsfm_node_list_t node_list;
|
|
/* the time when the station identification signal was received or address
|
|
* list update last, unit is 1s.
|
|
*/
|
|
uint32_t update_ts;
|
|
/* cco mac address, little-endian */
|
|
uint8_t cco_mac[IOT_MAC_ADDR_LEN];
|
|
/* is collecting stations hardware zone identification information */
|
|
uint8_t is_collecting;
|
|
} iot_brm_tsfm_global_t;
|
|
|
|
iot_brm_tsfm_global_t *p_brm_tsfm_glb = NULL;
|
|
|
|
static void iot_brm_tsfm_hash_table_clear_handler(
|
|
iot_addr_hash_entry_t *entry, void *param)
|
|
{
|
|
iot_addr_hash_table_remove(p_brm_tsfm_glb->node_list.node_table, entry);
|
|
iot_addr_hash_table_free(p_brm_tsfm_glb->node_list.node_table, entry);
|
|
}
|
|
|
|
static iot_brm_tsfm_info_desc_t *iot_brm_same_tsfm_find_min_snr(void)
|
|
{
|
|
iot_brm_tsfm_info_desc_t *node = NULL;
|
|
iot_brm_tsfm_node_list_t *node_list = &p_brm_tsfm_glb->node_list;
|
|
int8_t min_snr;
|
|
uint16_t i;
|
|
if (!node_list->node_cnt) {
|
|
goto out;
|
|
}
|
|
min_snr = IOT_BRM_MAX_SNR;
|
|
for (i = 0; i < node_list->node_cnt; i++) {
|
|
if (!node_list->entry[i]) {
|
|
continue;
|
|
}
|
|
if (node_list->entry[i]->snr < min_snr) {
|
|
node = node_list->entry[i];
|
|
min_snr = node_list->entry[i]->snr;
|
|
}
|
|
}
|
|
out:
|
|
return node;
|
|
}
|
|
|
|
static void iot_brm_same_tsfm_node_add(int8_t snr,
|
|
proto_conn_less_tsfm_info_rpt_t *rpt_h)
|
|
{
|
|
uint16_t i;
|
|
iot_brm_tsfm_node_list_t *node_list = &p_brm_tsfm_glb->node_list;
|
|
iot_brm_tsfm_info_desc_t *node;
|
|
uint8_t is_replace = 0;
|
|
uint8_t *addr;
|
|
node = (iot_brm_tsfm_info_desc_t *)iot_addr_hash_table_find(
|
|
node_list->node_table, rpt_h->sta_mac);
|
|
if (node) {
|
|
goto update;
|
|
}
|
|
node = (iot_brm_tsfm_info_desc_t *)iot_addr_hash_table_alloc(
|
|
node_list->node_table);
|
|
if (!node) {
|
|
node = iot_brm_same_tsfm_find_min_snr();
|
|
if (!node) {
|
|
IOT_ASSERT(0);
|
|
goto out;
|
|
}
|
|
iot_addr_hash_table_remove(p_brm_tsfm_glb->node_list.node_table,
|
|
&node->entry);
|
|
os_mem_set(node, 0, sizeof(*node));
|
|
is_replace = 1;
|
|
addr = node->entry.addr;
|
|
iot_brm_printf("%s - buffer full, replace %02x%02x%02x%02x%02x%02x\n",
|
|
__FUNCTION__, addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
|
|
}
|
|
iot_mac_addr_cpy(node->entry.addr, rpt_h->sta_mac);
|
|
iot_addr_hash_table_add(node_list->node_table, &node->entry);
|
|
node->snr = IOT_BRM_INVALID_SNR;
|
|
p_brm_tsfm_glb->update_ts = 0;
|
|
if (is_replace) {
|
|
goto update;
|
|
}
|
|
for (i = 0; i < IOT_BRM_TSFM_ADDR_LIST_MAX; i++) {
|
|
if (node_list->entry[i] == NULL) {
|
|
node_list->entry[i] = node;
|
|
break;
|
|
}
|
|
}
|
|
IOT_ASSERT(i < IOT_BRM_TSFM_ADDR_LIST_MAX);
|
|
node_list->node_cnt++;
|
|
|
|
update:
|
|
node->snr = iot_brm_calc_nw_snr(node->snr, snr);
|
|
node->pro_type = rpt_h->pro_type;
|
|
node->dev_type = rpt_h->dev_type;
|
|
node->phase_1 = rpt_h->phase_1;
|
|
node->phase_2 = rpt_h->phase_2;
|
|
node->phase_3 = rpt_h->phase_3;
|
|
|
|
iot_brm_printf("%s - sta_addr: %02x%02x%02x%02x%02x%02x, node count: %lu\n",
|
|
__FUNCTION__, rpt_h->sta_mac[5], rpt_h->sta_mac[4], rpt_h->sta_mac[3],
|
|
rpt_h->sta_mac[2], rpt_h->sta_mac[1], rpt_h->sta_mac[0],
|
|
node_list->node_cnt);
|
|
out:
|
|
return;
|
|
}
|
|
|
|
void iot_brm_same_tsfm_info_collect_handle(uint8_t *data, uint16_t len,
|
|
iot_pkt_t *pkt)
|
|
{
|
|
proto_conn_less_tsfm_info_rpt_t *rpt_h =
|
|
(proto_conn_less_tsfm_info_rpt_t *)data;
|
|
uint8_t *ptr = iot_pkt_data(pkt);
|
|
iot_plc_msdu_recv_t *msdu_h =
|
|
(iot_plc_msdu_recv_t *)(ptr - sizeof(*msdu_h));
|
|
uint8_t local_cco_addr[IOT_MAC_ADDR_LEN];
|
|
uint8_t reason;
|
|
if (p_brm_tsfm_glb == NULL) {
|
|
reason = 1;
|
|
goto drop;
|
|
}
|
|
if (len < sizeof(proto_conn_less_tsfm_info_rpt_t)) {
|
|
reason = 2;
|
|
goto drop;
|
|
}
|
|
if (p_brm_tsfm_glb->is_collecting == 0) {
|
|
reason = 3;
|
|
goto drop;
|
|
}
|
|
if (!iot_mac_addr_valid(iot_brm_get_cco_addr())) {
|
|
reason = 4;
|
|
goto drop;
|
|
}
|
|
|
|
iot_mac_addr_cpy(local_cco_addr, iot_brm_get_cco_addr());
|
|
iot_mac_addr_reverse(local_cco_addr);
|
|
/* Only save the sta with the same tsfm address as the local but different
|
|
* cco address.
|
|
*/
|
|
if (!iot_mac_addr_cmp(rpt_h->cco_mac, local_cco_addr) &&
|
|
iot_mac_addr_cmp(rpt_h->tsfm_mac, p_brm_tsfm_glb->cco_mac)) {
|
|
iot_brm_same_tsfm_node_add(msdu_h->snr, rpt_h);
|
|
}
|
|
goto out;
|
|
drop:
|
|
iot_brm_printf("%s drop reason %lu\n", __FUNCTION__, reason);
|
|
out:
|
|
if (pkt) {
|
|
iot_pkt_free(pkt);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void iot_brm_same_tsfm_collect_clear(void)
|
|
{
|
|
if (p_brm_tsfm_glb == NULL) {
|
|
IOT_ASSERT(0);
|
|
}
|
|
iot_addr_hash_table_loop(p_brm_tsfm_glb->node_list.node_table,
|
|
iot_brm_tsfm_hash_table_clear_handler, NULL);
|
|
p_brm_tsfm_glb->node_list.node_cnt = 0;
|
|
os_mem_set(p_brm_tsfm_glb->node_list.entry, 0x0,
|
|
sizeof(p_brm_tsfm_glb->node_list.entry));
|
|
}
|
|
|
|
uint32_t iot_brm_same_tsfm_collect_trigger(uint8_t * cco_addr)
|
|
{
|
|
uint32_t ret;
|
|
if (p_brm_tsfm_glb == NULL) {
|
|
ret = ERR_NOMEM;
|
|
goto out;
|
|
}
|
|
if (p_brm_tsfm_glb->is_collecting) {
|
|
if (!iot_mac_addr_cmp(cco_addr, p_brm_tsfm_glb->cco_mac)) {
|
|
/* receive new hardware tsfm info (the address is different from the
|
|
* last receive), restart collection.
|
|
*/
|
|
iot_mac_addr_cpy(p_brm_tsfm_glb->cco_mac, cco_addr);
|
|
iot_brm_same_tsfm_collect_clear();
|
|
}
|
|
} else {
|
|
iot_mac_addr_cpy(p_brm_tsfm_glb->cco_mac, cco_addr);
|
|
iot_brm_same_tsfm_collect_clear();
|
|
p_brm_tsfm_glb->is_collecting = 1;
|
|
}
|
|
p_brm_tsfm_glb->update_ts = 0;
|
|
iot_brm_printf("%s - cco_addr: %2x %2x %2x %2x %2x %2x\n", __FUNCTION__,
|
|
cco_addr[5], cco_addr[4], cco_addr[3], cco_addr[2], cco_addr[1],
|
|
cco_addr[0]);
|
|
ret = ERR_OK;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
void iot_brm_same_tsfm_collect_timeout(void)
|
|
{
|
|
if (p_brm_tsfm_glb == NULL) {
|
|
return;
|
|
}
|
|
if (p_brm_tsfm_glb->is_collecting == 1) {
|
|
p_brm_tsfm_glb->update_ts++;
|
|
if (p_brm_tsfm_glb->update_ts > IOT_BRM_TSFM_COLLECT_TIMEOUT) {
|
|
p_brm_tsfm_glb->update_ts = 0;
|
|
p_brm_tsfm_glb->is_collecting = 0;
|
|
iot_brm_printf("%s timeout\n", __FUNCTION__);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t iot_brm_same_tsfm_fill_node_info(
|
|
iot_sg_ext_cus_same_tsfm_node_resp_t *resp)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
uint16_t index;
|
|
iot_brm_tsfm_info_desc_t **node_list;
|
|
uint16_t i;
|
|
uint16_t node_count;
|
|
uint8_t list_sn;
|
|
if (resp == NULL || p_brm_tsfm_glb == NULL) {
|
|
IOT_ASSERT(0);
|
|
ret = ERR_FAIL;
|
|
goto out;
|
|
}
|
|
node_list = p_brm_tsfm_glb->node_list.entry;
|
|
list_sn = resp->req_info.list_sn;
|
|
resp->follow_flag = 0;
|
|
resp->node_cnt = 0;
|
|
if (p_brm_tsfm_glb->is_collecting == 0) {
|
|
resp->done = 1;
|
|
} else {
|
|
resp->done = 0;
|
|
}
|
|
if (list_sn == 0) {
|
|
goto out;
|
|
}
|
|
index = (list_sn - 1) * IOT_BRM_TSFM_FRAME_ENTRY_MAX;
|
|
if (index >= p_brm_tsfm_glb->node_list.node_cnt) {
|
|
goto out;
|
|
}
|
|
node_count = p_brm_tsfm_glb->node_list.node_cnt - index;
|
|
if (node_count > IOT_BRM_TSFM_FRAME_ENTRY_MAX) {
|
|
node_count = IOT_BRM_TSFM_FRAME_ENTRY_MAX;
|
|
resp->follow_flag = 1;
|
|
}
|
|
resp->node_cnt = node_count;
|
|
for (i = 0; i < node_count; i++) {
|
|
iot_mac_addr_cpy(resp->node_list[i].addr, node_list[index]->entry.addr);
|
|
resp->node_list[i].dev_type = node_list[index]->dev_type;
|
|
resp->node_list[i].pro_type = node_list[index]->pro_type;
|
|
index++;
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_brm_tsfm_init(void)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
p_brm_tsfm_glb = os_mem_malloc(IOT_BRM_MID, sizeof(*p_brm_tsfm_glb));
|
|
if (p_brm_tsfm_glb == NULL) {
|
|
ret = ERR_NOMEM;
|
|
goto out;
|
|
}
|
|
p_brm_tsfm_glb->node_list.node_table = iot_addr_hash_table_create(
|
|
IOT_BRM_MID, IOT_BRM_TSFM_ADDR_LIST_MAX,
|
|
sizeof(iot_brm_tsfm_info_desc_t), IOT_BRM_TSFM_HASH_TABLE_SIZE);
|
|
if (p_brm_tsfm_glb->node_list.node_table == NULL) {
|
|
ret = ERR_NOMEM;
|
|
goto out_list_fail;
|
|
}
|
|
p_brm_tsfm_glb->update_ts = 0;
|
|
p_brm_tsfm_glb->is_collecting = 0;
|
|
os_mem_set(p_brm_tsfm_glb->cco_mac, 0xFF, IOT_MAC_ADDR_LEN);
|
|
p_brm_tsfm_glb->node_list.node_cnt = 0;
|
|
os_mem_set(p_brm_tsfm_glb->node_list.entry, 0x0,
|
|
sizeof(p_brm_tsfm_glb->node_list.entry));
|
|
goto out;
|
|
out_list_fail:
|
|
iot_brm_tsfm_deinit();
|
|
out:
|
|
iot_brm_printf("%s - ret: %d\n", __FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
void iot_brm_tsfm_deinit(void)
|
|
{
|
|
if (p_brm_tsfm_glb == NULL) {
|
|
goto out;
|
|
}
|
|
if (p_brm_tsfm_glb->node_list.node_table != NULL) {
|
|
iot_addr_hash_table_delete(p_brm_tsfm_glb->node_list.node_table);
|
|
}
|
|
os_mem_free(p_brm_tsfm_glb);
|
|
p_brm_tsfm_glb = NULL;
|
|
out:
|
|
iot_brm_printf("%s\n", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
#endif /* IOT_BRM_ENABLE */
|