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

2709 lines
104 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 "beacon_frame.h"
#include "beacon.h"
#include "iot_errno.h"
#include "mac_bcm_api.h"
#include "mac_data_api.h"
#include "mpdu_frame.h"
#include "mac_tx_hw.h"
#include "mac.h"
#include "mac_msg.h"
#include "mac_desc_engine.h"
#include "iot_crc.h"
#include "mac_sched.h"
#include "mac_sched_hw.h"
#include "mac_cmn_hw.h"
#include "plc_fr.h"
#include "hw_tonemap.h"
#include "rate_control.h"
#include "iot_io.h"
#include "iot_dbglog_api.h"
#include "iot_dbglog_parser.h"
#include "mpdu_header.h"
#include "mac_crc.h"
#include "mac_cfg.h"
#include "phy_txrx_pwr.h"
#include "phy_chn.h"
#include "plc_mac_cfg.h"
#include "mac_tx_power.h"
#include "tx_desc_reg_api.h"
#include "mac_check_spur_cco.h"
#include "mac_reset.h"
#include "rf_beacon_frame.h"
#include "mac_rf_sched.h"
#include "mac_cert_test.h"
#include "mac_rf_tx_hw.h"
#include "mac_task.h"
#include "iot_oem_api.h"
#if SUPPORT_SOUTHERN_POWER_GRID
uint32_t mac_tx_detect_bcn(mac_beacon_ctx_t *bcn_ctxt)
{
iot_printf("%s\n", __FUNCTION__);
uint32_t len = sizeof(mac_beacon_ctx_t);
/* get a temporary pkt for bcn ctxt */
iot_pkt_t *detect_bcn = iot_pkt_alloc(len, PLC_MAC_BEACON_MID);
if (detect_bcn == NULL) {
iot_printf("detect_bcn alloc fail\n");
return ERR_NOMEM;
}
iot_pkt_reserve(detect_bcn, 0);
iot_pkt_put(detect_bcn, len);
mac_beacon_ctx_t *bcn =
(mac_beacon_ctx_t *)iot_pkt_block_ptr(detect_bcn, IOT_PKT_BLOCK_DATA);
os_mem_cpy((void *)bcn, (void *)bcn_ctxt, sizeof(mac_beacon_ctx_t));
if (bcn->beacon_component_enable[MAC_BC_BMI_TIME_SLOT]) {
/* fill detect bcn */
uint32_t tdma_dur = bcn->time_slot.bc_slot_dur * (
bcn->time_slot.cco_bc_cnt + bcn->time_slot.non_cco_bc_info.bc_cnt);
uint32_t csma_dur = 0;
for (uint8_t i = 0; i < bcn->time_slot.csma_info.phase_cnt; i++) {
csma_dur += bcn->time_slot.csma_info.slot_dur[i];
}
bcn->time_slot.bp_start_ntb = bcn->time_slot.bp_start_ntb +
MAC_MS_TO_NTB(tdma_dur) + MAC_MS_TO_NTB(csma_dur);
bcn->time_slot.bc_period = 0;
for (uint8_t j = 0; j < bcn->time_slot.d_csma_info.phase_cnt; j++) {
bcn->time_slot.bc_period += bcn->time_slot.d_csma_info.slot_dur[j];
bcn->time_slot.csma_info.phase[j]
= bcn->time_slot.d_csma_info.phase[j];
bcn->time_slot.csma_info.slot_dur[j]
= bcn->time_slot.d_csma_info.slot_dur[j];
}
bcn->time_slot.cco_bc_cnt = 1;
bcn->time_slot.proxy_bc_cnt = 0;
bcn->time_slot.bc_slot_dur = 15; /* 15ms */
bcn->time_slot.d_csma_lid = LID_BCSMA_FB_DETECT;
bcn->time_slot.tdma_slot_dur = 0;
bcn->time_slot.tdma_lid = 0;
/* proxy and discover beacons info */
bcn->time_slot.non_cco_bc_info.bc_cnt = 0;
/* csma slot info */
bcn->time_slot.csma_info.phase_cnt
= bcn->time_slot.d_csma_info.phase_cnt;
/* bcsma slot info*/
os_mem_set(&bcn->time_slot.d_csma_info, 0,
sizeof(bcn->time_slot.d_csma_info));
} else {
IOT_ASSERT(0);
}
/* disable detect info */
uint32_t detect_band = 0xff;
if (bcn->beacon_component_enable[MAC_BC_BMI_FB_DETECT]) {
detect_band = bcn->fb_detect.band_id;
} else {
IOT_ASSERT(0);
}
#if PLC_MAC_TX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_2
iot_printf("[spg_dbg] detect_band:%d, detect_start_ntb, "
"bc_period:%d\n",
detect_band, bcn->time_slot.bp_start_ntb, bcn->time_slot.bc_period);
#endif
/* init detect buf */
iot_pkt_t *detect_buff = iot_pkt_alloc(520, PLC_MAC_BEACON_MID);
if (detect_buff == NULL) {
iot_pkt_free(detect_bcn);
return ERR_NOMEM;
}
/* bcn tx no need to reserve any space,
* we put all after the first byte :
* FC + BCN PB payload + PB CRC
*/
iot_pkt_reserve(detect_buff, 0);
iot_pkt_put(detect_buff, 520);
mac_beacon_tx(PHY_PROTO_TYPE_GET(), detect_band,
bcn, detect_buff);
/* free detect bcn buf */
iot_pkt_free(detect_bcn);
return 0;
}
#endif
#if (PLC_SUPPORT_CCO_ROLE)
/* reset cco beacon context */
static void mac_beacon_cco_reset(mac_beacon_ctx_t *mac_beacon)
{
os_mem_set(&mac_beacon->cco, 0, sizeof(mac_beacon->cco));
}
/* cco only beacon update handling */
uint8_t mac_update_beacon_cco(uint32_t proto, mac_vdev_t *vdev,
mac_bc_update_t *ent)
{
uint64_t tmp;
uint8_t tx_cnt = 0, tx_req = 1, rf_tx_req = 1;
uint32_t *bc_period_cnt =
vdev_get_bc_period_cnt_ptr(proto, vdev);
mac_rf_vdev_t *rf_vdev = get_rf_vdev_ptr(vdev->ref_pdev_id,
RF_PDEV_ID, vdev->rf_vdev_id);
if (rf_vdev && rf_vdev->tx_rx_suspend) {
rf_tx_req = 0;
}
if (vdev && vdev->tx_rx_suspend) {
tx_req = 0;
}
/* auto power control */
/* TODO : There will be more and more follow-up conditions, */
/* need to input the variables to tx_power module directly later */
mac_beacon_ctx_t *bcn_ctx = &vdev->bcn_ctx;
if (ent->peer_cnt >= HIGH_PWR_NETWORK_SCALE_THRE ||
bcn_ctx->time_slot.bc_period >= HIGH_PWR_BCN_PERIOD_THRE) {
mac_high_power_req(vdev, HIGH_PWR_REQ_BY_NETWORK_SIZE, true);
}
/* below fields need to be updated for every beacon by mac layer
* 1. beacon period count
* 2. bp start ntb
*/
if(ent->new_bp_req) {
/* apply the next beacon period schedule into HW */
tmp = mac_sched_get_ntb64(vdev);
tmp += MAC_MS_TO_NTB(MAC_BP_AHEAD_NEXT_BP_DUR);
if (tmp > vdev->bcn_ctx.cco.next_start_ntb64) {
/* next bp start too late. adjust the new start ntb */
iot_printf("%s next bp start too late, start_ntb: %lu-%lu, "
"curr_ntb %lu-%lu\n", __FUNCTION__,
iot_uint64_higher32(vdev->bcn_ctx.cco.next_start_ntb64),
iot_uint64_lower32(vdev->bcn_ctx.cco.next_start_ntb64),
iot_uint64_higher32(tmp), iot_uint64_lower32(tmp));
vdev->bcn_ctx.cco.next_start_ntb64 = tmp +
MAC_MS_TO_NTB(MAC_BP_AHEAD_NEXT_BP_DUR);
mac_pdev_t *pdev = get_pdev_ptr(vdev->ref_pdev_id);
if (pdev->mac_pm.mac_pm_flag) {
vdev->bcn_ctx.cco.next_start_ntb64 +=
MAC_MS_TO_NTB(MAC_BP_AHEAD_NEXT_BP_DUR);
}
}
#if SUPPORT_IEEE_1901
uint16_t dur_compens = vdev->bcn_ctx.time_slot.protected_region_dur
% MAC_I1901_NN_CCO_PER_DUR_MS;
if (dur_compens) {
vdev->bcn_ctx.time_slot.protected_region_dur +=
MAC_I1901_NN_CCO_PER_DUR_MS - dur_compens;
}
#endif
#if FORCE_INC_BCN_INV_MS
vdev->bcn_ctx.cco.next_start_ntb64 += MAC_MS_TO_NTB(FORCE_INC_BCN_INV_MS);
#endif
/* config scheduler for next beacon period */
vdev->bcn_ctx.cco.curr_start_ntb64 = mac_sched_cco_set(vdev,
&vdev->bcn_ctx.time_slot, vdev->bcn_ctx.cco.next_start_ntb64,
&vdev->bcn_ctx.cco.next_start_ntb64);
/* rf cco schedule set */
mac_rf_sched_cco_set(rf_vdev, &vdev->bcn_ctx.time_slot,
vdev->bcn_ctx.cco.curr_start_ntb64,
vdev->bcn_ctx.cco.next_start_ntb64);
/* update beacon period count */
vdev->bcn_ctx.cco.curr_bp_cnt++;
if (vdev->bcn_ctx.cco.curr_bp_cnt == 0)
vdev->bcn_ctx.cco.curr_bp_cnt = 1;
*bc_period_cnt =
vdev->bcn_ctx.cco.curr_bp_cnt;
/* update beacon period start ntb */
vdev->bcn_ctx.time_slot.bp_start_ntb =
iot_uint64_lower32(vdev->bcn_ctx.cco.curr_start_ntb64);
/* update tx phase */
vdev_set_sta_cap_phase(proto, vdev, vdev->l_phase1);
vdev->bcn_ctx.fc.phase = vdev->l_phase1;
if (tx_req) {
/* trigger new beacon tx */
tx_cnt = mac_beacon_tx(proto, phy_proto_single_band_id_get(),
&vdev->bcn_ctx, vdev->bcn_ctx.mac_beacon_buffer[0]);
}
if (rf_tx_req) {
/* mac rf send beacon.
* NOTE:enqueue the rf beacon as early as possible.
*/
uint32_t ret = mac_rf_assemble_and_send_bcn(proto, vdev,
(uint8_t)vdev->bcn_ctx.time_slot.rf_std_tx, false);
if (ret && ret != ERR_NOSUPP) {
iot_printf("rf beacon send fail\n");
}
}
if (tx_req) {
if (vdev->l_phase2) {
/* update tx phase */
vdev_set_sta_cap_phase(proto, vdev, vdev->l_phase2);
vdev->bcn_ctx.fc.phase = vdev->l_phase2;
/* trigger new beacon tx */
mac_beacon_tx(proto, phy_proto_single_band_id_get(),
&vdev->bcn_ctx, vdev->bcn_ctx.mac_beacon_buffer[1]);
}
if (vdev->l_phase3) {
/* update tx phase */
vdev_set_sta_cap_phase(proto, vdev, vdev->l_phase3);
vdev->bcn_ctx.fc.phase = vdev->l_phase3;
/* trigger new beacon tx */
mac_beacon_tx(proto, phy_proto_single_band_id_get(),
&vdev->bcn_ctx, vdev->bcn_ctx.mac_beacon_buffer[2]);
}
#if SUPPORT_SOUTHERN_POWER_GRID
/* need tx detect pkt */
if (MAC_BEACON_IS_DETECT == bcn_ctx->is_tx_detect) {
vdev->bcn_ctx.fc.phase =
vdev->bcn_ctx.time_slot.d_csma_info.phase[0];
mac_tx_detect_bcn(bcn_ctx);
bcn_ctx->is_tx_detect = MAC_BEACON_IS_NORMAL;
}
#endif
}
}
return tx_cnt;
}
#else /* PLC_SUPPORT_CCO_ROLE */
#define mac_beacon_cco_reset(mac_beacon)
#define mac_update_beacon_cco(proto, vdev, ent) (0)
#endif /* PLC_SUPPORT_CCO_ROLE */
void mac_beacon_uniq_info_get(uint32_t proto, mac_beacon_ctx_t *bcn_ctx,
mac_bc_ent_str_info_t *ptr)
{
IOT_ASSERT(ptr && bcn_ctx);
switch (proto) {
case PLC_PROTO_TYPE_SG:
ptr->plh_str_size = sizeof(mac_bc_fp_t);
ptr->sta_cap_str_size = sizeof(mac_bc_sta_cap_t);
ptr->rt_param_str_size = sizeof(mac_bc_rt_param_t);
ptr->simple_param_str_size = sizeof(mac_bc_simple_param_t);
ptr->plh_str_ptr =
(void *)&bcn_ctx->sg_uniq_bc_str.payload_header;
ptr->sta_cap_str_ptr =
(void *)&bcn_ctx->sg_uniq_bc_str.sta_cap;
ptr->rt_param_str_ptr =
(void *)&bcn_ctx->sg_uniq_bc_str.route_param;
ptr->simple_param_str_ptr =
(void *)&bcn_ctx->sg_uniq_bc_str.simple_param;
break;
case PLC_PROTO_TYPE_SPG:
ptr->plh_str_size = sizeof(mac_bc_fp_spg_t);
ptr->sta_cap_str_size = sizeof(mac_bc_sta_cap_spg_t);
ptr->rt_param_str_size = sizeof(mac_bc_rt_param_spg_t);
ptr->simple_param_str_size = sizeof(mac_bc_simple_param_spg_t);
ptr->plh_str_ptr =
(void *)&bcn_ctx->spg_uniq_bc_str.payload_header;
ptr->sta_cap_str_ptr =
(void *)&bcn_ctx->spg_uniq_bc_str.sta_cap;
ptr->rt_param_str_ptr =
(void *)&bcn_ctx->spg_uniq_bc_str.route_param;
ptr->simple_param_str_ptr =
(void *)&bcn_ctx->spg_uniq_bc_str.simple_param;
break;
default:
IOT_ASSERT(0);
break;
}
}
/* sta only beacon update handling */
uint8_t mac_update_beacon_sta(uint32_t proto, mac_vdev_t *vdev,
mac_bc_update_t *ent)
{
uint64_t curr_ntb;
uint32_t end_ntb, sta_tx_type;
uint8_t tx_cnt = 0;
uint8_t reason = 0;
uint8_t high_power_req = 0;
mac_beacon_ctx_t *bcn_ctx = &vdev->bcn_ctx;
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
mac_rf_vdev_t *rf_vdev = get_rf_vdev_ptr(vdev->ref_pdev_id,
RF_PDEV_ID, vdev->rf_vdev_id);
mac_rf_pdev_t *rf_pdev = NULL;
if (rf_vdev) {
rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, rf_vdev->ref_pdev_id);
}
/* auto power control */
/* TODO : There will be more and more follow-up conditions, */
/* need to input the variables to tx_power module directly later */
if (ent->peer_cnt >= HIGH_PWR_NETWORK_SCALE_THRE) {
high_power_req = 1;
reason = HIGH_PWR_REQ_BY_NETWORK_SIZE;
} else if (ent->high_power) {
high_power_req = 1;
reason = HIGH_PWR_REQ_BY_CVG;
}
if (high_power_req) {
mac_high_power_req(vdev, reason, true);
}
#if DEBUG_HWQ_SHCED_HANG
pdev->dbg_status = MAC_TX_HANG_STATUS_4;
#endif
/* stop HW scheduler first if it's running */
mac_sched_stop(vdev);
/* rf schedule stop */
mac_rf_sched_stop(rf_vdev);
#if DEBUG_HWQ_SHCED_HANG
pdev->dbg_status = MACC_TX_HANG_STATUS_MAX;
#endif
/* if last beacon period, there's TDMA frame
* not done, then we need to clean them now, or else
* they would be sent in the wrong period
*/
mac_tx_flush_all_tdma_queue(&pdev->hwq_hdl);
/* flush detest beacon for spg */
if (vdev->fb_lid_exist) {
/* check bcsma pending */
mac_tx_flush_bcsma_pending_queue(&pdev->hwq_hdl);
vdev->bcsma_non_exist_cnt = 0;
}
if (rf_pdev) {
/* flush tdma hwq */
mac_rf_tx_flush_all_tdma_queue(&rf_pdev->hwq_hdl);
/* flush csma bcn hwq */
mac_rf_csma_bcn_flush(&rf_pdev->hwq_hdl);
}
if (bcn_ctx->sta.ntb_sync_done == 0) {
/* config HW to sync up the NTB with the preferred network. */
if (bcn_ctx->fc.delta_ntb) {
mac_sched_sync_ntb(vdev, 0, bcn_ctx->fc.delta_ntb);
}
#if MAC_ZC_START_FOLLOW_VDEV
mac_zc_set_func_cmd(vdev->ref_pdev_id, MAC_ZC_FUNC_CMD_NTB_STABLE_NOTIF,
NULL);
#else
mac_zc_set_func_cmd(vdev->ref_pdev_id, MAC_ZC_FUNC_CMD_RESET_HW, NULL);
#endif
bcn_ctx->sta.ntb_sync_done = 1;
} else if (bcn_ctx->sta.force_sw_sync) {
/* config HW to sync up the NTB with the preferred network. */
if (bcn_ctx->fc.delta_ntb) {
mac_sched_sync_ntb(vdev, 0, bcn_ctx->fc.delta_ntb);
}
}
/* if this beacon is simple beacon, need reuse timeslot */
if (bcn_ctx->beacon_component_enable[MAC_BC_BMI_RF_SIMPLE_PARAM]) {
mac_bc_time_slot_t *ts = &vdev->bcn_ctx.time_slot;
mac_bc_simple_param_t *simple_sg =
&vdev->bcn_ctx.sg_uniq_bc_str.simple_param;
mac_bc_simple_param_spg_t *simple_spg =
&vdev->bcn_ctx.spg_uniq_bc_str.simple_param;
uint16_t csma_dur;
uint32_t csma_start_ntb;
if (proto == PLC_PROTO_TYPE_SPG) {
csma_dur = simple_spg->csma_dur;
csma_start_ntb = simple_spg->csma_start_ntb;
} else {
csma_dur = simple_sg->csma_dur;
csma_start_ntb = simple_sg->csma_start_ntb;
}
os_mem_set(ts, 0, sizeof(mac_bc_time_slot_t));
ts->csma_info.phase_cnt = 1;
ts->csma_slot_frag_s = csma_dur;
ts->csma_info.phase[0] = vdev->l_phase1 ? vdev->l_phase1 : PLC_PHASE_A;
ts->csma_info.slot_dur[0] = csma_dur;
ts->bp_start_ntb = csma_start_ntb;
ts->bc_period = csma_dur;
}
curr_ntb = mac_sched_get_ntb64(vdev);
end_ntb = bcn_ctx->time_slot.bp_start_ntb +
MAC_MS_TO_NTB(bcn_ctx->time_slot.bc_period);
if ((end_ntb - iot_uint64_lower32(curr_ntb)) >= 0x7FFFFFFF) {
/* current beacon period is obsolete */
iot_printf("%s bp already expired start_ntb %lu, "
"end_ntb %lu, curr_ntb %lu\n", __FUNCTION__,
bcn_ctx->time_slot.bp_start_ntb, end_ntb,
iot_uint64_lower32(curr_ntb));
if (mac_get_cert_test_flag() && vdev->opposite_3ps) {
bcn_ctx->time_slot.bp_start_ntb = (uint32_t)curr_ntb;
end_ntb = bcn_ctx->time_slot.bp_start_ntb +
MAC_MS_TO_NTB(bcn_ctx->time_slot.bc_period);
goto bc_sched;
}
/* config a csma only command list to enable scheduler */
bcn_ctx->sta.allow_reuse_ts = 0;
mac_sched_set_csma_only(vdev, curr_ntb,
(uint8_t)bcn_ctx->time_slot.allow_reuse);
/* rf csma only schedule set */
mac_rf_sched_set_csma_only(rf_vdev, curr_ntb,
(uint8_t)bcn_ctx->time_slot.allow_reuse);
} else {
bc_sched:
/* apply the next beacon period schedule into HW, at least enable tx
* for local logical phase.
*/
switch (vdev->l_phase1) {
case PLC_PHASE_A:
ent->phase_a_tx = 1;
break;
case PLC_PHASE_B:
ent->phase_b_tx = 1;
break;
case PLC_PHASE_C:
ent->phase_c_tx = 1;
break;
default:
break;
}
bcn_ctx->sta.bc_d_with_non = ent->bc_d_with_non;
/* backup tx phase config */
bcn_ctx->sta.phase_a_tx = ent->phase_a_tx;
bcn_ctx->sta.phase_b_tx = ent->phase_b_tx;
bcn_ctx->sta.phase_c_tx = ent->phase_c_tx;
mac_sched_sta_set(vdev, &vdev->bcn_ctx.time_slot,
bcn_ctx->time_slot.bp_start_ntb, ent->phase_a_tx,
ent->phase_b_tx, ent->phase_c_tx, 1);
/* rf sta schedule set */
sta_tx_type = mac_rf_sched_sta_set(rf_vdev, &vdev->bcn_ctx.time_slot,
bcn_ctx->time_slot.bp_start_ntb, 1);
/* check if a new beacon tx is required for the update beacon
* template. for cco role device, always delay the new beacon tx
* to the periodical beacon phase.
*/
if (ent->tx_req) {
/* for hplc beacon, do not tx beacon on rf only type */
if (!HPLC_RF_SUPPORT || ((BEACON_TX_ONLY_RF != sta_tx_type) &&
!vdev->tx_rx_suspend)) {
/* always use local phase for beacon tx */
vdev->bcn_ctx.fc.phase = vdev->l_phase1;
tx_cnt = mac_beacon_tx(proto, phy_proto_single_band_id_get(),
&vdev->bcn_ctx, vdev->bcn_ctx.mac_beacon_buffer[0]);
#if SUPPORT_SOUTHERN_POWER_GRID
/* need tx detect pkt */
if (MAC_BEACON_IS_DETECT == bcn_ctx->is_tx_detect) {
if (phy_band_id_get() ==
IOT_SUPPORT_TONE_MULTI_BAND021) {
mac_tx_detect_bcn(bcn_ctx);
}
bcn_ctx->is_tx_detect = MAC_BEACON_IS_NORMAL;
}
#endif
}
uint8_t is_csma_tx = 0, is_std_tx = 0, tx_req = 1;
/* tx stardand beacon on HPLC RF type,
* otherwise tx simple beacon
*/
switch (sta_tx_type) {
case BEACON_TX_ONLY_HPLC:
/* do not tx beacon on hplc only type */
tx_req = 0;
break;
case BEACON_TX_ONLY_RF:
/* fix hplc+rf test bed, sta bcast sof process test case fail,
* BEACON_TX_ONLY_RF need send rf stdandard beacon.
*/
is_std_tx = 1;
break;
case BEACON_TX_HPLC_SIMPLE_RF:
case BEACON_TX_HPLC_SIMPLE_RF_SYNC:
is_std_tx = 0;
break;
case BEACON_TX_HPLC_RF:
case BEACON_TX_HPLC_RF_SYNC:
is_std_tx = 1;
break;
case BEACON_TX_HPLC_CSMA_SIMPLE_RF:
is_std_tx = 0;
/* if type is csma simple rf, need tx beacon on csma slot */
is_csma_tx = 1;
break;
default:
iot_printf("%s err type:%lu\n", __FUNCTION__, sta_tx_type);
/* if error type, do not tx beacon */
tx_req = 0;
break;
}
if (rf_vdev && rf_vdev->tx_rx_suspend) {
tx_req = 0;
}
if (tx_req) {
/* mac rf send beacon */
uint32_t ret = mac_rf_assemble_and_send_bcn(proto, vdev,
is_std_tx, is_csma_tx);
if (ret && ret != ERR_NOSUPP) {
iot_printf("rf beacon send fail\n");
}
}
}
}
/* judge hplc slot is exist or not */
if (vdev->bcsma_slot_exist) {
/* exist hplc bcsma slot, not care */
vdev->bcsma_non_exist_cnt = 0;
} else {
/* do not exist bcsma slot */
vdev->bcsma_non_exist_cnt++;
if (vdev->bcsma_non_exist_cnt > BCSMA_NON_EXIST_PD_CNT) {
vdev->bcsma_non_exist_cnt = 0;
mac_tx_flush_bcsma_pending_queue(&pdev->hwq_hdl);
}
}
if (rf_vdev) {
/* judge rf slot is exist or not */
if (rf_vdev->bcsma_slot_exist) {
/* exist rf bcsma slot, not care */
rf_vdev->bcsma_non_exist_cnt = 0;
} else {
/* do not exist bcsma slot */
rf_vdev->bcsma_non_exist_cnt++;
if (rf_vdev->bcsma_non_exist_cnt > BCSMA_NON_EXIST_PD_CNT) {
rf_vdev->bcsma_non_exist_cnt = 0;
mac_rf_tx_flush_bcsma_pending_queue(&rf_pdev->hwq_hdl);
}
}
}
return tx_cnt;
}
uint32_t mac_beacon_init(mac_beacon_ctx_t *mac_beacon, void *vdev_ptr)
{
mac_vdev_t *vdev = vdev_ptr;
uint8_t i, j;
if (mac_beacon->inited) {
return ERR_INVAL;
}
for (i = 0; i < vdev->mac_vdev_cfg.p_phase_cnt; i++) {
/* TODO: check the alloc size and resv len */
mac_beacon->mac_beacon_buffer[i] = iot_pkt_alloc(520,
PLC_MAC_BEACON_MID);
if (mac_beacon->mac_beacon_buffer[i] == NULL) {
for (j = 0; j < i; j++) {
iot_pkt_free(mac_beacon->mac_beacon_buffer[j]);
mac_beacon->mac_beacon_buffer[j] = NULL;
}
return ERR_NOMEM;
}
/* bcn tx no need to reserve any space,
* we put all after the first byte :
* FC + BCN PB payload + PB CRC
*/
iot_pkt_reserve(mac_beacon->mac_beacon_buffer[i], 0);
iot_pkt_put(mac_beacon->mac_beacon_buffer[i], 520);
}
uint32_t ret = mac_rf_beacon_init(mac_beacon);
if (!ret) {
iot_printf("mac rf beacon success!\n");
}
mac_beacon->ref_vdev_ptr = vdev_ptr;
mac_beacon->inited = 1;
/* enable/disable force sw ntb sync feature */
mac_beacon->sta.force_sw_sync = !(PLC_ENABLE_HW_NTB_SYNC);
mac_beacon->sta.bc_d_with_non = 0;
return 0;
}
/* reset the beacon ctx */
uint32_t mac_beacon_reset(mac_beacon_ctx_t *mac_beacon)
{
uint32_t proto = PHY_PROTO_TYPE_GET();
/* get beacon info */
mac_bc_ent_str_info_t bc_ent_str = { 0 };
mac_beacon_uniq_info_get(proto, mac_beacon, &bc_ent_str);
IOT_ASSERT(bc_ent_str.plh_str_ptr &&
bc_ent_str.rt_param_str_ptr &&
bc_ent_str.sta_cap_str_ptr);
mac_beacon->nid_inited = 0;
mac_beacon->entry_sort_cnt = 0;
mac_beacon->unknown_entry = NULL;
os_mem_set(&mac_beacon->beacon_component_enable, 0,
sizeof(mac_beacon->beacon_component_enable));
os_mem_set(&mac_beacon->fc, 0, sizeof(mac_beacon->fc));
os_mem_set(bc_ent_str.plh_str_ptr, 0,
bc_ent_str.plh_str_size);
os_mem_set(bc_ent_str.sta_cap_str_ptr, 0, bc_ent_str.sta_cap_str_size);
os_mem_set(bc_ent_str.rt_param_str_ptr, 0,
bc_ent_str.rt_param_str_size);
os_mem_set(bc_ent_str.simple_param_str_ptr, 0,
bc_ent_str.simple_param_str_size);
os_mem_set(&mac_beacon->freq_chg, 0, sizeof(mac_beacon->freq_chg));
os_mem_set(&mac_beacon->rf_chg, 0, sizeof(mac_beacon->rf_chg));
os_mem_set(&mac_beacon->rf_route, 0, sizeof(mac_beacon->rf_route));
os_mem_set(&mac_beacon->time_slot, 0, sizeof(mac_beacon->time_slot));
os_mem_set(&mac_beacon->meter, 0, sizeof(mac_beacon->meter));
os_mem_set(&mac_beacon->fb_detect, 0, sizeof(mac_beacon->fb_detect));
os_mem_set(&mac_beacon->rtc, 0, sizeof(mac_beacon->rtc));
os_mem_set(&mac_beacon->sta, 0, sizeof(mac_beacon->sta));
os_mem_set(mac_beacon->entry_sort, 0, sizeof(mac_beacon->entry_sort));
/* enable/disable force sw ntb sync feature */
mac_beacon->sta.force_sw_sync = !(PLC_ENABLE_HW_NTB_SYNC);
mac_beacon->sta.bc_d_with_non = 0;
mac_beacon_cco_reset(mac_beacon);
return 0;
}
#if SUPPORT_SMART_GRID
void mac_beacon_fill_buf_sg(mac_beacon_ctx_t *bcn, uint8_t **tmp)
{
uint8_t *p_unknown;
uint16_t unknown_len;
/* fill in FC */
frame_control_t *fc = (frame_control_t*)(*tmp);
(*tmp) += sizeof(frame_control_t);
if (bcn->beacon_component_enable[MAC_BC_FC_INFO]) {
fc->delimiter_type = FC_DELIM_BEACON;
fc->network_type = bcn->fc.net_type;
fc->nid = bcn->fc.nid;
if (bcn->fc.is_rf) {
fc->vf.rf_bcn.time_stamp =
mac_sched_get_ntb((mac_vdev_t *)bcn->ref_vdev_ptr);
fc->vf.rf_bcn.src_tei = vdev_get_tei(bcn->ref_vdev_ptr);
} else {
fc->vf.bcn.time_stamp =
mac_sched_get_ntb((mac_vdev_t *)bcn->ref_vdev_ptr);
#if (MAC_SCHED_DEBUG || RUNTIME_DEBUG)
iot_printf("%s curr ntb:%lu, start ntb %lu, nid %lu phase %lu\n",
__FUNCTION__, fc->vf.bcn.time_stamp,
bcn->time_slot.bp_start_ntb, bcn->fc.nid, bcn->fc.phase);
iot_dbglog_input(PLC_MAC_BEACON_MID, DBGLOG_INFO,
IOT_MAC_BEACON_TX_NTB_INFO, 4, fc->vf.bcn.time_stamp,
bcn->time_slot.bp_start_ntb, bcn->fc.nid, bcn->fc.phase);
#endif
fc->vf.bcn.src_tei = vdev_get_tei(bcn->ref_vdev_ptr);
fc->vf.bcn.sym_num = 0; /* filled by HW */
fc->vf.bcn.phase_num = bcn->fc.phase;
}
} else {
IOT_ASSERT(0);
}
/* fill in beacon payload fix header */
beacon_payload_std_header_t *plh =
(beacon_payload_std_header_t *)(*tmp);
(*tmp) += sizeof(beacon_payload_std_header_t);
/* updaet MAC_BC_FIX_P */
if (bcn->beacon_component_enable[MAC_BC_FIX_P]) {
plh->fixed_hdr.beacon_type = bcn->sg_uniq_bc_str.payload_header.type;
plh->fixed_hdr.sg_forming_complete =
bcn->sg_uniq_bc_str.payload_header.assoc_done;
plh->fixed_hdr.allow_assoc =
bcn->sg_uniq_bc_str.payload_header.allow_assoc;
plh->fixed_hdr.allow_chan_eval =
bcn->sg_uniq_bc_str.payload_header.allow_chan_eval;
plh->fixed_hdr.sg_forming_cnt =
bcn->sg_uniq_bc_str.payload_header.network_sn;
plh->fixed_hdr.beacon_seq_num =
bcn->sg_uniq_bc_str.payload_header.bc_period_cnt;
plh->fixed_hdr.simple_beacon =
bcn->sg_uniq_bc_str.payload_header.simple_beacon;
plh->fixed_hdr.auth_enable =
(uint8_t)bcn->sg_uniq_bc_str.payload_header.auth_enable;
iot_mac_addr_cpy(plh->fixed_hdr.cco_mac_addr,
bcn->sg_uniq_bc_str.payload_header.cco_addr);
plh->rf_channel = bcn->sg_uniq_bc_str.payload_header.rf_channel;
plh->rf_option = bcn->sg_uniq_bc_str.payload_header.rf_option;
plh->encrypt_mode = bcn->sg_uniq_bc_str.payload_header.encrypt_mode;
plh->cek_seq = bcn->sg_uniq_bc_str.payload_header.cek_seq;
plh->encrypt_algo = bcn->sg_uniq_bc_str.payload_header.encrypt_algo;
plh->rsvd1 = bcn->sg_uniq_bc_str.payload_header.used_rsvd1;
plh->rsvd2 = bcn->sg_uniq_bc_str.payload_header.used_rsvd2;
/* entry count will be filled in later */
plh->beacon_entry_num = 0;
} else {
IOT_ASSERT(0);
}
/* fill in the beacon control info, CCO itself manage bcn entries fill
* order, while STA follow CCO's behavior
*/
if (PLC_DEV_ROLE_CCO == mac_vdev_cfg_get_node_role(
(mac_vdev_t *)bcn->ref_vdev_ptr)) {
os_mem_set(bcn->entry_sort, 0x00, sizeof(bcn->entry_sort));
bcn->entry_sort_cnt = 8;
bcn->entry_sort[0] = MAC_BCN_TYPE_ID_STA_CAP;
bcn->entry_sort[1] = MAC_BCN_TYPE_ID_RT_PARAM;
bcn->entry_sort[2] = MAC_BCN_TYPE_ID_FREQ_CHQ;
bcn->entry_sort[3] = MAC_BCN_TYPE_ID_RF_CHANNEL_CHQ;
bcn->entry_sort[4] = MAC_BCN_TYPE_ID_RF_ROUTE;
bcn->entry_sort[5] = MAC_BCN_TYPE_ID_RTC;
bcn->entry_sort[6] = MAC_BCN_TYPE_ID_VENDOR_SPEC;
bcn->entry_sort[7] = MAC_BCN_TYPE_ID_TIME_SLOT;
}
for (uint8_t k = 0; k < bcn->entry_sort_cnt; k++) {
switch (bcn->entry_sort[k])
{
case MAC_BCN_TYPE_ID_STA_CAP:
{
/* fill in sta cap */
beacon_entry_sta_cap_t *cap = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_STA_CAP]) {
plh->beacon_entry_num++;
cap = (beacon_entry_sta_cap_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_sta_cap_t);
cap->beacon_entry_type = MAC_BCN_TYPE_ID_STA_CAP;
cap->beacon_entry_len = sizeof(*cap);
cap->tei = bcn->sg_uniq_bc_str.sta_cap.tei;
cap->pco_tei = bcn->sg_uniq_bc_str.sta_cap.proxy;
iot_mac_addr_cpy(cap->src_mac_addr,
bcn->sg_uniq_bc_str.sta_cap.addr);
cap->reach_rate_to_cco =
bcn->sg_uniq_bc_str.sta_cap.min_ul_dl_sr;
cap->node_role = bcn->sg_uniq_bc_str.sta_cap.role;
cap->node_level = bcn->sg_uniq_bc_str.sta_cap.level;
cap->snr_to_pco = bcn->sg_uniq_bc_str.sta_cap.snr;
cap->phase = bcn->sg_uniq_bc_str.sta_cap.phase;
cap->rf_hop = bcn->sg_uniq_bc_str.sta_cap.rf_hop;
cap->rsvd = bcn->sg_uniq_bc_str.sta_cap.used_rsvd;
}
break;
}
case MAC_BCN_TYPE_ID_RT_PARAM:
{
/* fill in the routing info */
beacon_entry_route_t *prt = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_RT_PARAM]) {
plh->beacon_entry_num++;
prt = (beacon_entry_route_t*)(*tmp);
(*tmp) += sizeof(beacon_entry_route_t);
prt->beacon_entry_type = MAC_BCN_TYPE_ID_RT_PARAM;
prt->beacon_entry_len = sizeof(*prt);
prt->routing_update_intval =
bcn->sg_uniq_bc_str.route_param.rt_period;
prt->next_update_countdown =
bcn->sg_uniq_bc_str.route_param.rt_left_period;
prt->pco_discover_list_intval =
bcn->sg_uniq_bc_str.route_param.p_dis_period;
prt->sta_discover_list_intval =
bcn->sg_uniq_bc_str.route_param.s_dis_period;
}
break;
}
case MAC_BCN_TYPE_ID_FREQ_CHQ:
{
/* fill in the freq change info */
beacon_entry_freq_change_t *fqc = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_FREQ_CHG]) {
plh->beacon_entry_num++;
fqc = (beacon_entry_freq_change_t*)(*tmp);
(*tmp) += sizeof(beacon_entry_freq_change_t);
fqc->beacon_entry_type = MAC_BCN_TYPE_ID_FREQ_CHQ;
fqc->beacon_entry_len = sizeof(*fqc);
fqc->target_freq = bcn->freq_chg.targer_freq;
fqc->change_countdown = bcn->freq_chg.time_left;
}
break;
}
case MAC_BCN_TYPE_ID_RF_CHANNEL_CHQ:
{
/* fill in the rf channel change info */
beacon_entry_rf_channel_chg_t *rf_channel = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_RF_CHANNEL_CHG]) {
plh->beacon_entry_num++;
rf_channel = (beacon_entry_rf_channel_chg_t*)(*tmp);
(*tmp) += sizeof(beacon_entry_rf_channel_chg_t);
rf_channel->beacon_entry_type =
MAC_BCN_TYPE_ID_RF_CHANNEL_CHQ;
rf_channel->beacon_entry_len = sizeof(*rf_channel);
rf_channel->target_rf = bcn->rf_chg.target_rf_channel;
rf_channel->target_option = bcn->rf_chg.target_rf_option;
rf_channel->time_left = bcn->rf_chg.time_left;
rf_channel->rsvd = bcn->rf_chg.used_rsvd;
}
break;
}
case MAC_BCN_TYPE_ID_RF_ROUTE:
{
/* fill in the rf route param info */
beacon_entry_rf_route_t *rf_route = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_RF_ROUTE]) {
plh->beacon_entry_num++;
rf_route = (beacon_entry_rf_route_t*)(*tmp);
(*tmp) += sizeof(beacon_entry_rf_route_t);
rf_route->beacon_entry_type = MAC_BCN_TYPE_ID_RF_ROUTE;
rf_route->beacon_entry_len = sizeof(*rf_route);
rf_route->rf_dis_period = bcn->rf_route.rf_dis_period;
rf_route->rf_age_period = bcn->rf_route.rf_age_period;
}
break;
}
case MAC_BCN_TYPE_ID_RTC:
{
/* fill in the rtc info */
beacon_entry_rtc_t *rtc = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_RTC]) {
plh->beacon_entry_num++;
rtc = (beacon_entry_rtc_t*)(*tmp);
(*tmp) += sizeof(beacon_entry_rtc_t);
rtc->beacon_entry_type = MAC_BCN_TYPE_ID_RTC;
rtc->beacon_entry_len = sizeof(*rtc);
rtc->cco_date = bcn->rtc.cco_date;
rtc->cco_ntb = bcn->rtc.cco_ntb;
}
break;
}
case MAC_BCN_TYPE_ID_TIME_SLOT:
{
/* fill in the time slot info */
beacon_entry_time_slot_alloc_t *pts = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_TIME_SLOT]) {
plh->beacon_entry_num++;
pts = (beacon_entry_time_slot_alloc_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_time_slot_alloc_t);
pts->beacon_entry_type = MAC_BCN_TYPE_ID_TIME_SLOT;
/* bcn entry len need to be calculated later */
/* fixed len area */
pts->total_slot_non_cco_beacon =
bcn->time_slot.non_cco_bc_info.bc_cnt;
pts->total_slot_cco_beacon =
bcn->time_slot.cco_bc_cnt;
pts->csma_phase_num =
bcn->time_slot.csma_info.phase_cnt;
pts->total_slot_pco_beacon =
bcn->time_slot.proxy_bc_cnt;
pts->beacon_slot_period =
bcn->time_slot.bc_slot_dur; /* unit ms */
/* unit 10ms */
pts->csma_slot_period =
(uint8_t)(bcn->time_slot.csma_slot_frag_s / 10);
pts->bind_csma_phase_num =
bcn->time_slot.d_csma_info.phase_cnt; /* 1-3 */
pts->bind_csma_lid =
bcn->time_slot.d_csma_lid;
pts->tdma_period =
bcn->time_slot.tdma_slot_dur; /* unit ms */
pts->tdma_lid =
bcn->time_slot.tdma_lid;
pts->cur_beacon_timestamp =
bcn->time_slot.bp_start_ntb;
pts->beacon_period =
bcn->time_slot.bc_period; /* unit ms */
pts->rf_bc_slot_period =
(uint16_t)bcn->time_slot.rf_bc_slot_dur; /* unit ms */
pts->rsvd1 = (uint16_t)bcn->time_slot.sg_used_rsvd1;
pts->rsvd2 = (uint16_t)bcn->time_slot.sg_used_rsvd2;
/* non cco beacon area */
if (bcn->sg_uniq_bc_str.payload_header.type !=
PLC_BC_TYPE_D || bcn->sta.bc_d_with_non) {
/* skip beacon slot detail for discovery beacon */
for (int i = 0; i <
bcn->time_slot.non_cco_bc_info.bc_cnt; i++) {
sub_beacon_entry_non_cco_beacon_t *pnc =
(sub_beacon_entry_non_cco_beacon_t*)(*tmp);
(*tmp) += sizeof(*pnc);
pnc->tei_to_send =
bcn->time_slot.non_cco_bc_info.sta[i].tei;
pnc->beacon_type =
bcn->time_slot.non_cco_bc_info.sta[i].type;
pnc->tx_flag =
bcn->time_slot.non_cco_bc_info.sta[i].tx_flag;
}
}
/* csma time slot area */
for (int i = 0; i < bcn->time_slot.csma_info.phase_cnt;
i++) {
sub_beacon_entry_csma_slot_t *pct =
(sub_beacon_entry_csma_slot_t*)(*tmp);
(*tmp) += sizeof(*pct);
pct->csma_period = bcn->time_slot.csma_info.slot_dur[i];
pct->phase = bcn->time_slot.csma_info.phase[i];
pct->resv = bcn->time_slot.csma_info.used_rsvd[i];
}
/* bind csma time slot area */
for (int i = 0; i < bcn->time_slot.d_csma_info.phase_cnt;
i++) {
sub_beacon_entry_bind_csma_slot_t *pbc =
(sub_beacon_entry_bind_csma_slot_t*)(*tmp);
(*tmp) += sizeof(*pbc);
pbc->bind_csma_period =
bcn->time_slot.d_csma_info.slot_dur[i];
pbc->phase = bcn->time_slot.d_csma_info.phase[i];
pbc->resv = bcn->time_slot.d_csma_info.used_rsvd[i];
}
/* recal the total len, exclude header len */
pts->beacon_entry_len = (uint16_t)((*tmp) - (uint8_t*)pts);
}
break;
}
case MAC_BCN_TYPE_ID_VENDOR_SPEC:
{
/* fill in the vendor specific info */
beacon_entry_vendor_spec_t *vendor = NULL;
beacon_entry_vendor_roam_t *vendor_roam = NULL;
beacon_entry_vendor_data_t *vendor_data = NULL;
beacon_entry_vendor_debug_t *vendor_debug = NULL;
beacon_entry_vendor_tsfm_t *vendor_tsfm = NULL;
beacon_entry_vendor_security_t *vendor_sec = NULL;
beacon_entry_vendor_rf_t *vendor_rf = NULL;
/* check vendor app data size */
BUILD_BUG_ON(MAC_BC_APP_DATA_MAX == sizeof(vendor_data->data));
if (bcn->beacon_component_enable[MAC_BC_BMI_VENDOR_SPEC]) {
plh->beacon_entry_num++;
vendor = (beacon_entry_vendor_spec_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_spec_t);
os_mem_set(vendor, 0, sizeof(*vendor));
vendor->beacon_entry_type = MAC_BCN_TYPE_ID_VENDOR_SPEC;
vendor->beacon_entry_len = sizeof(*vendor);
vendor->power = bcn->vendor.power;
vendor->allowed_cco_tf_sr = bcn->vendor.allowed_cco_tf_sr;
vendor->proxy_select_dur = bcn->vendor.proxy_select_dur;
vendor->fixed_rate = bcn->vendor.fixed_rate;
vendor->pco_snr_rpt = bcn->vendor.pco_snr_rpt;
vendor->dm_tx_cfg = bcn->vendor.dm_tx_cfg;
vendor->cco_debug = bcn->vendor.cco_debug;
vendor->vendor_id = bcn->vendor.vendor_id;
if (bcn->vendor.th_data_valid) {
plh->beacon_entry_num++;
/* add roaming related vendor entry */
vendor_roam = (beacon_entry_vendor_roam_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_roam_t);
os_mem_set(vendor_roam, 0, sizeof(*vendor_roam));
vendor_roam->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_ROAM;
vendor_roam->beacon_entry_len = sizeof(*vendor_roam);
vendor_roam->sta_proxy_weight_rank =
bcn->vendor.sta_proxy_weight_rank;
vendor_roam->sta_proxy_good_tf_sr_th =
bcn->vendor.sta_proxy_good_tf_sr_th;
vendor_roam->sta_roaming_gap_h =
bcn->vendor.sta_roaming_gap_h;
vendor_roam->sta_roaming_gap_l =
bcn->vendor.sta_roaming_gap_l;
vendor_roam->cco_phase_check_tf_sr_th =
bcn->vendor.cco_phase_check_tf_sr_th;
vendor_roam->cco_phase_gap_own_h =
bcn->vendor.cco_phase_gap_own_h;
vendor_roam->cco_phase_gap_own_l =
bcn->vendor.cco_phase_gap_own_l;
vendor_roam->cco_phase_gap_other =
bcn->vendor.cco_phase_gap_other;
vendor_roam->level_score_h_th =
bcn->vendor.level_score_h_th;
vendor_roam->level_score_h =
bcn->vendor.level_score_h;
vendor_roam->level_score_l =
bcn->vendor.level_score_l;
vendor_roam->cco_good_tf_sr_th =
bcn->vendor.cco_good_tf_sr_th;
vendor_roam->cco_good_tx_sr_th =
bcn->vendor.cco_good_tx_sr_th;
vendor_roam->cco_good_rx_sr_th =
bcn->vendor.cco_good_rx_sr_th;
vendor_roam->pco_good_tf_sr_th =
bcn->vendor.pco_good_tf_sr_th;
vendor_roam->pco_good_tx_sr_th =
bcn->vendor.pco_good_tx_sr_th;
vendor_roam->pco_good_rx_sr_th =
bcn->vendor.pco_good_rx_sr_th;
vendor_roam->clamber_tf_sr_th =
bcn->vendor.clamber_tf_sr_th;
vendor_roam->clamber_target_tf_sr_th =
bcn->vendor.clamber_target_tf_sr_th;
vendor_roam->proxy_tf_sr_rank =
bcn->vendor.proxy_tf_sr_rank;
vendor_roam->roam_learn_cnt =
bcn->vendor.roam_learn_cnt;
}
if (bcn->vendor.app_data_valid) {
plh->beacon_entry_num++;
/* add app data related vendor entry */
vendor_data = (beacon_entry_vendor_data_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_data_t);
os_mem_set(vendor_data, 0, sizeof(*vendor_data));
vendor_data->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_DATA;
vendor_data->beacon_entry_len = sizeof(*vendor_data);
os_mem_cpy(vendor_data->data, bcn->vendor.app_data,
sizeof(bcn->vendor.app_data));
}
if (bcn->vendor.addr_valid) {
plh->beacon_entry_num++;
/* add debug related vendor entry */
vendor_debug = (beacon_entry_vendor_debug_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_debug_t);
os_mem_set(vendor_debug, 0, sizeof(*vendor_debug));
vendor_debug->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_DEBUG;
vendor_debug->beacon_entry_len = sizeof(*vendor_debug);
iot_mac_addr_cpy(vendor_debug->addr, bcn->vendor.addr);
}
if (bcn->vendor.tsfm_valid) {
plh->beacon_entry_num++;
/* add tsfm related vendor entry */
vendor_tsfm = (beacon_entry_vendor_tsfm_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_tsfm_t);
os_mem_set(vendor_tsfm, 0, sizeof(*vendor_tsfm));
vendor_tsfm->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_TSFM;
vendor_tsfm->beacon_entry_len = sizeof(*vendor_tsfm);
vendor_tsfm->rpt_tsfm_dur = bcn->vendor.rpt_tsfm_dur;
vendor_tsfm->tsfm_algorithm =
bcn->vendor.tsfm_algorithm;
vendor_tsfm->tsfm_cco_detect_en =
bcn->vendor.tsfm_cco_detect_en;
vendor_tsfm->tsfm_low_snr_th =
bcn->vendor.tsfm_low_snr_th;
vendor_tsfm->tsfm_snr_stat_high_th =
bcn->vendor.tsfm_snr_stat_high_th;
vendor_tsfm->check_tsfm_dur =
bcn->vendor.check_tsfm_dur;
vendor_tsfm->tsfm_snr_diff_th1 =
bcn->vendor.tsfm_snr_diff_th1;
vendor_tsfm->tsfm_snr_diff_th2 =
bcn->vendor.tsfm_snr_diff_th2;
vendor_tsfm->tsfm_level_big_diff_th =
bcn->vendor.tsfm_level_big_diff_th;
vendor_tsfm->tsfm_cco_low_snr_th =
bcn->vendor.tsfm_cco_low_snr_th;
vendor_tsfm->tsfm_cco_snr_penal =
bcn->vendor.tsfm_cco_snr_penal;
vendor_tsfm->tsfm_cco_diff_th1 =
bcn->vendor.tsfm_cco_diff_th1;
vendor_tsfm->tsfm_cco_diff_th2 =
bcn->vendor.tsfm_cco_diff_th2;
vendor_tsfm->tsfm_zc_diff_th1 =
bcn->vendor.tsfm_zc_diff_th1;
vendor_tsfm->tsfm_zc_diff_th2 =
bcn->vendor.tsfm_zc_diff_th2;
vendor_tsfm->tsfm_zc_diff_th3 =
bcn->vendor.tsfm_zc_diff_th3;
vendor_tsfm->tsfm_zc_diff_th4 =
bcn->vendor.tsfm_zc_diff_th4;
vendor_tsfm->tsfm_snr_bc_factor =
bcn->vendor.tsfm_snr_bc_factor;
vendor_tsfm->tsfm_snr_sof_factor =
bcn->vendor.tsfm_snr_sof_factor;
}
if (bcn->vendor.passcode_valid) {
plh->beacon_entry_num++;
/* add security related vendor entry */
vendor_sec = (beacon_entry_vendor_security_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_security_t);
os_mem_set(vendor_sec, 0, sizeof(*vendor_sec));
vendor_sec->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_SECURITY;
vendor_sec->beacon_entry_len = sizeof(*vendor_sec);
vendor_sec->passcode = bcn->vendor.passcode;
}
if (bcn->vendor.rf_power_valid ||
bcn->vendor.force_link_valid) {
plh->beacon_entry_num++;
/* add rf related vendor entry */
vendor_rf = (beacon_entry_vendor_rf_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_rf_t);
os_mem_set(vendor_rf, 0, sizeof(*vendor_rf));
vendor_rf->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_RF;
vendor_rf->beacon_entry_len = sizeof(*vendor_rf);
vendor_rf->rf_power = bcn->vendor.rf_power;
vendor_rf->rf_power_valid = bcn->vendor.rf_power_valid;
vendor_rf->force_link_valid = bcn->vendor.force_link_valid;
vendor_rf->force_rf_link = bcn->vendor.force_rf_link;
}
}
break;
}
case MAC_BCN_TYPE_ID_UNKNOWN:
{
/* fill in unknown entry info */
if (bcn->beacon_component_enable[MAC_BC_BMI_UNKNOWN] &&
bcn->unknown_entry && iot_pkt_data_len(bcn->unknown_entry)) {
plh->beacon_entry_num++;
p_unknown = iot_pkt_data(bcn->unknown_entry);
if (get_bcn_entry_hdr_len(p_unknown[0]) == 3) {
unknown_len = ((uint16_t)p_unknown[2]) << 8;
unknown_len |= p_unknown[1];
} else {
unknown_len = p_unknown[1];
}
os_mem_cpy(*tmp, p_unknown, unknown_len);
(*tmp) += unknown_len;
iot_pkt_pull(bcn->unknown_entry, unknown_len);
}
break;
}
default:
IOT_ASSERT(0);
break;
}
}
}
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
void mac_beacon_fill_buf_spg(mac_beacon_ctx_t *bcn, uint8_t **tmp,
bool_t is_detect)
{
uint8_t *p_unknown;
uint16_t unknown_len;
/* fill in FC */
spg_frame_control_t *spg_fc = (spg_frame_control_t*)(*tmp);
uint32_t ts;
(*tmp) += sizeof(spg_frame_control_t);
if (bcn->beacon_component_enable[MAC_BC_FC_INFO]) {
spg_fc->delimiter_type = FC_DELIM_BEACON;
spg_fc->access_ind = bcn->fc.net_type;
spg_fc->snid = (uint8_t)bcn->fc.nid;
ts = mac_sched_get_ntb((mac_vdev_t *)bcn->ref_vdev_ptr);
if (bcn->fc.is_rf) {
spg_fc->vf.rf_bcn.time_stamp = ts;
spg_fc->vf.rf_bcn.src_tei = vdev_get_tei(bcn->ref_vdev_ptr);
spg_fc->vf.rf_bcn.bcn_period_cnt = bcn->fc.bp_cnt;
} else {
spg_fc->vf.bcn.time_stamp = ts;
spg_fc->vf.bcn.bcn_period_cnt = bcn->fc.bp_cnt;
spg_fc->vf.bcn.src_tei = vdev_get_tei(bcn->ref_vdev_ptr);
spg_fc->vf.bcn.sym_num = 0; /* filled by HW */
spg_fc->vf.bcn.phase_num = bcn->fc.phase;
}
#if (MAC_SCHED_DEBUG || RUNTIME_DEBUG)
iot_printf("%s curr ntb:%lu, start ntb %lu, nid %lu phase %lu\n",
__FUNCTION__, ts, bcn->time_slot.bp_start_ntb, bcn->fc.nid,
bcn->fc.phase);
iot_dbglog_input(PLC_MAC_BEACON_MID, DBGLOG_INFO,
IOT_MAC_BEACON_TX_NTB_INFO, 4, ts, bcn->time_slot.bp_start_ntb,
bcn->fc.nid, bcn->fc.phase);
#endif
} else {
IOT_ASSERT(0);
}
/* fill in beacon payload fix header */
spg_beacon_payload_std_header_t *plh =
(spg_beacon_payload_std_header_t *)(*tmp);
(*tmp) += sizeof(spg_beacon_payload_std_header_t);
if (bcn->beacon_component_enable[MAC_BC_FIX_P]) {
plh->fixed_hdr.beacon_type = bcn->spg_uniq_bc_str.payload_header.type;
plh->fixed_hdr.spg_forming_complete =
bcn->spg_uniq_bc_str.payload_header.assoc_done;
plh->fixed_hdr.allow_assoc =
bcn->spg_uniq_bc_str.payload_header.allow_assoc;
plh->fixed_hdr.multi_select_func_swt =
bcn->spg_uniq_bc_str.payload_header.multi_select;
plh->fixed_hdr.spg_forming_sn =
bcn->spg_uniq_bc_str.payload_header.network_sn;
plh->short_network_id =
bcn->spg_uniq_bc_str.payload_header.short_network_id;
plh->fixed_hdr.simple_beacon =
bcn->spg_uniq_bc_str.payload_header.simple_beacon;
plh->rf_channel = bcn->spg_uniq_bc_str.payload_header.rf_channel;
plh->rf_option = bcn->spg_uniq_bc_str.payload_header.rf_option;
plh->rsvd1 = bcn->spg_uniq_bc_str.payload_header.used_rsvd1;
plh->rsvd2 = bcn->spg_uniq_bc_str.payload_header.used_rsvd2;
/* entry count will be filled in later */
plh->beacon_entry_num = 0;
} else {
IOT_ASSERT(0);
}
/* fill in the beacon control info, CCO itself manage bcn entries fill
* order, while STA follow CCO's behavior
*/
if (PLC_DEV_ROLE_CCO == mac_vdev_cfg_get_node_role(
(mac_vdev_t *)bcn->ref_vdev_ptr)) {
os_mem_set(bcn->entry_sort, 0x00, sizeof(bcn->entry_sort));
bcn->entry_sort_cnt = 10;
bcn->entry_sort[0] = SPG_MAC_BCN_TYPE_ID_STA_CAP;
bcn->entry_sort[1] = SPG_MAC_BCN_TYPE_ID_RT_PARAM;
bcn->entry_sort[2] = SPG_MAC_BCN_TYPE_ID_FREQ_CHQ;
bcn->entry_sort[3] = SPG_MAC_BCN_TYPE_ID_RF_CHANNEL_CHQ;
bcn->entry_sort[4] = SPG_MAC_BCN_TYPE_ID_RF_ROUTE;
bcn->entry_sort[5] = SPG_MAC_BCN_TYPE_ID_METER;
bcn->entry_sort[6] = SPG_MAC_BCN_TYPE_ID_FB_DETECT;
bcn->entry_sort[7] = SPG_MAC_BCN_TYPE_ID_RTC;
bcn->entry_sort[8] = MAC_BCN_TYPE_ID_VENDOR_SPEC;
bcn->entry_sort[9] = SPG_MAC_BCN_TYPE_ID_TIME_SLOT;
}
for (uint8_t k = 0; k < bcn->entry_sort_cnt; k++) {
switch (bcn->entry_sort[k])
{
case SPG_MAC_BCN_TYPE_ID_STA_CAP:
{
/* fill in sta cap */
spg_beacon_entry_sta_cap_t *cap = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_STA_CAP]) {
plh->beacon_entry_num++;
cap = (spg_beacon_entry_sta_cap_t *)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_sta_cap_t);
cap->beacon_entry_type = SPG_MAC_BCN_TYPE_ID_STA_CAP;
cap->beacon_entry_len = sizeof(*cap);
cap->tei = bcn->spg_uniq_bc_str.sta_cap.tei;
cap->pco_tei = bcn->spg_uniq_bc_str.sta_cap.proxy;
cap->reach_rate_to_cco =
bcn->spg_uniq_bc_str.sta_cap.min_ul_dl_sr;
cap->node_role = bcn->spg_uniq_bc_str.sta_cap.role;
cap->node_level = bcn->spg_uniq_bc_str.sta_cap.level;
cap->phase = bcn->spg_uniq_bc_str.sta_cap.phase;
cap->bcn_used_flag =
bcn->spg_uniq_bc_str.sta_cap.allow_chan_eval;
iot_mac_addr_cpy(cap->src_mac_addr,
bcn->spg_uniq_bc_str.sta_cap.addr);
cap->rf_hop = bcn->spg_uniq_bc_str.sta_cap.rf_hop;
cap->rsvd = bcn->spg_uniq_bc_str.sta_cap.used_rsvd;
}
break;
}
case SPG_MAC_BCN_TYPE_ID_RT_PARAM:
{
/* fill in the routing info */
spg_beacon_entry_route_t *prt = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_RT_PARAM]) {
plh->beacon_entry_num++;
prt = (spg_beacon_entry_route_t*)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_route_t);
prt->beacon_entry_type = SPG_MAC_BCN_TYPE_ID_RT_PARAM;
prt->beacon_entry_len = sizeof(*prt);
prt->routing_update_intval =
bcn->spg_uniq_bc_str.route_param.rt_period;
prt->next_update_countdown =
bcn->spg_uniq_bc_str.route_param.rt_left_period;
prt->rsvd1 = bcn->spg_uniq_bc_str.route_param.used_rsvd1;
os_mem_cpy(prt->rsvd2,
bcn->spg_uniq_bc_str.route_param.used_rsvd2,
sizeof(prt->rsvd2));
iot_mac_addr_cpy(prt->cco_mac_addr,
bcn->spg_uniq_bc_str.route_param.cco_addr);
}
break;
}
case SPG_MAC_BCN_TYPE_ID_FREQ_CHQ:
{
/* fill in the freq change info */
spg_beacon_entry_freq_change_t *fqc = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_FREQ_CHG]) {
plh->beacon_entry_num++;
fqc = (spg_beacon_entry_freq_change_t*)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_freq_change_t);
fqc->beacon_entry_type = SPG_MAC_BCN_TYPE_ID_FREQ_CHQ;
fqc->beacon_entry_len = sizeof(*fqc);
fqc->target_freq = bcn->freq_chg.targer_freq;
fqc->change_countdown = bcn->freq_chg.time_left;
}
break;
}
case SPG_MAC_BCN_TYPE_ID_RF_CHANNEL_CHQ:
{
/* fill in the rf channel change info */
spg_beacon_entry_rf_channel_chg_t *rf_channel = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_RF_CHANNEL_CHG]) {
plh->beacon_entry_num++;
rf_channel = (spg_beacon_entry_rf_channel_chg_t*)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_rf_channel_chg_t);
rf_channel->beacon_entry_type =
SPG_MAC_BCN_TYPE_ID_RF_CHANNEL_CHQ;
rf_channel->beacon_entry_len = sizeof(*rf_channel);
rf_channel->target_rf = bcn->rf_chg.target_rf_channel;
rf_channel->target_option = bcn->rf_chg.target_rf_option;
rf_channel->time_left = bcn->rf_chg.time_left;
rf_channel->rsvd = bcn->rf_chg.used_rsvd;
}
break;
}
case SPG_MAC_BCN_TYPE_ID_RF_ROUTE:
{
/* fill in the rf route param info */
spg_beacon_entry_rf_route_t *rf_route = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_RF_ROUTE]) {
plh->beacon_entry_num++;
rf_route = (spg_beacon_entry_rf_route_t*)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_rf_route_t);
rf_route->beacon_entry_type = SPG_MAC_BCN_TYPE_ID_RF_ROUTE;
rf_route->beacon_entry_len = sizeof(*rf_route);
rf_route->rf_dis_period = bcn->rf_route.rf_dis_period;
rf_route->rf_age_period = bcn->rf_route.rf_age_period;
}
break;
}
case SPG_MAC_BCN_TYPE_ID_METER:
{
/* fill in the meter info */
spg_beacon_entry_meter_t *meter = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_METER]) {
plh->beacon_entry_num++;
meter = (spg_beacon_entry_meter_t*)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_meter_t) + bcn->meter.len;
meter->beacon_entry_type = SPG_MAC_BCN_TYPE_ID_METER;
meter->beacon_entry_len = sizeof(*meter) + bcn->meter.len;
os_mem_cpy(meter->data, bcn->meter.data, bcn->meter.len);
}
break;
}
case SPG_MAC_BCN_TYPE_ID_FB_DETECT:
{
/* fill in the freq band detection info */
spg_beacon_entry_fb_detect_t *fb_detect = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_FB_DETECT] &&
!is_detect) {
plh->beacon_entry_num++;
fb_detect = (spg_beacon_entry_fb_detect_t*)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_fb_detect_t);
fb_detect->beacon_entry_type = SPG_MAC_BCN_TYPE_ID_FB_DETECT;
fb_detect->beacon_entry_len = sizeof(*fb_detect);
fb_detect->band_id = bcn->fb_detect.band_id;
fb_detect->d_csma_lid = bcn->fb_detect.d_csma_lid;
}
break;
}
case SPG_MAC_BCN_TYPE_ID_RTC:
{
/* fill in the rtc info */
spg_beacon_entry_rtc_t *rtc = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_RTC]) {
plh->beacon_entry_num++;
rtc = (spg_beacon_entry_rtc_t*)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_rtc_t);
rtc->beacon_entry_type = SPG_MAC_BCN_TYPE_ID_RTC;
rtc->beacon_entry_len = sizeof(*rtc);
rtc->cco_date = bcn->rtc.cco_date;
rtc->cco_ntb = bcn->rtc.cco_ntb;
}
break;
}
case SPG_MAC_BCN_TYPE_ID_TIME_SLOT:
{
/* fill in the time slot info */
spg_beacon_entry_time_slot_alloc_t *pts = NULL;
if (bcn->beacon_component_enable[MAC_BC_BMI_TIME_SLOT]) {
plh->beacon_entry_num++;
pts = (spg_beacon_entry_time_slot_alloc_t *)(*tmp);
(*tmp) += sizeof(spg_beacon_entry_time_slot_alloc_t);
pts->beacon_entry_type = SPG_MAC_BCN_TYPE_ID_TIME_SLOT;
/* bcn entry len need to be calculated later */
/* fixed len area */
pts->total_slot_non_cco_beacon =
bcn->time_slot.non_cco_bc_info.bc_cnt;
pts->total_slot_cco_beacon =
bcn->time_slot.cco_bc_cnt;
pts->csma_phase_num =
bcn->time_slot.csma_info.phase_cnt;
pts->total_slot_pco_beacon =
bcn->time_slot.proxy_bc_cnt;
pts->beacon_slot_period =
bcn->time_slot.bc_slot_dur * 10; /* unit 100us */
/* copy the original value, ignore unit */
pts->csma_slot_period =
bcn->time_slot.org_csma_slot_frag_s;
pts->bind_csma_phase_num =
bcn->time_slot.d_csma_info.phase_cnt; /* 1-3 */
pts->bind_csma_lid =
bcn->time_slot.d_csma_lid;
pts->tdma_period =
bcn->time_slot.tdma_slot_dur * 10; /* unit 100us */
pts->tdma_lid =
bcn->time_slot.tdma_lid;
pts->cur_beacon_timestamp =
bcn->time_slot.bp_start_ntb;
pts->beacon_period =
bcn->time_slot.bc_period * 10; /* unit 100us */
pts->rf_bc_slot_period =
(uint16_t)bcn->time_slot.rf_bc_slot_dur; /* unit ms */
pts->rsvd = bcn->time_slot.spg_used_rsvd;
/* non cco beacon area */
if (bcn->spg_uniq_bc_str.payload_header.type != PLC_BC_TYPE_D ||
bcn->sta.bc_d_with_non) {
/* skip beacon slot detail for discovery beacon */
for (int i = 0; i < bcn->time_slot.non_cco_bc_info.bc_cnt;
i++) {
spg_sub_beacon_entry_non_cco_beacon_t *pnc =
(spg_sub_beacon_entry_non_cco_beacon_t*)(*tmp);
(*tmp) += sizeof(*pnc);
pnc->tei_to_send =
bcn->time_slot.non_cco_bc_info.sta[i].tei;
pnc->beacon_type =
bcn->time_slot.non_cco_bc_info.sta[i].type;
pnc->tx_flag =
bcn->time_slot.non_cco_bc_info.sta[i].tx_flag;
}
}
/* csma time slot area */
for (int i = 0; i < bcn->time_slot.csma_info.phase_cnt; i++) {
spg_sub_beacon_entry_csma_slot_t *pct =
(spg_sub_beacon_entry_csma_slot_t*)(*tmp);
(*tmp) += sizeof(*pct);
pct->csma_period =
bcn->time_slot.csma_info.slot_dur[i] * 10;
pct->phase = bcn->time_slot.csma_info.phase[i];
}
/* bind csma time slot area */
for (int i = 0; i < bcn->time_slot.d_csma_info.phase_cnt; i++) {
spg_sub_beacon_entry_bind_csma_slot_t *pbc =
(spg_sub_beacon_entry_bind_csma_slot_t*)(*tmp);
(*tmp) += sizeof(*pbc);
pbc->bind_csma_period =
bcn->time_slot.d_csma_info.slot_dur[i] * 10;
pbc->phase = bcn->time_slot.d_csma_info.phase[i];
}
/* recal the total len, exclude header len */
pts->beacon_entry_len =
(uint16_t)((*tmp) - (uint8_t*)pts);
}
break;
}
case MAC_BCN_TYPE_ID_VENDOR_SPEC:
{
/* fill in the vendor specific info */
beacon_entry_vendor_spec_t *vendor = NULL;
beacon_entry_vendor_roam_t *vendor_roam = NULL;
beacon_entry_vendor_data_t *vendor_data = NULL;
beacon_entry_vendor_debug_t *vendor_debug = NULL;
beacon_entry_vendor_tsfm_t *vendor_tsfm = NULL;
beacon_entry_vendor_security_t *vendor_sec = NULL;
beacon_entry_vendor_rf_t *vendor_rf = NULL;
/* check vendor app data size */
BUILD_BUG_ON(MAC_BC_APP_DATA_MAX == sizeof(vendor_data->data));
if (bcn->beacon_component_enable[MAC_BC_BMI_VENDOR_SPEC]) {
plh->beacon_entry_num++;
vendor = (beacon_entry_vendor_spec_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_spec_t);
os_mem_set(vendor, 0, sizeof(*vendor));
vendor->beacon_entry_type = MAC_BCN_TYPE_ID_VENDOR_SPEC;
vendor->beacon_entry_len = sizeof(*vendor);
vendor->power = bcn->vendor.power;
vendor->allowed_cco_tf_sr = bcn->vendor.allowed_cco_tf_sr;
vendor->proxy_select_dur = bcn->vendor.proxy_select_dur;
vendor->fixed_rate = bcn->vendor.fixed_rate;
vendor->pco_snr_rpt = bcn->vendor.pco_snr_rpt;
vendor->dm_tx_cfg = bcn->vendor.dm_tx_cfg;
vendor->cco_debug = bcn->vendor.cco_debug;
vendor->vendor_id = bcn->vendor.vendor_id;
if (bcn->vendor.th_data_valid) {
plh->beacon_entry_num++;
/* add roaming related vendor entry */
vendor_roam = (beacon_entry_vendor_roam_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_roam_t);
os_mem_set(vendor_roam, 0, sizeof(*vendor_roam));
vendor_roam->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_ROAM;
vendor_roam->beacon_entry_len = sizeof(*vendor_roam);
vendor_roam->sta_proxy_weight_rank =
bcn->vendor.sta_proxy_weight_rank;
vendor_roam->sta_proxy_good_tf_sr_th =
bcn->vendor.sta_proxy_good_tf_sr_th;
vendor_roam->sta_roaming_gap_h =
bcn->vendor.sta_roaming_gap_h;
vendor_roam->sta_roaming_gap_l =
bcn->vendor.sta_roaming_gap_l;
vendor_roam->cco_phase_check_tf_sr_th =
bcn->vendor.cco_phase_check_tf_sr_th;
vendor_roam->cco_phase_gap_own_h =
bcn->vendor.cco_phase_gap_own_h;
vendor_roam->cco_phase_gap_own_l =
bcn->vendor.cco_phase_gap_own_l;
vendor_roam->cco_phase_gap_other =
bcn->vendor.cco_phase_gap_other;
vendor_roam->level_score_h_th =
bcn->vendor.level_score_h_th;
vendor_roam->level_score_h =
bcn->vendor.level_score_h;
vendor_roam->level_score_l =
bcn->vendor.level_score_l;
vendor_roam->cco_good_tf_sr_th =
bcn->vendor.cco_good_tf_sr_th;
vendor_roam->cco_good_tx_sr_th =
bcn->vendor.cco_good_tx_sr_th;
vendor_roam->cco_good_rx_sr_th =
bcn->vendor.cco_good_rx_sr_th;
vendor_roam->pco_good_tf_sr_th =
bcn->vendor.pco_good_tf_sr_th;
vendor_roam->pco_good_tx_sr_th =
bcn->vendor.pco_good_tx_sr_th;
vendor_roam->pco_good_rx_sr_th =
bcn->vendor.pco_good_rx_sr_th;
vendor_roam->clamber_tf_sr_th =
bcn->vendor.clamber_tf_sr_th;
vendor_roam->clamber_target_tf_sr_th =
bcn->vendor.clamber_target_tf_sr_th;
vendor_roam->proxy_tf_sr_rank =
bcn->vendor.proxy_tf_sr_rank;
vendor_roam->roam_learn_cnt =
bcn->vendor.roam_learn_cnt;
}
if (bcn->vendor.app_data_valid) {
plh->beacon_entry_num++;
/* add app data related vendor entry */
vendor_data = (beacon_entry_vendor_data_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_data_t);
os_mem_set(vendor_data, 0, sizeof(*vendor_data));
vendor_data->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_DATA;
vendor_data->beacon_entry_len = sizeof(*vendor_data);
os_mem_cpy(vendor_data->data, bcn->vendor.app_data,
sizeof(bcn->vendor.app_data));
}
if (bcn->vendor.addr_valid) {
plh->beacon_entry_num++;
/* add debug related vendor entry */
vendor_debug = (beacon_entry_vendor_debug_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_debug_t);
os_mem_set(vendor_debug, 0, sizeof(*vendor_debug));
vendor_debug->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_DEBUG;
vendor_debug->beacon_entry_len = sizeof(*vendor_debug);
iot_mac_addr_cpy(vendor_debug->addr, bcn->vendor.addr);
}
if (bcn->vendor.tsfm_valid) {
plh->beacon_entry_num++;
/* add tsfm related vendor entry */
vendor_tsfm = (beacon_entry_vendor_tsfm_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_tsfm_t);
os_mem_set(vendor_tsfm, 0, sizeof(*vendor_tsfm));
vendor_tsfm->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_TSFM;
vendor_tsfm->beacon_entry_len = sizeof(*vendor_tsfm);
vendor_tsfm->rpt_tsfm_dur = bcn->vendor.rpt_tsfm_dur;
vendor_tsfm->tsfm_algorithm = bcn->vendor.tsfm_algorithm;
vendor_tsfm->tsfm_cco_detect_en =
bcn->vendor.tsfm_cco_detect_en;
vendor_tsfm->tsfm_low_snr_th = bcn->vendor.tsfm_low_snr_th;
vendor_tsfm->tsfm_snr_stat_high_th =
bcn->vendor.tsfm_snr_stat_high_th;
vendor_tsfm->check_tsfm_dur = bcn->vendor.check_tsfm_dur;
vendor_tsfm->tsfm_snr_diff_th1 =
bcn->vendor.tsfm_snr_diff_th1;
vendor_tsfm->tsfm_snr_diff_th2 =
bcn->vendor.tsfm_snr_diff_th2;
vendor_tsfm->tsfm_level_big_diff_th =
bcn->vendor.tsfm_level_big_diff_th;
vendor_tsfm->tsfm_cco_low_snr_th =
bcn->vendor.tsfm_cco_low_snr_th;
vendor_tsfm->tsfm_cco_snr_penal =
bcn->vendor.tsfm_cco_snr_penal;
vendor_tsfm->tsfm_cco_diff_th1 =
bcn->vendor.tsfm_cco_diff_th1;
vendor_tsfm->tsfm_cco_diff_th2 =
bcn->vendor.tsfm_cco_diff_th2;
vendor_tsfm->tsfm_zc_diff_th1 =
bcn->vendor.tsfm_zc_diff_th1;
vendor_tsfm->tsfm_zc_diff_th2 =
bcn->vendor.tsfm_zc_diff_th2;
vendor_tsfm->tsfm_zc_diff_th3 =
bcn->vendor.tsfm_zc_diff_th3;
vendor_tsfm->tsfm_zc_diff_th4 =
bcn->vendor.tsfm_zc_diff_th4;
vendor_tsfm->tsfm_snr_bc_factor =
bcn->vendor.tsfm_snr_bc_factor;
vendor_tsfm->tsfm_snr_sof_factor =
bcn->vendor.tsfm_snr_sof_factor;
}
if (bcn->vendor.passcode_valid) {
plh->beacon_entry_num++;
/* add security related vendor entry */
vendor_sec = (beacon_entry_vendor_security_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_security_t);
os_mem_set(vendor_sec, 0, sizeof(*vendor_sec));
vendor_sec->beacon_entry_type =
MAC_BCN_TYPE_ID_VENDOR_SECURITY;
vendor_sec->beacon_entry_len = sizeof(*vendor_sec);
vendor_sec->passcode = bcn->vendor.passcode;
}
if (bcn->vendor.rf_power_valid ||
bcn->vendor.force_link_valid) {
plh->beacon_entry_num++;
/* add rf related vendor entry */
vendor_rf = (beacon_entry_vendor_rf_t *)(*tmp);
(*tmp) += sizeof(beacon_entry_vendor_rf_t);
os_mem_set(vendor_rf, 0, sizeof(*vendor_rf));
vendor_rf->beacon_entry_type = MAC_BCN_TYPE_ID_VENDOR_RF;
vendor_rf->beacon_entry_len = sizeof(*vendor_rf);
vendor_rf->rf_power = bcn->vendor.rf_power;
vendor_rf->rf_power_valid = bcn->vendor.rf_power_valid;
vendor_rf->force_link_valid = bcn->vendor.force_link_valid;
vendor_rf->force_rf_link = bcn->vendor.force_rf_link;
}
}
break;
}
case MAC_BCN_TYPE_ID_UNKNOWN:
{
/* fill in unknown entry info */
if (bcn->beacon_component_enable[MAC_BC_BMI_UNKNOWN] &&
bcn->unknown_entry && iot_pkt_data_len(bcn->unknown_entry)) {
plh->beacon_entry_num++;
p_unknown = iot_pkt_data(bcn->unknown_entry);
if (get_bcn_entry_hdr_len_spg(p_unknown[0]) == 3) {
unknown_len = ((uint16_t)p_unknown[2]) << 8;
unknown_len |= p_unknown[1];
} else {
unknown_len = p_unknown[1];
}
os_mem_cpy(*tmp, p_unknown, unknown_len);
(*tmp) += unknown_len;
iot_pkt_pull(bcn->unknown_entry, unknown_len);
}
break;
}
default:
IOT_ASSERT(0);
break;
}
}
}
#endif
void mac_beacon_fill_pld_icv(uint32_t proto, uint8_t *data,
iot_pkt_t* bcn_buf)
{
IOT_ASSERT(data);
uint8_t fc_len = mac_get_mpdu_fc_len(proto);
switch (proto) {
case PLC_PROTO_TYPE_SG:
{
#if SUPPORT_IEEE_1901
i1901_beacon_payload_icv_t *icv = NULL;
icv = (i1901_beacon_payload_icv_t*)data;
icv->icv = iot_getcrc32_update(CRC32_INIT_VECT_I1901,
iot_pkt_data(bcn_buf) + fc_len,
(uint32_t)(data - iot_pkt_data(bcn_buf) - fc_len));
#else
beacon_payload_icv_t *icv = NULL;
icv = (beacon_payload_icv_t*)data;
icv->icv =
iot_getcrc32(iot_pkt_data(bcn_buf) + fc_len,
(uint32_t)(data - iot_pkt_data(bcn_buf) - fc_len));
#endif
break;
}
case PLC_PROTO_TYPE_SPG:
{
spg_beacon_payload_icv_t *icv = NULL;
icv = (spg_beacon_payload_icv_t*)data;
icv->icv =
iot_getcrc32(iot_pkt_data(bcn_buf) + fc_len,
(uint32_t)(data - iot_pkt_data(bcn_buf) - fc_len));
break;
}
default:
IOT_ASSERT(0);
break;
}
}
void mac_beacon_fill_fc_tmi(uint32_t proto, void *fc, uint32_t tmi)
{
IOT_ASSERT(fc);
switch (proto) {
case PLC_PROTO_TYPE_SG:
{
frame_control_t *sg_fc = (frame_control_t *)fc;
sg_fc->vf.bcn.tmi = tmi & 0xf;
break;
}
case PLC_PROTO_TYPE_SPG:
{
spg_frame_control_t *spg_fc = (spg_frame_control_t *)fc;
spg_fc->vf.bcn.tmi = tmi & 0xf;
break;
}
default:
IOT_ASSERT(0);
break;
}
}
uint32_t mac_tx_fl_cal_bcn(uint8_t proto, uint8_t rate_mode,
uint32_t proto_band_id, uint8_t tmi, uint8_t ext_tmi)
{
uint32_t tx_fl = 0;
/* fl = symbol + fc + payload + bifs. then:
* symbol + fc = mac_rx_get_delim();
* payload = phy_get_flppb_from_table * 1. (for beacon, only 1pb num)
* bifs = mac_get_tx_bifs
*/
(void)proto; //TODO: check proto
//if (PLC_PROTO_TYPE_SG == proto)
{
uint32_t hw_band_id = phy_proto_band_to_hw_band(proto_band_id);
tx_fl = mac_rx_get_delim(rate_mode, hw_band_id)
+ phy_get_flppb_from_table(hw_band_id, tmi, ext_tmi)
+ mac_get_tx_bifs(proto);
}
return tx_fl;
}
/* beacon payload to send, it would add some FC or PB info into the iot_pkt_t
and to form an Beacon MPDU.
*/
uint8_t mac_beacon_tx(uint32_t proto, uint32_t proto_band_id,
mac_beacon_ctx_t *bcn, iot_pkt_t* bcn_buf)
{
uint8_t rid;
uint32_t tmi, ext_tmi;
uint32_t rate_mode;
uint32_t tx_power = PHY_FULL_PWR_DBUV;
uint32_t pb_size;
uint32_t fl;
uint8_t tx_cnt, retry_cnt;
uint8_t *tmp = iot_pkt_block_ptr(bcn_buf, IOT_PKT_BLOCK_DATA);
uint8_t bc_pb_crc_len = mac_get_pb_crc_len(FC_DELIM_BEACON, proto);
uint8_t bc_pld_icv_len = 0;
uint8_t bc_pb_resv_len = 0;
uint8_t fc_len = mac_get_mpdu_fc_len(proto);
void *fc = (void *)tmp;
os_mem_set(tmp, 0, iot_pkt_block_len(bcn_buf, IOT_PKT_BLOCK_DATA) +
iot_pkt_block_len(bcn_buf, IOT_PKT_BLOCK_TAIL));
#if SUPPORT_SMART_GRID
if (PLC_PROTO_TYPE_SG == proto) {
/* fill sg fill beacon payload */
mac_beacon_fill_buf_sg(bcn, &tmp);
#if SUPPORT_IEEE_1901
bc_pld_icv_len = sizeof(i1901_beacon_payload_icv_t);
#else
bc_pld_icv_len = sizeof(beacon_payload_icv_t);
#endif
bc_pb_resv_len = 0;
}
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
if (PLC_PROTO_TYPE_SPG == proto) {
bool_t is_detect = false;
if (phy_proto_single_band_id_get() != proto_band_id) {
is_detect = true;
}
/* fill spg beacon payload */
mac_beacon_fill_buf_spg(bcn, &tmp, is_detect);
bc_pld_icv_len = sizeof(spg_beacon_payload_icv_t);
bc_pb_resv_len = SPG_BCN_PB_RESV_LEN;
}
#endif
uint32_t bcn_len;
/* bcn_len is payload length for mac_bcn_get_rate,
* not including FC
*/
bcn_len = tmp - iot_pkt_data(bcn_buf)
+ bc_pld_icv_len + bc_pb_crc_len
+ bc_pb_resv_len - fc_len;
/* get rate idx */
if (mac_bcn_get_rate(bcn->ref_vdev_ptr,
proto, true, bcn_len, proto_band_id, &rid, &rate_mode)) {
IOT_ASSERT(0);
}
/* get pbsz, tmi and ext emi if not GP */
phy_get_tmi_by_rid(proto, rid, &tmi, &ext_tmi);
phy_get_rt_pbsz(proto, rid, &pb_size);
IOT_ASSERT(bcn_len <= pb_size);
tmp = iot_pkt_data(bcn_buf) + fc_len + pb_size
- bc_pb_crc_len - bc_pb_resv_len
- bc_pld_icv_len;
/* fill icv */
mac_beacon_fill_pld_icv(proto, tmp, bcn_buf);
tmp += bc_pld_icv_len;
/* fill the correct tmi now,
* as the bcn len is got into
* consideration
*/
mac_beacon_fill_fc_tmi(proto, fc, tmi);
IOT_ASSERT(iot_pkt_set_tail(bcn_buf, tmp));
fl = mac_tx_fl_cal_bcn((uint8_t)proto, (uint8_t)rate_mode,
proto_band_id, (uint8_t)tmi, (uint8_t)ext_tmi);
if (phy_proto_single_band_id_get() == proto_band_id) {
/* slot unit: 1ms, fl unit: 1us, bifs unit: 1us.
* for tx bcn, the mac hw will calculate how many count can be sent in this
* slot.
* 1. the last time for tx bcn, mac hw not care the bifs.
* 2. each slot must be reserved some time for hw operation.
*/
tx_cnt = (uint8_t)((bcn->time_slot.bc_slot_dur * 1000
+ mac_get_tx_bifs(proto)
- mac_tx_get_slot_guard((uint8_t)proto, (uint8_t)FC_DELIM_BEACON))
/ fl);
} else {
tx_cnt = PLC_BCN_DEF_DETECT_RETRY_CNT;
}
/* fix GW hplc + rf dual mode test bed channel conflict case, test bed
* always get history beacon frames from buffer pool, we should not retry
* tx beacon so as to let it get more new beacon frames
*/
if (PLC_DEV_ROLE_CCO == mac_vdev_cfg_get_node_role(
(mac_vdev_t *)bcn->ref_vdev_ptr)) {
if (mac_get_cert_test_flag() &&
/* modify retry cnt = 0 for sanxi cert test
* after received the beacon,
* the console sends an association request immediately,
* which will collide with the retry packet,
* so the retry is removed.
*/
(USER_TYPE_STATE_GRID_XIAN == iot_oem_get_user_type() ||
/* fix gw hplc test bed center beacon case, test bed not received phase
* A center beacon when using kl3 hardware device. we should retry
* phase A beacon
*/
bcn->fc.phase != PLC_PHASE_A)) {
retry_cnt = 0;
goto label_1;
}
}
retry_cnt = mac_cfg_get_bcn_def_retry_cnt();
label_1:
//default tx cnt = retry cnt + 1, 1 means this time is sent normally
tx_cnt = min(tx_cnt, retry_cnt + 1);
if (0 == tx_cnt) {
iot_printf("%s:tx_cnt=%d, fl=%d, bc_slot=%d,"
"bc_period=%d, band_id=%d, rid=%d, rate_mode=%d\n",
__FUNCTION__, tx_cnt, fl, bcn->time_slot.bc_slot_dur,
bcn->time_slot.bc_period, proto_band_id, rid, rate_mode);
IOT_ASSERT(0);
} else if (retry_cnt && (tx_cnt < (retry_cnt + 1))) {
retry_cnt = tx_cnt - 1;
}
mac_send_bcn(proto, proto_band_id,
((mac_vdev_t *)bcn->ref_vdev_ptr)->ref_pdev_id,
bcn_buf, rate_mode, bcn->fc.phase, retry_cnt, tx_power);
return tx_cnt;
}
uint32_t mac_beacon_rx_icv_get(uint8_t proto, iot_pkt_t* buf)
{
uint32_t bcn_icv = 0;
IOT_ASSERT(buf);
switch(proto) {
#if SUPPORT_SMART_GRID
case PLC_PROTO_TYPE_SG:
{
beacon_payload_icv_t *icv;
#if SUPPORT_IEEE_1901
icv = (beacon_payload_icv_t*)(iot_pkt_block_ptr(buf, IOT_PKT_BLOCK_TAIL)
- sizeof(beacon_payload_icv_t) - I1901_BCN_PB_CRC_LEN);
#else
icv = (beacon_payload_icv_t*)(iot_pkt_block_ptr(buf, IOT_PKT_BLOCK_TAIL)
- sizeof(beacon_payload_icv_t) - SG_BCN_PB_CRC_LEN);
#endif
bcn_icv = icv->icv;
break;
}
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
case PLC_PROTO_TYPE_SPG:
{
spg_beacon_payload_icv_t *icv;
icv = (spg_beacon_payload_icv_t*)(iot_pkt_block_ptr(buf,
IOT_PKT_BLOCK_TAIL) - sizeof(spg_beacon_payload_icv_t)
- SPG_BCN_PB_CRC_LEN - SPG_BCN_PB_RESV_LEN);
bcn_icv = icv->icv;
break;
}
#endif
default:
break;
}
return bcn_icv;
}
static void mac_beacon_rx_plh_get(uint8_t proto, bcn_pld_hdr_t *msg,
uint8_t *tmp, mac_rx_info_t *rx_info)
{
IOT_ASSERT(msg);
switch(proto) {
#if SUPPORT_SMART_GRID
case PLC_PROTO_TYPE_SG:
{
beacon_payload_fixed_header_t *plh_sg =
(beacon_payload_fixed_header_t *)tmp;
msg->beacon_type = plh_sg->beacon_type;
msg->beacon_seq_num = plh_sg->beacon_seq_num;
iot_mac_addr_cpy(msg->cco_addr, plh_sg->cco_mac_addr);
break;
}
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
case PLC_PROTO_TYPE_SPG:
{
spg_frame_control_t *fc_spg =
(spg_frame_control_t *)rx_info->fc;
spg_beacon_payload_fixed_header_t *plh_spg =
(spg_beacon_payload_fixed_header_t *)tmp;
msg->beacon_type = plh_spg->beacon_type;
msg->beacon_seq_num = fc_spg->vf.bcn.bcn_period_cnt;
break;
}
#endif
default:
break;
}
}
bool_t mac_beacon_is_cco_type(uint32_t proto, bcn_pld_hdr_t *plh,
mac_vdev_t *vdev)
{
IOT_ASSERT(plh && vdev);
bool_t targ_cco_bc = true;
switch (proto) {
#if SUPPORT_SMART_GRID
case PLC_PROTO_TYPE_SG:
if (!iot_mac_addr_cmp(plh->cco_addr,
vdev->bcn_ctx.sg_uniq_bc_str.payload_header.cco_addr))
targ_cco_bc = false;
break;
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
case PLC_PROTO_TYPE_SPG:
if (PLC_BC_TYPE_C != plh->beacon_type)
targ_cco_bc = false;
break;
#endif
default:
IOT_ASSERT(0);
break;
}
return targ_cco_bc;
}
#if (!IOT_HTBUS_EN)
uint32_t mac_beacon_rx(uint8_t proto, void *vdev_ptr, iot_pkt_t* buf)
{
mac_vdev_t *vdev = (mac_vdev_t *)vdev_ptr;
uint8_t *tmp, new_bp = 0;
uint32_t i = 0;
uint32_t crc = 0;
uint32_t bcn_icv = 0;
mac_rx_info_t *rx_info;
if (!vdev || !buf) {
IOT_ASSERT(0);
goto err;
}
if (vdev->start_cfg.mac_bc_rx_func == NULL) {
goto err;
}
tmp = iot_pkt_block_ptr(buf, IOT_PKT_BLOCK_DATA);
rx_info = (mac_rx_info_t *)(tmp - sizeof(*rx_info));
/* check crc */
uint32_t bcn_len = \
iot_pkt_block_len(buf, IOT_PKT_BLOCK_DATA);
#if PLC_MAC_RX_DEBUG_LOG
if (rx_info->phy.is_rf) {
iot_printf("rx bcn len %d on option:%d, channel:%d\n",
bcn_len, rx_info->phy.rf_option, rx_info->phy.channel_id);
} else {
iot_printf("rx bcn len %d on band %d\n", bcn_len, rx_info->phy.band_id);
}
#endif
/* check beacon payload crc */
bcn_icv = mac_beacon_rx_icv_get(proto, buf);
uint32_t ret = 0;
ret = mac_crc_get_bcn_swcrc(proto, iot_pkt_data(buf), bcn_len, &crc);
if(ret == ERR_CRC_LEN)
{
iot_printf("pld len err, when mac calu crc!\n");
mem_dump((uint32_t *)buf, 21); // 4iot_pkt addr + 16desc + 1DW plod
goto err;
}
if (crc != bcn_icv) {
/* TODO: check with accurate len,
*/
mac_add_rx_bcn_err_cnt();
iot_printf("bcn crcerrcnt: %lu,"
"bcn_icv=0x%x, crc_cal=0x%x"
"\n", mac_get_rx_bcn_err_cnt(), bcn_icv, crc);
#if PLC_HW_ISSUE_ASSERT_LEVEL <= PLC_HW_ISSUE_ASSERT_ALL
IOT_ASSERT(0);
#endif
goto err;
}
/* get fixed header and fc info */
bcn_pld_hdr_t plh = { 0 };
rx_fc_msg_t rx_fc = { 0 };
mac_beacon_rx_plh_get(proto, &plh, tmp, rx_info);
mac_beacon_rx_fc_info_get(proto, rx_info, &rx_fc);
/* sync sta/pco's timestamp */
if ((mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO) &&
(rx_fc.nid == vdev->bcn_ctx.fc.nid)) {
bool_t targ_cco_bc = \
mac_beacon_is_cco_type(proto, &plh, vdev);
uint32_t bc_period_cnt = vdev_get_bc_period_cnt(proto, vdev);
if (targ_cco_bc) {
#if ((HW_PLATFORM == HW_PLATFORM_SIMU) && (SCHED_SUPPORT == 0))
/* for HW scheduler not supported case, device may receive
* discovery beacon ahead of proxy beacon. ignore discovery beacon
* as the beacon slot detail of each tei is not available in
* discovery beacon. local device won't be able to decide if
* local device need to send out beacon for current beacon period.
*/
if (mac_get_tei(vdev) != PLC_TEI_INVAL &&
plh.beacon_type == PLC_BC_TYPE_D) {
goto err;
}
#endif
if (bc_period_cnt == 0) {
/* always accept the first beacon */
i = 1;
} else {
i = plh.beacon_seq_num - bc_period_cnt;
}
if (i && i <= PLC_BCN_DUPLICATE_GUARD) {
/* new beacon period, sync up the time stamp and save the
* start ntb
*/
new_bp = 1;
#if (MAC_SCHED_DEBUG || RUNTIME_DEBUG)
iot_printf("%s bc recv ntb %lu, bc send ntb %lu, "
"bp cnt %lu\n", __FUNCTION__,
mac_sched_get_ntb(vdev), rx_fc.time_stamp,
bc_period_cnt);
iot_dbglog_input(PLC_MAC_DATA_MID, DBGLOG_INFO,
IOT_MAC_BEACON_RX_NTB_INFO, 3, mac_sched_get_ntb(vdev),
rx_fc.time_stamp, bc_period_cnt);
#endif
}
}
}
mac_add_rx_bcn_upload_cnt();
vdev->start_cfg.mac_bc_rx_func(vdev->start_cfg.mac_callback_arg,
buf, new_bp);
return ERR_OK;
err:
iot_pkt_free(buf);
return ERR_INVAL;
}
uint32_t mac_update_beacon_internal(uint8_t pdev_id, uint8_t vdev_id,
mac_bc_update_t *ent, uint8_t *tx_cnt)
{
uint8_t is_boost = 0;
uint32_t ret = 0;
mac_vdev_t *vdev;
uint32_t proto = PHY_PROTO_TYPE_GET();
*tx_cnt = 0;
vdev = get_vdev_ptr(pdev_id, vdev_id);
if (vdev == NULL) {
ret = ERR_INVAL;
goto out;
}
/* boost mac task priority so as to update beacons quickly */
if ((mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO)
&& ent->tx_req) {
is_boost = 1;
mac_boost_task_prio();
}
mac_beacon_ctx_t *bcn_ctxt =
&vdev->bcn_ctx;
/* get beacon info */
mac_bc_ent_str_info_t bc_ent_str = { 0 };
mac_beacon_uniq_info_get(proto, bcn_ctxt, &bc_ent_str);
IOT_ASSERT(bc_ent_str.plh_str_ptr &&
bc_ent_str.rt_param_str_ptr &&
bc_ent_str.sta_cap_str_ptr);
/* alwasy disable optional beacon entry for each update by default */
bcn_ctxt->beacon_component_enable[MAC_BC_FC_INFO] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_FIX_P] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_STA_CAP] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_RT_PARAM] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_FREQ_CHG] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_TIME_SLOT] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_VENDOR_SPEC] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_METER] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_FB_DETECT] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_RF_CHANNEL_CHG] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_RF_ROUTE] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_RF_SIMPLE_PARAM] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_RTC] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_UNKNOWN] = 0;
bcn_ctxt->is_tx_detect = MAC_BEACON_IS_NORMAL;
bcn_ctxt->entry_sort_cnt = ent->entry_sort_cnt;
os_mem_cpy(bcn_ctxt->entry_sort, ent->entry_sort,
sizeof(bcn_ctxt->entry_sort));
for (int i = 0; i < ent->count; i++) {
switch (ent->entry[i].type)
{
case MAC_BC_FC_INFO:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->fc, ent->entry[i].data,
sizeof(bcn_ctxt->fc));
bcn_ctxt->fc.nid = mac_mask_input_nid(bcn_ctxt->fc.nid);
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_FIX_P:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(bc_ent_str.plh_str_ptr,
ent->entry[i].data,
bc_ent_str.plh_str_size);
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_BMI_STA_CAP:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(bc_ent_str.sta_cap_str_ptr, ent->entry[i].data,
bc_ent_str.sta_cap_str_size);
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
#if CPLC_IOT_CERT_ENABLE
mac_check_power_by_level(vdev,
bcn_ctxt->sg_uniq_bc_str.sta_cap.level);
#endif
}
break;
}
case MAC_BC_BMI_RT_PARAM:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(bc_ent_str.rt_param_str_ptr,
ent->entry[i].data, bc_ent_str.rt_param_str_size);
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_BMI_FREQ_CHG:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->freq_chg, ent->entry[i].data,
sizeof(bcn_ctxt->freq_chg));
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_BMI_RF_CHANNEL_CHG:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->rf_chg, ent->entry[i].data,
sizeof(bcn_ctxt->rf_chg));
bcn_ctxt->beacon_component_enable[ent->entry[i].type] = 1;
}
break;
}
case MAC_BC_BMI_RF_ROUTE:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->rf_route, ent->entry[i].data,
sizeof(bcn_ctxt->rf_route));
bcn_ctxt->beacon_component_enable[ent->entry[i].type] = 1;
}
break;
}
case MAC_BC_BMI_TIME_SLOT:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->time_slot, ent->entry[i].data,
sizeof(bcn_ctxt->time_slot));
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_BMI_METER:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->meter, ent->entry[i].data,
sizeof(bcn_ctxt->meter));
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_BMI_FB_DETECT:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->fb_detect, ent->entry[i].data,
sizeof(bcn_ctxt->fb_detect));
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
bcn_ctxt->is_tx_detect = MAC_BEACON_IS_DETECT;
}
break;
}
case MAC_BC_BMI_RTC:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->rtc, ent->entry[i].data,
sizeof(bcn_ctxt->rtc));
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_BMI_VENDOR_SPEC:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->vendor, ent->entry[i].data,
sizeof(bcn_ctxt->vendor));
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_BMI_RF_SIMPLE_PARAM:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(bc_ent_str.simple_param_str_ptr,
ent->entry[i].data, bc_ent_str.simple_param_str_size);
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
case MAC_BC_BMI_UNKNOWN:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
bcn_ctxt->unknown_entry = ent->entry[i].data;
bcn_ctxt->beacon_component_enable[ent->entry[i].type]
= 1;
}
break;
}
default:
IOT_ASSERT(0);
break;
}
}
/* config NID to HW once the NID is available */
vdev_set_nid(vdev, bcn_ctxt->fc.nid);
if (mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO) {
bcn_ctxt->sta.allow_reuse_ts = 1;
*tx_cnt = mac_update_beacon_sta(proto, vdev, ent);
} else {
*tx_cnt = mac_update_beacon_cco(proto, vdev, ent);
}
#if PLC_SUPPORT_DBG_PKT_MODE
vdev_set_block_dbg_pkt_4_rx_only(vdev, true);
#endif
out:
/* restore mac task default priority */
if (is_boost) {
mac_restore_task_prio();
}
return ret;
}
#endif /* (!IOT_HTBUS_EN) */
uint32_t mac_update_beacon(uint8_t pdev_id, uint8_t vdev_id,
mac_bc_update_t *ent, uint8_t *tx_cnt)
{
uint32_t ret = 0;
mac_msg_sync_t *msg = mac_alloc_msg_sync();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->msg.type = MAC_MSG_TYPE_CVG;
msg->msg.id = MAC_MSG_ID_CVG_UPDATE_BC;
msg->msg.data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
msg->msg.data2 = ent;
mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP);
/* get result */
ret = msg->msg.data1;
*tx_cnt = (uint8_t)(((uint32_t)msg->msg.data2) & 0xFF);
mac_free_msg_sync(msg);
out:
return ret;
}
#if (PLC_SUPPORT_CCO_ROLE)
uint32_t mac_start_beacon(uint8_t pdev_id, uint8_t vdev_id)
{
uint32_t ret = 0;
mac_msg_t *msg = mac_alloc_msg();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->type = MAC_MSG_TYPE_CVG;
msg->id = MAC_MSG_ID_CVG_START_BC;
msg->data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
out:
return ret;
}
uint32_t mac_start_beacon_internal(uint8_t pdev_id, uint8_t vdev_id)
{
mac_vdev_t *mac_vdev;
mac_beacon_ctx_t *bcn_ctx;
mac_rf_vdev_t *rf_vdev = NULL;
mac_vdev = get_vdev_ptr(pdev_id, vdev_id);
if (mac_vdev == NULL) {
return ERR_INVAL;
}
rf_vdev = get_rf_vdev_ptr(mac_vdev->ref_pdev_id,
RF_PDEV_ID, mac_vdev->rf_vdev_id);
bcn_ctx = &mac_vdev->bcn_ctx;
if (bcn_ctx->cco.started)
goto ret;
/* stop HW scheduler first if it's running */
mac_sched_stop(mac_vdev);
/* rf schedule stop */
mac_rf_sched_stop(rf_vdev);
/* set beacon period to be started in the near future */
bcn_ctx->cco.curr_start_ntb64 = mac_sched_get_ntb64(mac_vdev);
bcn_ctx->cco.curr_start_ntb64 += MAC_MS_TO_NTB(MAC_BP_AHEAD_NEXT_BP_DUR);
/* set command list scheduler and start the next beacon period */
bcn_ctx->cco.curr_start_ntb64 = mac_sched_cco_set(mac_vdev,
&bcn_ctx->time_slot, bcn_ctx->cco.curr_start_ntb64,
&bcn_ctx->cco.next_start_ntb64);
/* rf cco schedule set, start cco tx simple beacon */
mac_rf_sched_cco_set(rf_vdev, &mac_vdev->bcn_ctx.time_slot,
mac_vdev->bcn_ctx.cco.curr_start_ntb64,
mac_vdev->bcn_ctx.cco.next_start_ntb64);
bcn_ctx->cco.started = 1;
mac_config_tei(mac_vdev, vdev_get_tei(mac_vdev));
/* start check spur period timer */
mac_pdev_t *pdev = get_pdev_ptr(pdev_id);
mac_cco_check_spur_start_timer(&pdev->mac_check_spur_ctxt,
MAC_CCO_CHECK_SPUR_WAIT_PERIOD_START,
MAC_CHECK_SPUR_PD_MS);
ret:
return 0;
}
uint32_t mac_stop_beacon(uint8_t pdev_id, uint8_t vdev_id)
{
uint32_t ret = 0;
mac_msg_t *msg = mac_alloc_msg();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->type = MAC_MSG_TYPE_CVG;
msg->id = MAC_MSG_ID_CVG_STOP_BC;
msg->data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
out:
return ret;
}
uint32_t mac_stop_beacon_internal(uint8_t pdev_id, uint8_t vdev_id)
{
uint64_t start_ntb;
mac_vdev_t *mac_vdev;
mac_beacon_ctx_t *bcn_ctx;
mac_rf_vdev_t *rf_vdev = NULL;
mac_vdev = get_vdev_ptr(pdev_id, vdev_id);
if (mac_vdev == NULL) {
return ERR_INVAL;
}
rf_vdev = get_rf_vdev_ptr(mac_vdev->ref_pdev_id,
RF_PDEV_ID, mac_vdev->rf_vdev_id);
bcn_ctx = &mac_vdev->bcn_ctx;
if (bcn_ctx->cco.started == 0)
goto ret;
/* stop current HW scheduler */
mac_sched_stop(mac_vdev);
/* rf schedule stop */
mac_rf_sched_stop(rf_vdev);
/* start HW scheduler in rx only mode */
start_ntb = mac_sched_get_ntb64(mac_vdev);
mac_sched_set_csma_only(mac_vdev, start_ntb, 0);
/* rf csma only schedule set */
mac_rf_sched_set_csma_only(rf_vdev, start_ntb, 0);
bcn_ctx->cco.started = 0;
ret:
return 0;
}
#endif /* PLC_SUPPORT_CCO_ROLE */
uint32_t mac_send_bcn(uint32_t proto, uint32_t proto_band_id,
pdevid_t pdev_id, iot_pkt_t* bcn_buf,
uint32_t rate_mode, uint8_t phase, uint8_t retry_cnt, uint32_t tx_power)
{
uint32_t bcn_len, hw_retry_cnt, hw_band_id;
tx_mpdu_end *mpdu_end;
tx_mpdu_start *mpdu;
tx_pb_start *pb_start = NULL;
tx_dummy_node *dummy = NULL;
mac_queue_t swq_id;
uint8_t hwqid;
mac_pdev_t *pdev = g_mac_pdev[pdev_id];
uint32_t pb_hdr_resv_crc_len =
mac_get_pb_hdr_resv_crc_len(FC_DELIM_BEACON, proto);
uint8_t fc_len = mac_get_mpdu_fc_len(proto);
tx_fc_msg_t fc_info = { 0 };
mac_desc_get(&g_mac_desc_eng, PLC_TX_MPDU_END_POOL, (void **)&mpdu_end);
mac_desc_get(&g_mac_desc_eng, PLC_TX_MPDU_START_POOL, (void **)&mpdu);
mac_desc_get(&g_mac_desc_eng, PLC_TX_PB_START_POOL, (void **)&pb_start);
if (!(mpdu && mpdu_end && pb_start)) {
IOT_ASSERT(0);
return ERR_NOMEM;
}
mac_get_tx_msg_from_fc(proto, FC_DELIM_BEACON,
iot_pkt_data(bcn_buf), &fc_info);
iot_pkt_pull(bcn_buf, fc_len);
mac_beacon_send_fill_pb_start(proto, pb_start,
(uint32_t)iot_pkt_block_ptr(bcn_buf, IOT_PKT_BLOCK_DATA));
/*
* fill in mpdu start
*/
bcn_len = (uint16_t)iot_pkt_block_len(bcn_buf, IOT_PKT_BLOCK_DATA);
mac_tx_mpdu_fill_total_len(mpdu, bcn_len);
uint32_t pb_num = 1; /* bcn is 1 fixed */
uint32_t need_encry = 0;
uint32_t need_ack = 0;
/* for bcn the buffer is reused now */
uint32_t pb_buf_reuse = 1;
uint32_t sw_buf_offset = 0;
/*recovery pkt*/
iot_pkt_push(bcn_buf, fc_len);
uint32_t region_type;
lid_t lid;
bool_t is_tx_3phase = false;
bool_t is_sta = false;
if (phy_proto_single_band_id_get() == proto_band_id) {
/* if normal bcn, use PLC_BCN_REGION_BCN */
region_type = PLC_BCN_REGION_BCN;
lid = 0;
/* if normal bcn, beacon_mpdu->dummy */
mac_desc_get(&g_mac_desc_eng, PLC_TX_DUMMY_NODE_POOL, (void**)&dummy);
if (!dummy) {
IOT_ASSERT(0);
return ERR_NOMEM;
}
/* set dummy desc type */
dummy->desc_type = DESC_TYPE_TX_DUMMY;
} else {
mac_vdev_t *vdev = get_vdev_ptr(pdev_id, PLC_DEFAULT_VDEV);
is_sta = (mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO);
/* detect bcn, use PLC_BCN_REGION_BCSMA */
region_type = PLC_BCN_REGION_BCSMA;
lid = LID_BCSMA_START;
is_tx_3phase = true;
pb_buf_reuse = 0;
/* calculate sw_buf_offset */
iot_pkt_pull(bcn_buf, fc_len);
uint8_t *data = iot_pkt_block_ptr(bcn_buf, IOT_PKT_BLOCK_DATA);
sw_buf_offset = (uint32_t)(data - (uint8_t *)bcn_buf);
}
/* get swq type id */
swq_id = mac_q_get_swq_type(region_type,
is_sta ? PLC_PHASE_A : phase, lid);
/* check if swq type is support */
if (swq_id == MAX_MAC_QUE_NUM)
{
/* swq type error */
IOT_ASSERT(0);
}
/* check if the hwq already enabled */
hwqid = mac_q_get_hwqid(&pdev->hwq_hdl, swq_id);
if (hwqid == INV_MAC_HWQ_ID) {
/* hw queue is not enabled, try to alloc it */
hwqid = mac_q_alloc_hwq(&pdev->hwq_hdl, swq_id);
}
uint32_t tx_port = HW_DESC_TX_PORT_PLC;
uint32_t ppdu_mode = 0;
uint32_t tone_amp_tbl_idx = 0;
/* get pb mod */
uint32_t pb_mod, ext_tmi = 0;
IOT_ASSERT(0 == phy_get_pb_mod(proto,
fc_info.tmi, ext_tmi, &pb_mod));
hw_band_id = phy_proto_band_to_hw_band(proto_band_id);
uint32_t tx_symbnum_ppb = phy_get_symppb_from_table(
hw_band_id, fc_info.tmi, ext_tmi);
uint32_t sw_tx_fl_ppb = phy_get_flppb_from_table(
hw_band_id, fc_info.tmi, ext_tmi);
if (tx_symbnum_ppb == 0 || sw_tx_fl_ppb == 0) {
iot_printf("%s,sym_ppb or fl_ppb = 0,band_id:%d, tmi:%d, exttmi:%d\n",
__FUNCTION__, hw_band_id, fc_info.tmi, ext_tmi);
IOT_ASSERT(0);
}
//TODO: extension for modify actual hw retry cnt
hw_retry_cnt = retry_cnt;
mac_tx_mpdu_fill_macinfo(mpdu, swq_id, pb_num,
need_encry, need_ack, tx_symbnum_ppb,
sw_tx_fl_ppb, 0, pb_hdr_resv_crc_len, hw_retry_cnt,
1, 1, mpdu_end, pb_start, (tx_mpdu_start *)dummy,
pb_buf_reuse, sw_buf_offset, 0, 0, 0, 0, 0
);
mac_tx_mpdu_fill_phyinfo(
mpdu, tx_port, tx_power, is_tx_3phase ? PLC_PHASE_ALL : phase,
hw_band_id, ppdu_mode, tone_amp_tbl_idx, pb_mod, rate_mode);
mac_tx_mpdu_fill_fcinfo(
mpdu, proto, pb_num, phase, FC_DELIM_BEACON,
fc_info.network_type, fc_info.nid, fc_info.bcn_period_cnt,
fc_info.tmi, ext_tmi,
0xfff, fc_info.src_tei, 0, 1, 0, 0, 0 , 0, NULL
);
return mac_tx_hw_mpdu(&pdev->hwq_hdl, hwqid, mpdu);
}
uint32_t mac_beacon_cal_biggest_csma_phase(mac_beacon_ctx_t *bcn_ctx,
uint8_t *biggest_phase)
{
uint32_t ret = ERR_INVAL;
if (!bcn_ctx || !biggest_phase) {
IOT_ASSERT(0);
return ret;
}
mac_bc_cmsa_si_t *ci = &bcn_ctx->time_slot.csma_info;
uint32_t max_slot_dur = 0;
for (int i = 0; i < ci->phase_cnt; i++)
{
if (ci->slot_dur[i] > max_slot_dur) {
max_slot_dur = ci->slot_dur[i];
*biggest_phase = ci->phase[i];
ret = ERR_OK;
}
}
return ret;
}