Files
kunlun/plc/halmac/ppm_scan/mac_rf_scan.c
2024-09-28 14:24:04 +08:00

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
}