993 lines
29 KiB
C
Executable File
993 lines
29 KiB
C
Executable File
/****************************************************************************
|
|
|
|
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_ppm_scan.h"
|
|
#include "iot_errno.h"
|
|
#include "plc_const.h"
|
|
#include "mac_cmn_hw.h"
|
|
#include "mac_pdev.h"
|
|
#include "phy_chn.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 "mac_init_api.h"
|
|
#include "plc_protocol.h"
|
|
#include "hw_war.h"
|
|
/* for PPM_NTB_CAL */
|
|
#include "portmacro.h"
|
|
/* for DEBUG_SYSTICK */
|
|
#include "iot_gpio_api.h"
|
|
#include "mac_check_spur_sta.h"
|
|
#include "gp_timer.h"
|
|
#include "mac_cert_test.h"
|
|
#include "phy_nf.h"
|
|
#include "iot_bitmap_api.h"
|
|
#include "mac_peer.h"
|
|
#include "iot_oem_api.h"
|
|
|
|
#define DEBUG_SYSTICK 0
|
|
#define MAC_PPM_RECORD_DEBUG 0
|
|
|
|
#if MAC_PPM_MULTI_NODE_ENABLE
|
|
|
|
static void mac_ppm_record_timer_handler(mac_ppm_ctxt_t *ppm_ctxt);
|
|
|
|
#else
|
|
|
|
#define mac_ppm_record_timer_handler(ppm_ctxt); \
|
|
do { \
|
|
(void)ppm_ctxt; \
|
|
} while(0)
|
|
|
|
#endif
|
|
|
|
/*
|
|
* @brief restart mac scan process
|
|
* @param scan: pointer to phy scan context
|
|
* @retval: ERR_OK - success, otherwise - failure
|
|
*/
|
|
static uint32_t mac_scan_restart(mac_scan_ctxt_t *scan)
|
|
{
|
|
if (!scan) {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
/* start scan diable check spur */
|
|
mac_pdev_t *pdev_t = get_pdev_ptr(PLC_PDEV_ID);
|
|
mac_check_spur_en(&pdev_t->mac_check_spur_ctxt, false);
|
|
|
|
if (!mac_scan_get_band_selected(scan)) {
|
|
scan->is_started = 1;
|
|
if (scan->is_first_scan_done || (0 == scan->start_ts)) {
|
|
scan->start_ts = os_boot_time32();
|
|
if (0 == scan->start_ts) {
|
|
scan->start_ts++;
|
|
}
|
|
}
|
|
scan->is_rx_packet = 0;
|
|
g_phy_cpu_share_ctxt.pm_status.band_select_ok = 0;
|
|
return ERR_OK;
|
|
}
|
|
return ERR_NOSUPP;
|
|
}
|
|
|
|
static uint32_t mac_scan_next_target(mac_pdev_t *pdev)
|
|
{
|
|
uint8_t band_id, mask_id;
|
|
mac_scan_ctxt_t *scan = &pdev->scan;
|
|
|
|
scan->is_first_scan_done = 1;
|
|
if (++scan->scan_idx >= scan->scan_count) {
|
|
scan->scan_idx = 0;
|
|
}
|
|
|
|
band_id = scan->scan_info[scan->scan_idx].band_id;
|
|
mask_id = phy_band_to_tonemask_id_get(band_id);
|
|
|
|
uint32_t proto = PHY_PROTO_TYPE_GET();
|
|
iot_printf("switch to band %d, proto %d-%d, mask id %d,...\n",
|
|
band_id, proto, SUPPORT_IEEE_1901, mask_id);
|
|
|
|
/* if protocol/bandid/maskid are not changed, do not have to switch band */
|
|
if (proto != phy_proto_type_get() || band_id != phy_band_id_get() ||
|
|
mask_id != phy_mask_id_get()) {
|
|
|
|
phy_band_id_to_set(band_id);
|
|
/* keep proto and mask un changed currently */
|
|
phy_proto_type_to_set(proto);
|
|
phy_mask_id_to_set(mask_id);
|
|
|
|
/* start to switch band */
|
|
mac_new_phy_cfg_apply();
|
|
|
|
mac_vdev_war_rx_abort_init();
|
|
}
|
|
|
|
if (!mac_get_cert_test_flag()) {
|
|
mac_ppm_init(&pdev->vdev[PLC_DEFAULT_VDEV]->mac_ppm,
|
|
phy_get_cal_ppm_in_pib(), IOT_SUPPORT_RATE_SR);
|
|
}
|
|
|
|
/* clear mac status cnt */
|
|
mac_status_cnt_clr();
|
|
|
|
mac_scan_restart(scan);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
void mac_scan_band_check_timeout(void)
|
|
{
|
|
uint32_t min_time, dwell_time, delta_time;
|
|
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
|
|
mac_vdev_t *vdev = get_vdev_ptr(PLC_PDEV_ID, PLC_DEFAULT_VDEV);
|
|
mac_scan_ctxt_t *scan = &pdev->scan;
|
|
|
|
mac_ppm_record_timer_handler(&vdev->mac_ppm);
|
|
if (vdev->stop_flag || (0 == scan->is_started) || mac_get_cert_test_flag()
|
|
|| mac_scan_get_band_selected(scan)) {
|
|
return;
|
|
}
|
|
|
|
if (scan->is_first_scan_done) {
|
|
min_time = scan->scan_info[scan->scan_idx].min_time;
|
|
dwell_time = scan->scan_info[scan->scan_idx].dwell_time;
|
|
} else {
|
|
#if CPLC_IOT_CERT_ENABLE
|
|
/* for cert test, we should not miss
|
|
* any test cmd or beacon before
|
|
* switch band, and the test seems
|
|
* not very critical for the assoc time
|
|
* so let's set this to a larger value
|
|
*/
|
|
min_time = PLC_SCAN_CERT_DWELL_TIME_S;
|
|
dwell_time = PLC_SCAN_CERT_DWELL_TIME_S;
|
|
#else
|
|
uint8_t user_type = iot_oem_get_user_type();
|
|
if ((USER_TYPE_SOUTHEN_POWER_GRID_GX_NW21 == user_type)
|
|
|| (USER_TYPE_SOUTHEN_POWER_GRID_GUIZHOU == user_type)) {
|
|
min_time = MAC_SCAN_FIRST_DWELL_SPG_GX_S;
|
|
dwell_time = MAC_SCAN_FIRST_DWELL_SPG_GX_S;
|
|
} else {
|
|
min_time = PLC_SCAN_FIRST_DWELL_TIME_S;
|
|
dwell_time = PLC_SCAN_MAX_DWELL_TIME_S;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
IOT_ASSERT(min_time <= dwell_time);
|
|
delta_time = os_boot_time32() - scan->start_ts;
|
|
|
|
if (!scan->is_rx_packet && (delta_time
|
|
>= (min_time * PHY_SNR_CAL_TIMER_PERIOD))) {
|
|
vdev_reset_ppm_sync(vdev);
|
|
mac_scan_next_target(pdev);
|
|
} else if (delta_time >= (dwell_time * PHY_SNR_CAL_TIMER_PERIOD)) {
|
|
vdev_reset_ppm_sync(vdev);
|
|
mac_scan_next_target(pdev);
|
|
}
|
|
}
|
|
|
|
uint32_t mac_scan_get_support_band_tbl(uint32_t proto, uint32_t size,
|
|
plc_scan_band_t *band_info)
|
|
{
|
|
uint8_t idx, band_cnt;
|
|
plc_phy_band_table_t *src_tbl;
|
|
|
|
band_cnt = 0;
|
|
src_tbl = NULL;
|
|
if (!band_info || (0 == size)) {
|
|
return band_cnt;
|
|
}
|
|
|
|
band_cnt = (uint8_t)phy_support_band_table_get(proto, (void **)&src_tbl);
|
|
if (size < band_cnt) {
|
|
iot_printf("%s. get size %d small %d\n", __FUNCTION__, size, band_cnt);
|
|
}
|
|
|
|
band_cnt = (uint8_t)min(size, band_cnt);
|
|
for (idx = 0; idx < band_cnt; idx++) {
|
|
band_info[idx].band_id = src_tbl[idx].band_id;
|
|
band_info[idx].min_time = PLC_SCAN_MIN_DWELL_TIME_S;
|
|
band_info[idx].dwell_time = PLC_SCAN_MAX_DWELL_TIME_S;
|
|
}
|
|
|
|
return band_cnt;
|
|
}
|
|
|
|
uint32_t mac_scan_set_band_info(uint32_t proto, uint32_t size,
|
|
plc_scan_band_t *band_info)
|
|
{
|
|
uint8_t i, j, idx;
|
|
uint32_t support_cnt, save_max_cnt;
|
|
iot_pkt_t *support_pkt;
|
|
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
|
|
mac_scan_ctxt_t *scan;
|
|
plc_scan_band_t *support_band, *save_band;
|
|
|
|
scan = &pdev->scan;
|
|
save_band = scan->scan_info;
|
|
save_max_cnt = IOT_ARRAY_CNT(scan->scan_info);
|
|
|
|
if ((0 == size) || !band_info) {
|
|
iot_printf("scan_band set para error\n");
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
if ((size == scan->scan_count) && (!os_mem_cmp(save_band,
|
|
band_info, sizeof(plc_scan_band_t) * size))) {
|
|
iot_printf("scan_band set same info %d\n", size);
|
|
goto switch_band;
|
|
}
|
|
|
|
support_pkt = iot_pkt_alloc(sizeof(plc_scan_band_t)
|
|
* PLC_SCAN_BAND_MAX_CNT, PLC_MAC_COMMON_MID);
|
|
IOT_ASSERT(support_pkt);
|
|
support_band = (plc_scan_band_t *)iot_pkt_data(support_pkt);
|
|
support_cnt = mac_scan_get_support_band_tbl(proto, PLC_SCAN_BAND_MAX_CNT,
|
|
support_band);
|
|
|
|
idx = 0;
|
|
for (i = 0; (i < size) && (idx < save_max_cnt); i++) {
|
|
for (j = 0; j < support_cnt; j++) {
|
|
if (support_band[j].band_id == band_info[i].band_id) {
|
|
save_band[idx].band_id = band_info[i].band_id;
|
|
if (band_info[i].min_time && (band_info[i].min_time
|
|
<= band_info[i].dwell_time)) {
|
|
save_band[idx].min_time = band_info[i].min_time;
|
|
save_band[idx].dwell_time = band_info[i].dwell_time;
|
|
} else {
|
|
iot_printf("band % min:%d, dwell:%d invalid\n",
|
|
band_info[i].band_id, band_info[i].min_time,
|
|
band_info[i].dwell_time);
|
|
save_band[idx].min_time = PLC_SCAN_MIN_DWELL_TIME_S;
|
|
save_band[idx].dwell_time = PLC_SCAN_MAX_DWELL_TIME_S;
|
|
}
|
|
iot_printf("scan_band set %d band:%d, min:%d, dwell:%d\n",
|
|
idx, save_band[idx].band_id, save_band[idx].min_time,
|
|
save_band[idx].dwell_time);
|
|
idx++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
IOT_ASSERT_DUMP(idx, (uint32_t *)band_info,
|
|
(sizeof(plc_scan_band_t) * size) / 4);
|
|
|
|
iot_pkt_free(support_pkt);
|
|
|
|
scan->scan_count = idx;
|
|
|
|
switch_band:
|
|
scan->scan_idx = scan->scan_count - 1;
|
|
mac_vdev_t *vdev = get_vdev_ptr(PLC_PDEV_ID, PLC_DEFAULT_VDEV);
|
|
if (vdev && vdev->is_up && scan->is_first_scan_done && scan->is_started
|
|
&& !mac_scan_get_band_selected(scan)) {
|
|
/* immediately switch to the new scan band table */
|
|
iot_printf("scan_band update immed\n");
|
|
mac_scan_next_target(pdev);
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t mac_scan_get_band_info(uint32_t proto, uint32_t size,
|
|
plc_scan_band_t *band_info)
|
|
{
|
|
uint32_t cnt;
|
|
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);;
|
|
mac_scan_ctxt_t *scan = &pdev->scan;
|
|
|
|
(void)proto;
|
|
if ((0 == size) || !band_info) {
|
|
return 0;
|
|
}
|
|
|
|
cnt = min(size, scan->scan_count);
|
|
if (cnt) {
|
|
os_mem_cpy(band_info, scan->scan_info, sizeof(plc_scan_band_t) * cnt);
|
|
}
|
|
|
|
return cnt;
|
|
}
|
|
|
|
uint32_t mac_scan_set_band_selected(mac_scan_ctxt_t *scan, uint32_t is_sel)
|
|
{
|
|
IOT_ASSERT(scan);
|
|
scan->band_selected = !!is_sel;
|
|
|
|
if (is_sel) {
|
|
scan->is_first_scan_done = 1;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t mac_scan_get_band_selected(mac_scan_ctxt_t *scan)
|
|
{
|
|
IOT_ASSERT(scan);
|
|
|
|
return scan->band_selected;
|
|
}
|
|
|
|
uint32_t mac_scan_start(mac_scan_ctxt_t *scan)
|
|
{
|
|
mac_pdev_t *pdev_t = get_pdev_ptr(PLC_PDEV_ID);
|
|
|
|
if ((mac_scan_restart(scan) == ERR_OK) &&
|
|
pdev_t->scan.is_first_scan_done) {
|
|
mac_scan_next_target(pdev_t);
|
|
}
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t mac_scan_stop(mac_scan_ctxt_t *scan)
|
|
{
|
|
if (!scan) {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
/* stop scan diable check spur */
|
|
mac_pdev_t *pdev_t = get_pdev_ptr(PLC_PDEV_ID);
|
|
mac_check_spur_en(&pdev_t->mac_check_spur_ctxt, true);
|
|
|
|
scan->is_started = 0;
|
|
g_phy_cpu_share_ctxt.pm_status.band_select_ok = 1;
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
void mac_scan_update_rx_status(mac_scan_ctxt_t *scan, rx_fc_msg_t *fc_msg,
|
|
uint8_t band_id)
|
|
{
|
|
mac_vdev_t *vdev = get_vdev_ptr(PLC_PDEV_ID, PLC_DEFAULT_VDEV);
|
|
|
|
if (scan->is_rx_packet
|
|
|| (mac_vdev_cfg_get_node_role(vdev) == PLC_DEV_ROLE_CCO)
|
|
|| mac_scan_get_band_selected(scan)
|
|
|| (band_id != phy_proto_single_band_id_get())) {
|
|
return;
|
|
}
|
|
|
|
switch (fc_msg->delimiter) {
|
|
case FC_DELIM_SOF:
|
|
if (!PLC_TEI_IS_VALID(fc_msg->dst_tei)
|
|
&& (PLC_TEI_BCAST != fc_msg->dst_tei)) {
|
|
return;
|
|
}
|
|
case FC_DELIM_BEACON:
|
|
case FC_DELIM_NNCCO:
|
|
if (!PLC_TEI_IS_VALID(fc_msg->src_tei)
|
|
|| (PLC_NID_INVALID == fc_msg->nid)
|
|
|| vdev_is_bl_nid(vdev, fc_msg->nid)) {
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
scan->is_rx_packet = 1;
|
|
}
|
|
|
|
void mac_nid_ppm_reset_msg_handler()
|
|
{
|
|
/* msg context */
|
|
iot_printf("%s *****************\n", __FUNCTION__);
|
|
mac_pdev_t *pdev = g_mac_pdev[PLC_PDEV_ID];
|
|
mac_vdev_t *vdev = pdev->vdev[PLC_DEFAULT_VDEV];
|
|
nid_t nid;
|
|
if(vdev->is_up && (ERR_OK != vdev_get_nid(vdev, &nid)))
|
|
{
|
|
vdev_reset_ppm_sync(vdev);
|
|
/* continue the scan process */
|
|
mac_scan_next_target(pdev);
|
|
#if K48_STA_MULTI_CHANNEL_SELECT_ENABLE
|
|
iot_mac_k48sta_scan_channel_start(pdev);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void mac_scan_init(void *pdev_in, uint8_t is_reinit)
|
|
{
|
|
mac_pdev_t *pdev = (mac_pdev_t *)pdev_in;
|
|
mac_scan_ctxt_t *scan = &pdev->scan;
|
|
|
|
if (!is_reinit) {
|
|
scan->is_first_scan_done = 0;
|
|
scan->scan_idx = 0;
|
|
scan->start_ts = 0;
|
|
|
|
/* update default scan band table */
|
|
mac_scan_set_band_info(PHY_PROTO_TYPE_GET(),
|
|
IOT_ARRAY_CNT(plc_scan_tbl_glb),
|
|
(plc_scan_band_t *)&plc_scan_tbl_glb);
|
|
|
|
#if PLC_SUPPORT_BAND_SCAN
|
|
/* only sta need to scan band */
|
|
register_phy_call_mac_scan_band_cb(mac_scan_band_check_timeout);
|
|
#else
|
|
register_phy_call_mac_scan_band_cb(NULL);
|
|
#endif
|
|
} else if (!mac_scan_get_band_selected(scan) &&
|
|
(os_boot_time32() < 30 * 1000)) {
|
|
/* fix gw cert test bed sta cannot receive cert command because of
|
|
* uart baud rate is mismatch, clear is_first_scan_done flag to
|
|
* extend band switching time when vdev restart.
|
|
*/
|
|
scan->is_first_scan_done = 0;
|
|
scan->scan_idx = 0;
|
|
scan->start_ts = 0;
|
|
}
|
|
|
|
scan->band_selected = 0;
|
|
scan->is_started = 0;
|
|
scan->is_rx_packet = 0;
|
|
}
|
|
|
|
#if PPM_NTB_CAL
|
|
|
|
uint32_t IRAM_ATTR mac_adj_ntb_every_ms_from_isr(mac_ppm_ctxt_t *ppm_ctxt)
|
|
{
|
|
/* gp timer0 used by the os, unit: 1us */
|
|
uint32_t cur_adj_ts = gp_timer_get_current_val(0);
|
|
int16_t ppm_in = ppm_ctxt->ntb_ppm;
|
|
int32_t adj_ntb_calc_accum = ppm_ctxt->adj_ntb_calc_accum;
|
|
uint32_t delta_ts;
|
|
int64_t ntb_update_delta;
|
|
|
|
if (ppm_in && ppm_ctxt->adj_ntb_ts) {
|
|
/* us to ntb */
|
|
delta_ts = (uint32_t)(cur_adj_ts - ppm_ctxt->adj_ntb_ts) * 25;
|
|
ntb_update_delta = (int64_t)delta_ts * (int64_t)ppm_in;
|
|
adj_ntb_calc_accum += ntb_update_delta
|
|
% (1 << (PPM_CALC_MILLION_SHIFT + PLC_NTB_PPM_SHIFT));
|
|
ntb_update_delta /= 1 << (PPM_CALC_MILLION_SHIFT + PLC_NTB_PPM_SHIFT);
|
|
ntb_update_delta += adj_ntb_calc_accum
|
|
/ (1 << (PPM_CALC_MILLION_SHIFT + PLC_NTB_PPM_SHIFT));
|
|
adj_ntb_calc_accum %= (1 << (PPM_CALC_MILLION_SHIFT
|
|
+ PLC_NTB_PPM_SHIFT));
|
|
|
|
#if ENA_WAR_728
|
|
/* WAR728: 1/3 chance that the mac ntb timer will miss a clock
|
|
* when the sw modifies the ntb delta register.
|
|
*/
|
|
if (ntb_update_delta) {
|
|
if (ntb_update_delta < 0) {
|
|
adj_ntb_calc_accum += mac_config_ntb_delta_from_isr(0,
|
|
(uint32_t)(-ntb_update_delta))
|
|
<< (PPM_CALC_MILLION_SHIFT + PLC_NTB_PPM_SHIFT);
|
|
} else {
|
|
adj_ntb_calc_accum += mac_config_ntb_delta_from_isr(1,
|
|
(uint32_t)ntb_update_delta)
|
|
<< (PPM_CALC_MILLION_SHIFT + PLC_NTB_PPM_SHIFT);
|
|
}
|
|
}
|
|
#else
|
|
if (ntb_update_delta) {
|
|
if (ntb_update_delta < 0) {
|
|
mac_config_ntb_delta_from_isr(0, (uint32_t)(-ntb_update_delta));
|
|
} else {
|
|
mac_config_ntb_delta_from_isr(1, (uint32_t)ntb_update_delta);
|
|
}
|
|
}
|
|
#endif
|
|
ppm_ctxt->adj_ntb_calc_accum = adj_ntb_calc_accum;
|
|
}
|
|
|
|
if (cur_adj_ts) {
|
|
ppm_ctxt->adj_ntb_ts = cur_adj_ts;
|
|
} else {
|
|
ppm_ctxt->adj_ntb_ts = 1;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
void IRAM_ATTR mac_ntb_sync_ppm_from_isr()
|
|
{
|
|
/* NOTE: this API is called from systick isr,
|
|
* should be no parameters, currently, we only
|
|
* use one pdev and default vdev
|
|
* TODO: add more check if more vdevs
|
|
*/
|
|
mac_pdev_t *pdev = g_mac_pdev[PLC_PDEV_ID];
|
|
if (pdev) {
|
|
mac_vdev_t *vdev = pdev->vdev[PLC_DEFAULT_VDEV];
|
|
if (vdev) {
|
|
/* if vdev created */
|
|
nid_t my_nid;
|
|
if (vdev_get_nid(vdev, &my_nid) != ERR_OK) {
|
|
return;
|
|
}
|
|
mac_ppm_ctxt_t *ppm_ctxt = &vdev->mac_ppm;
|
|
if (ppm_ctxt->is_inited) {
|
|
/* if ppm module inited */
|
|
mac_adj_ntb_every_ms_from_isr(ppm_ctxt);
|
|
}
|
|
}
|
|
}
|
|
#if DEBUG_SYSTICK
|
|
{
|
|
static uint32_t g_toggle=0;
|
|
g_toggle = g_toggle ? 0:1;
|
|
iot_gpio_value_set(44, g_toggle);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
void mac_ppm_reset_counter(mac_ntb_record_ctxt_t *record)
|
|
{
|
|
record->last_bcn_local_ts = 0;
|
|
record->last_bcn_remote_tx_ntb = 0;
|
|
record->last_saved_ntb = 0;
|
|
record->last_bcn_local_ntb = 0;
|
|
}
|
|
|
|
void mac_scan_set_ntb_ppm(mac_ppm_ctxt_t *ppm_ctxt, int16_t ppm,
|
|
uint32_t rate_mode) {
|
|
if (!ppm_ctxt) {
|
|
IOT_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
/* Note: mac update ppm logic
|
|
* kl1: update every ms currently by sw.
|
|
* kl2: hw default support mac update ppm. if need use soft sync ntb ppm,
|
|
* need ppm = ppm + 40. every ms must trigger hw interrupt, even
|
|
* cfg_nbt_delta_va == 0, and must config cfg_modify_ntb_en=1 and
|
|
* cfg_nbt_delta_val.
|
|
* kl3: same as kl2.
|
|
*/
|
|
ppm_ctxt->ntb_ppm = ppm;
|
|
mac_ppm_cal_set(PHY_CAL_UNIT_1_1, ppm, rate_mode);
|
|
}
|
|
|
|
int16_t mac_scan_get_ntb_ppm(mac_ppm_ctxt_t * ppm_ctxt) {
|
|
if (!ppm_ctxt) {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
return (int16_t) (ppm_ctxt->ntb_ppm);
|
|
}
|
|
|
|
void mac_scan_set_bb_ppm(mac_ppm_ctxt_t *ppm_ctxt, int16_t ppm,
|
|
uint32_t rate_mode, uint8_t update_flag)
|
|
{
|
|
if (!ppm_ctxt) {
|
|
IOT_ASSERT(0);
|
|
return;
|
|
}
|
|
ppm_ctxt->bb_ppm = ppm;
|
|
#if (IOT_STA_CONTROL_MODE == IOT_STA_CONTROL_TYPE_METER)
|
|
/* for ckq, not fix tx ppm */
|
|
if (BB_PPM_TX_ONLY == update_flag) {
|
|
return;
|
|
}
|
|
update_flag = BB_PPM_RX_ONLY;
|
|
#endif
|
|
|
|
#if ENA_RX_BB_PPM
|
|
if (mac_multi_sync_get_ena(PLC_PDEV_ID)) {
|
|
if (BB_PPM_RX_ONLY == update_flag) {
|
|
return;
|
|
}
|
|
update_flag = BB_PPM_TX_ONLY;
|
|
}
|
|
#endif
|
|
|
|
phy_ppm_cal_and_update_hw(PHY_CAL_UNIT_1_1, ppm, rate_mode, update_flag);
|
|
}
|
|
|
|
int16_t mac_scan_get_bb_ppm(mac_ppm_ctxt_t * ppm_ctxt) {
|
|
if (!ppm_ctxt) {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
return (int16_t) (ppm_ctxt->bb_ppm);
|
|
}
|
|
|
|
static int16_t mac_ppm_round(int16_t ppm_err)
|
|
{
|
|
int16_t temp_ppm_err = IOT_ABS(ppm_err);
|
|
/* If it is larger than half of the decimal part,
|
|
* it will move upward, otherwise it will move downward
|
|
*/
|
|
if (temp_ppm_err & ((1 << PLC_NTB_PPM_SHIFT) >> 1)) {
|
|
if (ppm_err >= 0) {
|
|
temp_ppm_err = 0;
|
|
} else {
|
|
temp_ppm_err = 1;
|
|
}
|
|
} else {
|
|
if (ppm_err >= 0) {
|
|
temp_ppm_err = 1;
|
|
} else {
|
|
temp_ppm_err = 0;
|
|
}
|
|
}
|
|
return temp_ppm_err;
|
|
}
|
|
|
|
uint32_t mac_ntb_ppm_sync(mac_ppm_ctxt_t *ppm_ctxt, uint32_t rate_mode,
|
|
uint32_t remote_ts, uint32_t local_ts, uint32_t local_ntb,
|
|
int16_t ppm_hw, int16_t *ntb_ppm, uint32_t bcn_period_ms,
|
|
bool_t is_vaild_tei)
|
|
{
|
|
(void)ppm_hw;
|
|
uint8_t update_flag = BB_PPM_TXRX;
|
|
int16_t ppm_err = mac_ppm_cal(&ppm_ctxt->ntb_record, 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 (is_vaild_tei) {
|
|
mac_scan_set_ntb_ppm(ppm_ctxt, -ppm_err, rate_mode);
|
|
ppm_ctxt->ntb_ppm_update_cnt++;
|
|
}
|
|
if (ppm_ctxt->is_sync_bb_ppm_to_ntb) {
|
|
/* enable bb ppm sync */
|
|
mac_scan_set_bb_ppm(ppm_ctxt,
|
|
((-ppm_err) >> PLC_NTB_PPM_SHIFT) + mac_ppm_round(ppm_err),
|
|
rate_mode, update_flag);
|
|
} else {
|
|
/* disable bb ppm sync */
|
|
iot_printf("not sync bb ppm to ntb, ppm:%d\n", ppm_err);
|
|
}
|
|
if (ntb_ppm) {
|
|
*ntb_ppm = ppm_err;
|
|
}
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
int16_t mac_ppm_cal(mac_ntb_record_ctxt_t *ntb_ctxt, uint32_t remote_ts,
|
|
uint32_t local_ts, uint32_t local_ntb, uint32_t bcn_period_ms)
|
|
{
|
|
uint8_t is_update_ts = 0;
|
|
int64_t ntb_diff;
|
|
int64_t ntb_period, local_period;
|
|
uint64_t last_saved_ntb = mac_sched_get_ntb64(NULL);
|
|
int16_t ppm_err = PLC_MAX_MAC_NTB_PPM;
|
|
|
|
if (ntb_ctxt->last_saved_ntb) {
|
|
ntb_period = (int64_t)remote_ts
|
|
- (int64_t)ntb_ctxt->last_bcn_remote_tx_ntb;
|
|
if (ntb_period < 0) {
|
|
/* wrap around happen */
|
|
ntb_period = (~0 - ntb_ctxt->last_bcn_remote_tx_ntb + 1)
|
|
+ remote_ts;
|
|
}
|
|
local_period = (int64_t)local_ts - (int64_t)ntb_ctxt->last_bcn_local_ts;
|
|
if (local_period < 0) {
|
|
/* wrap */
|
|
local_period = (~0 - ntb_ctxt->last_bcn_local_ts + 1) + local_ts;
|
|
}
|
|
/* if wrap_cnt > 0, then it's long time not
|
|
* receiving PCO's bcn (> 4 mins)
|
|
*/
|
|
ntb_period |= (last_saved_ntb - ntb_ctxt->last_saved_ntb)
|
|
& 0xffffffff00000000l;
|
|
local_period |= (last_saved_ntb - ntb_ctxt->last_saved_ntb)
|
|
& 0xffffffff00000000l;
|
|
if (ntb_period
|
|
> MAC_MS_TO_NTB(max(50, bcn_period_ms >> 2))) {
|
|
ntb_diff = (int64_t) (local_period - ntb_period);
|
|
ppm_err = (int16_t) PPM_CAL_FROM_NTB(ntb_diff, ntb_period);
|
|
is_update_ts = 1;
|
|
#if (PLC_MAC_RX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1)
|
|
iot_printf("ntb_p=0x%08x%08x, "
|
|
"ntb_d=0x%08x%08x, calc_ppm=%d, real_ppm=%d"
|
|
"\n",
|
|
iot_uint64_higher32(ntb_period),
|
|
iot_uint64_lower32(ntb_period),
|
|
iot_uint64_higher32(ntb_diff),
|
|
iot_uint64_lower32(ntb_diff),
|
|
ppm_err, ppm_err / (1 << PLC_NTB_PPM_SHIFT));
|
|
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_INFO_LVL_2,
|
|
IOT_MAC_PPM_SYNC_ID, 6,
|
|
iot_uint64_higher32(ntb_period),
|
|
iot_uint64_lower32(ntb_period),
|
|
iot_uint64_higher32(ntb_diff),
|
|
iot_uint64_lower32(ntb_diff),
|
|
ppm_err, ppm_err / (1 << PLC_NTB_PPM_SHIFT));
|
|
#endif
|
|
}
|
|
} else {
|
|
is_update_ts = 1;
|
|
}
|
|
|
|
if (is_update_ts) {
|
|
ntb_ctxt->last_saved_ntb = last_saved_ntb;
|
|
ntb_ctxt->last_bcn_local_ts = local_ts;
|
|
ntb_ctxt->last_bcn_remote_tx_ntb = remote_ts;
|
|
ntb_ctxt->last_bcn_local_ntb = local_ntb;
|
|
}
|
|
|
|
return ppm_err;
|
|
}
|
|
|
|
#if MAC_PPM_MULTI_NODE_ENABLE
|
|
|
|
/**
|
|
*@brief mac_ppm_record_node_init
|
|
*
|
|
* initialize the ppm record node
|
|
*
|
|
*@param node [point to node]
|
|
*@exception [none.]
|
|
*@return [none.]
|
|
*/
|
|
static void mac_ppm_record_node_init(mac_ppm_node_t *node)
|
|
{
|
|
if (node == NULL) {
|
|
return;
|
|
}
|
|
|
|
os_mem_set((uint8_t *)&node->record_ctxt, 0, sizeof(mac_ntb_record_ctxt_t));
|
|
node->src_tei = PLC_TEI_INVAL;
|
|
node->ppm = PLC_MAX_MAC_NTB_PPM;
|
|
}
|
|
|
|
/**
|
|
*@brief mac_ppm_record_init
|
|
*
|
|
* initialize the ppm record
|
|
*
|
|
*@param node [point to ppm_ctxt]
|
|
*@exception [none.]
|
|
*@return [none.]
|
|
*/
|
|
static void mac_ppm_record_init(mac_ppm_ctxt_t *ppm_ctxt)
|
|
{
|
|
uint16_t idx;
|
|
mac_ppm_record_t *record = &ppm_ctxt->record_info;
|
|
|
|
for (idx = 0; idx < MAC_PPM_RECORD_NODE_COUNT; idx++) {
|
|
mac_ppm_record_node_init(&record->node[idx]);
|
|
}
|
|
}
|
|
|
|
void mac_ppm_record_refresh_handle(mac_ppm_ctxt_t *arg)
|
|
{
|
|
uint8_t idx, count;
|
|
uint32_t m = 1;
|
|
uint64_t last_saved_ntb;
|
|
uint64_t new_saved_ntb = mac_sched_get_ntb64(NULL);
|
|
mac_ppm_record_t *record = &arg->record_info;
|
|
|
|
if (!record->is_start) {
|
|
return;
|
|
}
|
|
|
|
/* if it is time for refresh recording informatiom */
|
|
count = iot_bitmap_cbs((uint8_t *)record->bitmap,
|
|
sizeof(record->bitmap));
|
|
|
|
for (idx = 0; idx < count; idx++, m++) {
|
|
m = iot_bitmap_ffs_from((uint8_t *)record->bitmap,
|
|
sizeof(record->bitmap), m);
|
|
|
|
last_saved_ntb = record->node[m - 1].record_ctxt.last_saved_ntb;
|
|
if (new_saved_ntb - last_saved_ntb >= MAC_PPM_RECORD_REFRESH_INTERVAL) {
|
|
iot_bitmap_clear((uint8_t *)record->bitmap,
|
|
sizeof(record->bitmap), m);
|
|
iot_printf("ppm record delete ppm = %d, src_tei = %d\n",
|
|
record->node[m - 1].ppm,
|
|
record->node[m - 1].src_tei);
|
|
mac_ppm_record_node_init(&record->node[m - 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*@brief mac_ppm_record_timer_handler
|
|
*
|
|
* ppm record timer handle function
|
|
*
|
|
*@param ppm_ctxt [point to the mac_ppm_ctxt_t variable witch will
|
|
record the ppm data]
|
|
*@exception [none.]
|
|
*@return [none.]
|
|
*/
|
|
static void mac_ppm_record_timer_handler(mac_ppm_ctxt_t *ppm_ctxt)
|
|
{
|
|
uint32_t new_saved_ms = os_boot_time32();
|
|
|
|
if (ppm_ctxt->record_info.is_start) {
|
|
if (new_saved_ms - ppm_ctxt->record_info.last_saved_ms >=
|
|
MAC_PPM_RECORD_CHECK_INTERVAL) {
|
|
/* 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_PPM_RECORD_TIMER;
|
|
msg->data1 = 0;
|
|
msg->data2 = ppm_ctxt;
|
|
mac_queue_msg(msg, MAC_MSG_QUEUE_LP);
|
|
ppm_ctxt->record_info.last_saved_ms = new_saved_ms;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mac_ppm_record_timer_start(mac_ppm_ctxt_t *ppm_ctxt)
|
|
{
|
|
mac_ppm_record_init(ppm_ctxt);
|
|
#if MAC_PPM_RECORD_DEBUG
|
|
iot_printf("ppm record start ppm_ctxt = 0x%x\n", ppm_ctxt);
|
|
#endif /* MAC_PPM_RECORD_DEBUG */
|
|
ppm_ctxt->record_info.is_start = 1;
|
|
}
|
|
|
|
void mac_ppm_record_timer_stop(mac_ppm_ctxt_t *ppm_ctxt)
|
|
{
|
|
#if MAC_PPM_RECORD_DEBUG
|
|
iot_printf("ppm record stop ppm_ctxt = 0x%x\n", ppm_ctxt);
|
|
#endif /* MAC_PPM_RECORD_DEBUG */
|
|
mac_clean_msg(MAC_MSG_TYPE_TIMER, MAC_MSG_ID_PPM_RECORD_TIMER);
|
|
}
|
|
|
|
/**
|
|
*@brief mac_ppm_node_record
|
|
*
|
|
* record nerghbor node's ppm
|
|
*
|
|
*@param ppm_node [point to the mac_ppm_node variable witch will
|
|
record the ppm data]
|
|
*@param ppm_err [ppm error]
|
|
*@exception [none.]
|
|
*@return [none.]
|
|
*/
|
|
static void mac_ppm_node_record(mac_ppm_node_t *ppm_node, int16_t ppm_err)
|
|
{
|
|
if ((ppm_err == PLC_MAX_MAC_NTB_PPM) || (ppm_node == NULL)) {
|
|
return;
|
|
}
|
|
|
|
if (ppm_node->ppm != PLC_MAX_MAC_NTB_PPM) {
|
|
ppm_node->ppm = ppm_node->ppm - ((ppm_node->ppm) >> 3) +
|
|
((ppm_err) >> 3);
|
|
} else {
|
|
ppm_node->ppm = ppm_err;
|
|
}
|
|
|
|
#if MAC_PPM_RECORD_DEBUG
|
|
iot_printf("ppm record find, src_tei = %d, ppm_node->ppm = %d\n",
|
|
ppm_node->src_tei, ppm_node->ppm);
|
|
#endif /* MAC_PPM_RECORD_DEBUG */
|
|
}
|
|
|
|
/**
|
|
*@brief mac_ppm_get_node_record
|
|
*
|
|
* get nerghbor node's ntb
|
|
*
|
|
*@param src_tei [source tei]
|
|
*@param ppm_ctx [point to the mac_ppm_ctxt_t variable witch will
|
|
record the ppm data]
|
|
*@exception [none.]
|
|
*@return [point to mac_ppm_node_t struct.]
|
|
*/
|
|
static mac_ppm_node_t *mac_ppm_get_node_record(uint16_t src_tei,
|
|
mac_ppm_ctxt_t *ppm_ctxt)
|
|
{
|
|
uint16_t idx, count;
|
|
uint32_t m = 1;
|
|
mac_ppm_record_t *record = &ppm_ctxt->record_info;
|
|
mac_ppm_node_t *ret = NULL;
|
|
|
|
count = iot_bitmap_cbs((uint8_t *)record->bitmap,
|
|
sizeof(record->bitmap));
|
|
for (idx = 0, m = 1; idx < count; idx++, m++) {
|
|
m = iot_bitmap_ffs_from((uint8_t *)record->bitmap,
|
|
sizeof(record->bitmap), m);
|
|
|
|
if (record->node[m - 1].src_tei == src_tei) {
|
|
ret = &record->node[m - 1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if there is a space to save the device's information */
|
|
if (ret == NULL) {
|
|
m = 1;
|
|
m = iot_bitmap_ffz_from((uint8_t *)record->bitmap,
|
|
sizeof(record->bitmap), m);
|
|
if (!m) {
|
|
#if MAC_PPM_RECORD_DEBUG
|
|
iot_printf("ppm record get no space for new node\n");
|
|
#endif /* MAC_PPM_RECORD_DEBUG */
|
|
return ret;
|
|
}
|
|
|
|
ret = &record->node[m - 1];
|
|
record->node[m - 1].src_tei = src_tei;
|
|
iot_bitmap_set((uint8_t *)record->bitmap, sizeof(record->bitmap), m);
|
|
#if MAC_PPM_RECORD_DEBUG
|
|
iot_printf("ppm record get a space for m == %d tei = %d\n", m, src_tei);
|
|
#endif /* MAC_PPM_RECORD_DEBUG */
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void mac_ppm_record_handle(void *vdev_input, uint32_t nid,
|
|
rx_fc_msg_t *rx_fc_msg, uint32_t local_ts, uint32_t ntb_ts, uint32_t proto)
|
|
{
|
|
uint16_t ppm_err;
|
|
mac_vdev_t *vdev = (mac_vdev_t *)vdev_input;
|
|
mac_peer_t *peer = find_peer(vdev, nid, (tei_t)rx_fc_msg->src_tei);
|
|
mac_ppm_node_t *ppm_node = NULL;
|
|
|
|
if ((!peer) || (!peer->is_sub_peer)) {
|
|
ppm_node = mac_ppm_get_node_record(
|
|
rx_fc_msg->src_tei, &vdev->mac_ppm);
|
|
if (ppm_node) {
|
|
ppm_err = mac_ppm_cal(&ppm_node->record_ctxt,
|
|
rx_fc_msg->time_stamp, local_ts, ntb_ts,
|
|
vdev_get_bc_period_ms(vdev, proto));
|
|
mac_ppm_node_record(ppm_node, ppm_err);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif/* MAC_PPM_MULTI_NODE_ENABLE */
|
|
|
|
uint32_t mac_ppm_init(mac_ppm_ctxt_t *ppm, int16_t ppm_init,
|
|
uint32_t rate_mode)
|
|
{
|
|
int16_t bb_ppm, ntb_ppm;
|
|
|
|
bb_ppm = ppm_init;
|
|
ntb_ppm = ppm_init;
|
|
|
|
iot_printf("***set ini bb ppm = %d, ntb ppm = %d\n", bb_ppm, ntb_ppm);
|
|
mac_enable_hw_ntb_adjust(true);
|
|
mac_ppm_reset_counter(&ppm->ntb_record);
|
|
ppm->is_sync_bb_ppm_to_ntb = 1;
|
|
mac_scan_set_ntb_ppm(ppm, ntb_ppm << PLC_NTB_PPM_SHIFT, rate_mode);
|
|
mac_scan_set_bb_ppm(ppm, bb_ppm, rate_mode, BB_PPM_TXRX);
|
|
ppm->is_inited = 1;
|
|
ppm->ntb_ppm_update_cnt = 0;
|
|
#if PPM_NTB_CAL
|
|
ppm->adj_ntb_ts = 0;
|
|
ppm->adj_ntb_calc_accum = 0;
|
|
#endif
|
|
|
|
#if DEBUG_SYSTICK
|
|
{
|
|
// force psram clk output
|
|
volatile uint32_t *reg = (volatile uint32_t *) 0x61000224;
|
|
*reg |= 0x4;
|
|
// gpio init
|
|
iot_gpio_open_as_output(44);
|
|
}
|
|
#endif
|
|
return ERR_OK;
|
|
}
|