492 lines
14 KiB
C
492 lines
14 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.
|
|
|
|
****************************************************************************/
|
|
|
|
#include "mac_rf_scan.h"
|
|
#include "iot_errno.h"
|
|
#include "plc_const.h"
|
|
#include "plc_rf_scan_tbl.h"
|
|
#include "mac_rf_pdev.h"
|
|
#include "iot_dbglog_api.h"
|
|
#include "iot_dbglog_parser.h"
|
|
#include "mac_sched_hw.h"
|
|
#include "iot_io.h"
|
|
#include "hw_phy_init.h"
|
|
#include "plc_protocol.h"
|
|
/* for PPM_NTB_CAL */
|
|
#include "portmacro.h"
|
|
#include "mac_rf.h"
|
|
#include "mac_msg.h"
|
|
#include "mac.h"
|
|
#include "phy_rf_chn.h"
|
|
#include "phy_nf.h"
|
|
#include "mac_cert_test.h"
|
|
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
|
|
#include "mac_rf_common_hw.h"
|
|
|
|
void mac_rf_scan_op_chn_tbl_init()
|
|
{
|
|
uint32_t tbl_len;
|
|
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
|
|
IOT_ASSERT(rf_pdev);
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
IOT_ASSERT(scan);
|
|
mac_rf_scan_op_chn_ctxt_t *rf_chn = &scan->rf_scan_op_chn_ctxt;
|
|
IOT_ASSERT(rf_chn);
|
|
uint8_t rf_channel_cnt;
|
|
const mac_rf_scan_op_chn_t *rf_scan_tbl;
|
|
|
|
if (rf_chn->rf_scan_op_chn_tbl) {
|
|
return;
|
|
}
|
|
|
|
/* check size */
|
|
BUILD_BUG_ON((RF_SCAN_TBL_NSG_CNT + RF_SCAN_TBL_NSG_EXT_CNT) <=
|
|
MAC_RF_SCAN_OP_CHN_MAX);
|
|
BUILD_BUG_ON((RF_SCAN_TBL_OVERSEAS_CNT + RF_SCAN_TBL_OVERSEAS_EXT_CNT) <=
|
|
MAC_RF_SCAN_OP_CHN_MAX);
|
|
|
|
tbl_len = MAC_RF_SCAN_OP_CHN_MAX * sizeof(mac_rf_scan_op_chn_t);
|
|
|
|
/* scan option channel tabled init */
|
|
rf_chn->rf_scan_op_chn_tbl = os_mem_malloc(PLC_MAC_COMMON_MID, tbl_len);
|
|
IOT_ASSERT(rf_chn->rf_scan_op_chn_tbl);
|
|
|
|
rf_channel_cnt = plc_get_rf_recommend_tbl(&rf_scan_tbl);
|
|
mac_rf_scan_set_scan_tbl(rf_channel_cnt, (uint8_t *)rf_scan_tbl);
|
|
}
|
|
|
|
void mac_rf_scan_set_scan_tbl(uint8_t tbl_size, uint8_t *rf_scan_tbl)
|
|
{
|
|
IOT_ASSERT(tbl_size && rf_scan_tbl);
|
|
uint32_t tbl_len, i, channel_max;
|
|
mac_rf_scan_op_chn_t *op_chn_p = NULL;
|
|
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
|
|
IOT_ASSERT(rf_pdev);
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
IOT_ASSERT(scan);
|
|
if (!RF_SUPPORT_OPTION_CHANNEL_SCAN) {
|
|
return;
|
|
}
|
|
mac_rf_scan_op_chn_ctxt_t *rf_chn = &scan->rf_scan_op_chn_ctxt;
|
|
IOT_ASSERT(rf_chn->rf_scan_op_chn_tbl);
|
|
|
|
/* calculate hole table len */
|
|
tbl_len = MAC_RF_SCAN_OP_CHN_MAX * sizeof(mac_rf_scan_op_chn_t);
|
|
/* clear table */
|
|
os_mem_set((uint8_t *)rf_chn->rf_scan_op_chn_tbl, 0, tbl_len);
|
|
/* calculate len */
|
|
IOT_ASSERT(tbl_size <= MAC_RF_SCAN_OP_CHN_MAX);
|
|
|
|
/* judge scan table is vaild or not */
|
|
for (i = 0; i < tbl_size; i++) {
|
|
op_chn_p = (mac_rf_scan_op_chn_t *)(rf_scan_tbl +
|
|
(i * sizeof(mac_rf_scan_op_chn_t)));
|
|
iot_printf("rf_scan_tbl op:%d, chn:%d, min:%d, max:%d\n",
|
|
op_chn_p->option_id, op_chn_p->channel_id,
|
|
op_chn_p->min_time, op_chn_p->dwell_time);
|
|
if (op_chn_p->option_id < PHY_RF_OPTION1_1M &&
|
|
op_chn_p->option_id >= PHY_RF_OPTION_MAX) {
|
|
IOT_ASSERT(0);
|
|
}
|
|
channel_max = phy_rf_get_channel_id_max(op_chn_p->option_id);
|
|
if (op_chn_p->channel_id <= RF_CHANNEL_ID_INVALID &&
|
|
op_chn_p->channel_id >= channel_max) {
|
|
IOT_ASSERT(0);
|
|
}
|
|
IOT_ASSERT(op_chn_p->min_time &&
|
|
op_chn_p->dwell_time >= op_chn_p->min_time);
|
|
}
|
|
|
|
tbl_len = tbl_size * sizeof(mac_rf_scan_op_chn_t);
|
|
/* set rf scan table */
|
|
os_mem_cpy((uint8_t *)rf_chn->rf_scan_op_chn_tbl, rf_scan_tbl, tbl_len);
|
|
|
|
scan->scan_idx = tbl_size - 1;
|
|
scan->scan_cnt = tbl_size;
|
|
}
|
|
|
|
void mac_rf_scan_set_channel_selected(uint32_t is_sel)
|
|
{
|
|
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
|
|
if (!rf_pdev) {
|
|
iot_printf("%s rfpdev is NULL\n", __FUNCTION__);
|
|
return;
|
|
}
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
IOT_ASSERT(scan);
|
|
|
|
scan->channel_selected = !!is_sel;
|
|
}
|
|
|
|
uint32_t mac_rf_scan_get_channel_selected()
|
|
{
|
|
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
|
|
IOT_ASSERT(rf_pdev);
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
IOT_ASSERT(scan);
|
|
|
|
return scan->channel_selected;
|
|
}
|
|
|
|
uint32_t mac_rf_scan_start()
|
|
{
|
|
mac_rf_scan_op_chn_t *op_chn_p = NULL;
|
|
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
|
|
IOT_ASSERT(rf_pdev);
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
|
|
if (!RF_SUPPORT_OPTION_CHANNEL_SCAN) {
|
|
return ERR_INVAL;
|
|
}
|
|
if (!scan) {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
if (!scan->rf_scan_timer) {
|
|
return ERR_INVAL;
|
|
}
|
|
IOT_ASSERT(scan->rf_scan_op_chn_ctxt.rf_scan_op_chn_tbl &&
|
|
(scan->scan_idx < scan->scan_cnt));
|
|
|
|
/* get current scan option/channel */
|
|
op_chn_p = scan->rf_scan_op_chn_ctxt.rf_scan_op_chn_tbl + scan->scan_idx;
|
|
IOT_ASSERT(op_chn_p->min_time &&
|
|
op_chn_p->dwell_time >= op_chn_p->min_time);
|
|
|
|
/* fix gw cert test bed sta leave network over 15 level case,
|
|
* sta missed rx valid beacon due to rf scan switch to other channel.
|
|
* cert mode, disable rf scan
|
|
*/
|
|
if (scan->rf_scan_timer && !mac_rf_scan_get_channel_selected() &&
|
|
!mac_get_cert_test_flag()) {
|
|
/* start the scan timer if band is not selected */
|
|
os_start_timer(scan->rf_scan_timer,
|
|
op_chn_p->dwell_time * MAC_RF_SCAN_TIMER_UNIT);
|
|
/* record rf timer start ms */
|
|
scan->timer_start_ms = os_boot_time32();
|
|
/* record phr ok cnt */
|
|
phy_rx_cnt_t *phy_rx_info = &g_phy_ctxt.dep.phy_status.phy_rx_cnt;
|
|
scan->phr_with_pld_cnt = phy_rx_info->phy_rf_rx_phr_ok_with_pld_cnt;
|
|
scan->phr_witchout_pld_cnt =
|
|
phy_rx_info->phy_rf_rx_phr_ok_without_pld_cnt;
|
|
scan->is_valid_packet = 0;
|
|
} else {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t mac_rf_scan_stop()
|
|
{
|
|
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
|
|
if (!rf_pdev) {
|
|
iot_printf("%s rfpdev is NULL\n", __FUNCTION__);
|
|
return ERR_INVAL;
|
|
}
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
|
|
if (!scan) {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
if (scan->rf_scan_timer) {
|
|
/* stop the scan timer */
|
|
os_stop_timer(scan->rf_scan_timer);
|
|
/* clear pending timer */
|
|
mac_clean_msg(MAC_MSG_TYPE_TIMER, MAC_MSG_ID_RF_SCAN_TIMER);
|
|
} else {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static uint32_t mac_rf_scan_restart()
|
|
{
|
|
uint32_t ret;
|
|
mac_rf_scan_stop();
|
|
ret = mac_rf_scan_start();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static mac_rf_scan_op_chn_t *mac_rf_scan_next_op_chn_to_switch()
|
|
{
|
|
mac_rf_scan_op_chn_t *scan_op_chn = NULL;
|
|
|
|
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
|
|
IOT_ASSERT(rf_pdev);
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
IOT_ASSERT(scan);
|
|
mac_rf_scan_op_chn_ctxt_t *rf_chn = &scan->rf_scan_op_chn_ctxt;
|
|
IOT_ASSERT(rf_chn->rf_scan_op_chn_tbl);
|
|
|
|
/* set scan idx */
|
|
if (++scan->scan_idx >= scan->scan_cnt) {
|
|
scan->scan_idx = 0;
|
|
}
|
|
|
|
scan_op_chn = (mac_rf_scan_op_chn_t *)(rf_chn->rf_scan_op_chn_tbl +
|
|
scan->scan_idx);
|
|
|
|
IOT_ASSERT(scan->scan_idx < MAC_RF_SCAN_OP_CHN_MAX && scan_op_chn != NULL);
|
|
|
|
return scan_op_chn;
|
|
}
|
|
|
|
uint32_t mac_rf_scan_next_target(void *arg)
|
|
{
|
|
mac_rf_pdev_t *rf_pdev = (mac_rf_pdev_t*) arg;
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
mac_rf_scan_op_chn_t *scan_op_chn = NULL;
|
|
uint32_t proto = PHY_PROTO_TYPE_GET();
|
|
|
|
if (!RF_SUPPORT_OPTION_CHANNEL_SCAN) {
|
|
return ERR_FAIL;
|
|
}
|
|
/* fix gw cert test bed sta leave network over 15 level case,
|
|
* sta missed rx valid beacon due to rf scan switch to other channel.
|
|
* cert mode, disable rf scan
|
|
*/
|
|
if (mac_rf_scan_get_channel_selected() || mac_get_cert_test_flag()) {
|
|
/* if channel selected, then stop the timer and quit */
|
|
mac_rf_scan_stop();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
scan_op_chn = mac_rf_scan_next_op_chn_to_switch();
|
|
scan->option_id = scan_op_chn->option_id;
|
|
scan->channel_id = scan_op_chn->channel_id;
|
|
|
|
iot_printf("switch to proto %d - %d, option %d, channel:%d, dwell:%d ms\n",
|
|
proto, SUPPORT_IEEE_1901, scan_op_chn->option_id,
|
|
scan_op_chn->channel_id, scan_op_chn->dwell_time * MAC_RF_SCAN_TIMER_UNIT);
|
|
|
|
/* start to switch option/channel */
|
|
mac_rf_set_self_option_channel((uint8_t)scan->option_id,
|
|
(uint8_t)scan->channel_id);
|
|
|
|
if (!mac_get_cert_test_flag()) {
|
|
mac_rf_ppm_init(rf_pdev->rf_vdev[PLC_DEFAULT_VDEV],
|
|
phy_get_cal_ppm_in_pib() << PLC_NTB_PPM_SHIFT);
|
|
}
|
|
|
|
mac_rf_scan_restart();
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
void mac_rf_scan_timer_handler(timer_id_t timer_id, void * arg)
|
|
{
|
|
(void) timer_id;
|
|
mac_rf_pdev_t *rf_pdev = (mac_rf_pdev_t*) arg;
|
|
|
|
/* timer context */
|
|
mac_msg_t *msg = mac_alloc_msg();
|
|
|
|
if (msg == NULL) {
|
|
IOT_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
msg->type = MAC_MSG_TYPE_TIMER;
|
|
msg->id = MAC_MSG_ID_RF_SCAN_TIMER;
|
|
msg->data1 = 0;
|
|
msg->data2 = rf_pdev;
|
|
mac_queue_msg(msg, MAC_MSG_QUEUE_MP);
|
|
return;
|
|
}
|
|
|
|
void mac_rf_scan_judge_restart()
|
|
{
|
|
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
|
|
mac_rf_vdev_t *rf_vdev = get_rf_vdev_ptr(PLC_PDEV_ID, rf_pdev->rf_pdev_id,
|
|
PLC_DEFAULT_VDEV);
|
|
IOT_ASSERT(rf_pdev);
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
IOT_ASSERT(scan);
|
|
uint32_t span_ms;
|
|
|
|
phy_rx_cnt_t *phy_rx_info = &g_phy_ctxt.dep.phy_status.phy_rx_cnt;
|
|
/* whether a valid packet was received during this time */
|
|
if (scan->is_valid_packet &&
|
|
(phy_rx_info->phy_rf_rx_phr_ok_with_pld_cnt != scan->phr_with_pld_cnt ||
|
|
phy_rx_info->phy_rf_rx_phr_ok_without_pld_cnt !=
|
|
scan->phr_witchout_pld_cnt)) {
|
|
return;
|
|
}
|
|
|
|
if (rf_vdev->stop_flag == 0 && !mac_get_cert_test_flag() &&
|
|
!mac_rf_scan_get_channel_selected()) {
|
|
mac_rf_scan_op_chn_ctxt_t *rf_chn = &scan->rf_scan_op_chn_ctxt;
|
|
mac_rf_scan_op_chn_t *op_chn_p = (mac_rf_scan_op_chn_t *)(
|
|
rf_chn->rf_scan_op_chn_tbl + scan->scan_idx);
|
|
uint32_t min_ms = (uint32_t)op_chn_p->min_time *
|
|
MAC_RF_SCAN_TIMER_UNIT;
|
|
span_ms = os_boot_time32() - scan->timer_start_ms;
|
|
if (span_ms >= min_ms) {
|
|
mac_rf_scan_next_target(rf_pdev);
|
|
}
|
|
}
|
|
}
|
|
|
|
void mac_rf_scan_init(void *pdev_in)
|
|
{
|
|
uint8_t option, channel;
|
|
mac_rf_pdev_t *rf_pdev = pdev_in;
|
|
mac_rf_scan_ctxt_t *scan = &rf_pdev->rf_scan;
|
|
phy_rf_get_default_cfg(&option, &channel);
|
|
|
|
scan->option_id = option;
|
|
scan->channel_id = RF_OPTION_INVALID;
|
|
scan->channel_selected = 0;
|
|
scan->scan_idx = 0;
|
|
scan->is_valid_packet = 0;
|
|
|
|
#if RF_SUPPORT_OPTION_CHANNEL_SCAN
|
|
/* only sta need to sync option channel */
|
|
if (scan->rf_scan_timer == 0) {
|
|
/* scan option channel table init */
|
|
mac_rf_scan_op_chn_tbl_init();
|
|
/* create timer */
|
|
scan->rf_scan_timer = os_create_timer(PLC_MAC_SCAN_MID, false,
|
|
mac_rf_scan_timer_handler, rf_pdev);
|
|
register_phy_call_mac_rf_scan_cb(mac_rf_scan_judge_restart);
|
|
}
|
|
#else
|
|
scan->rf_scan_timer = 0;
|
|
#endif
|
|
}
|
|
|
|
void mac_rf_scan_update_rx_status(void *vdev_in, mac_rf_scan_ctxt_t *scan,
|
|
uint32_t nid, uint8_t rx_channel)
|
|
{
|
|
if (scan->is_valid_packet) {
|
|
return;
|
|
}
|
|
if (rx_channel != mac_rf_get_self_channel()) {
|
|
return;
|
|
}
|
|
if ((nid != PLC_NID_INVALID) &&
|
|
vdev_is_bl_nid((mac_vdev_t *)vdev_in, nid)) {
|
|
return;
|
|
}
|
|
|
|
scan->is_valid_packet = 1;
|
|
}
|
|
|
|
#else /* HPLC_RF_DEV_SUPPORT */
|
|
|
|
void mac_rf_scan_set_scan_tbl(uint8_t tbl_size, uint8_t *rf_scan_tbl)
|
|
{
|
|
(void)tbl_size;
|
|
(void)rf_scan_tbl;
|
|
}
|
|
|
|
uint32_t mac_rf_scan_start()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
uint32_t mac_rf_scan_stop()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void mac_rf_scan_set_channel_selected(uint32_t is_sel)
|
|
{
|
|
(void)is_sel;
|
|
}
|
|
|
|
uint32_t mac_rf_scan_get_channel_selected()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
uint32_t mac_rf_scan_next_target(void *arg)
|
|
{
|
|
(void)arg;
|
|
return 0;
|
|
}
|
|
|
|
void mac_rf_scan_init(void *pdev_in)
|
|
{
|
|
(void)pdev_in;
|
|
}
|
|
|
|
void mac_rf_scan_update_rx_status(void *vdev_in, mac_rf_scan_ctxt_t *scan,
|
|
uint32_t nid, uint8_t rx_channel)
|
|
{
|
|
(void)vdev_in;
|
|
(void)scan;
|
|
(void)nid;
|
|
(void)rx_channel;
|
|
}
|
|
|
|
#endif
|
|
|
|
uint32_t mac_rf_ntb_ppm_sync(void *rf_vdev,
|
|
uint32_t remote_ts, uint32_t local_ts, uint32_t local_ntb,
|
|
uint32_t bcn_period_ms, int16_t *ppm_err_record, int16_t rfppm)
|
|
{
|
|
mac_rf_vdev_t *vdev = (mac_rf_vdev_t *)rf_vdev;
|
|
int16_t ppm_err = mac_ppm_cal(&vdev->mac_rf_ppm, remote_ts,
|
|
local_ts, local_ntb, bcn_period_ms);
|
|
|
|
if (ppm_err > -PLC_MAX_MAC_NTB_PPM && ppm_err < PLC_MAX_MAC_NTB_PPM) {
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
int16_t avg_ppm;
|
|
int64_t delta;
|
|
mac_vdev_t *plc_vdev;
|
|
int16_t set_ppm = mac_rf_get_wphy_ppm() + rfppm;
|
|
/* rf ppm from wphy interface */
|
|
mac_rf_set_wphy_ppm(set_ppm);
|
|
|
|
avg_ppm = vdev->rf_ntb_ppm;
|
|
vdev->rf_ntb_ppm = (avg_ppm - (avg_ppm >> 3)) + (-ppm_err >> 3);
|
|
|
|
plc_vdev = get_vdev_ptr(vdev->ref_pdev_id, vdev->parent_vdev_id);
|
|
delta = MAC_NTB_TO_MS((int64_t)(mac_sched_get_ntb64(NULL)
|
|
- plc_vdev->mac_ppm.ntb_record.last_saved_ntb));
|
|
if (delta > (int64_t)(vdev_get_bc_period_ms(plc_vdev,
|
|
PHY_PROTO_TYPE_GET()) * 2)) {
|
|
mac_scan_set_ntb_ppm(&plc_vdev->mac_ppm, vdev->rf_ntb_ppm, 0);
|
|
vdev->ntb_ppm_update_cnt++;
|
|
}
|
|
#endif
|
|
if (ppm_err_record) {
|
|
*ppm_err_record = ppm_err;
|
|
}
|
|
}
|
|
(void)rfppm;
|
|
return ERR_OK;
|
|
}
|
|
|
|
void mac_rf_ppm_init(void *rf_vdev, int16_t ppm)
|
|
{
|
|
mac_rf_vdev_t *vdev = (mac_rf_vdev_t *)rf_vdev;
|
|
|
|
mac_ppm_reset_counter(&vdev->mac_rf_ppm);
|
|
vdev->rf_ntb_ppm = ppm;
|
|
vdev->ntb_ppm_update_cnt = 0;
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
mac_rf_set_wphy_ppm(-ppm);
|
|
#endif
|
|
}
|