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

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;
}