744 lines
27 KiB
C
744 lines
27 KiB
C
/****************************************************************************
|
|
|
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
|
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
be copied by any method or incorporated into another program without
|
|
the express written consent of Aerospace C.Power. This Information or any portion
|
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
liability for its use in any way and conveys no license or title under
|
|
any patent or copyright and makes no representation or warranty that this
|
|
Information is free from patent or copyright infringement.
|
|
|
|
****************************************************************************/
|
|
#include "os_utils.h"
|
|
#include "os_mem_api.h"
|
|
#include "iot_config.h"
|
|
#include "mac_pdev.h"
|
|
#include "mpdu_frame.h"
|
|
#include "mpdu_header.h"
|
|
#include "iot_errno.h"
|
|
#include "iot_pkt.h"
|
|
#include "iot_io.h"
|
|
#include "iot_system.h"
|
|
#include "plc_protocol.h"
|
|
#include "mac_msg.h" /* for msg send */
|
|
#include "rx_desc_reg_api.h"
|
|
#include "mac_peer.h"
|
|
#include "mac_stream.h"
|
|
#include "mac_sched.h"
|
|
#include "mac_hplc_ext_api.h"
|
|
#include "mac_rx_hw.h"
|
|
#include "mac_cert_test.h"
|
|
#include "mac_check_spur_sta.h"
|
|
#include "mac_cmn_hw.h"
|
|
#include "mac_crc.h"
|
|
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
#include "phy_bb.h"
|
|
#include "rf_hw_tonemap.h"
|
|
#include "mac_rf_rx_hw.h"
|
|
#include "mac_rf_rx_buf_ring.h"
|
|
#include "rf_rx_desc_reg_api.h"
|
|
#include "mac_rf_sched.h"
|
|
#include "phy_rf_chn.h"
|
|
|
|
#if (HW_PLATFORM == HW_PLATFORM_SIMU)
|
|
|
|
void mac_rf_rx_desc_plc_to_rf(iot_pkt_t *rx_pkt)
|
|
{
|
|
rf_rx_buf_hdr_t rf_desc = {0};
|
|
rx_buf_hdr_t *plc_desc;
|
|
|
|
plc_desc = (rx_buf_hdr_t *)iot_pkt_data(rx_pkt);
|
|
|
|
/* attention */
|
|
mac_rf_rx_att_set_rx_mpdu_done(&rf_desc.att,
|
|
mac_rx_att_get_rx_mpdu_done(&plc_desc->att));
|
|
|
|
/* mpdu start */
|
|
os_mem_cpy(mac_rf_rx_mpdu_st_get_phr_addr(&rf_desc.mpdu_st),
|
|
mac_rx_mpdu_st_get_fc_addr(&plc_desc->mpdu_st), FC_LEN);
|
|
mac_rf_rx_mpdu_st_set_avg_snr(&rf_desc.mpdu_st,
|
|
mac_rx_mpdu_st_get_avg_snr(&plc_desc->mpdu_st));
|
|
|
|
/* mpdu end */
|
|
mac_rf_rx_mpdu_end_set_ntb_timestamp(&rf_desc.mpdu_ed,
|
|
mac_rx_mpdu_end_get_ntb_timestamp(&plc_desc->mpdu_ed));
|
|
mac_rf_rx_mpdu_end_set_local_timestamp(&rf_desc.mpdu_ed,
|
|
mac_rx_mpdu_end_get_local_timestamp(&plc_desc->mpdu_ed));
|
|
|
|
/* pb start */
|
|
mac_rf_rx_pb_st_set_msdu_start(&rf_desc.pb_st,
|
|
mac_rx_pb_st_get_msdu_start(&plc_desc->pb_st));
|
|
mac_rf_rx_pb_st_set_msdu_end(&rf_desc.pb_st,
|
|
mac_rx_pb_st_get_msdu_end(&plc_desc->pb_st));
|
|
mac_rf_rx_pb_st_set_pb_ssn(&rf_desc.pb_st,
|
|
mac_rx_pb_st_get_ssn(&plc_desc->pb_st));
|
|
mac_rf_rx_pb_st_set_first_pb(&rf_desc.pb_st,
|
|
mac_rx_pb_st_get_first_pb(&plc_desc->pb_st));
|
|
mac_rf_rx_pb_st_set_last_pb(&rf_desc.pb_st,
|
|
mac_rx_pb_st_get_last_pb(&plc_desc->pb_st));
|
|
mac_rf_rx_pb_st_set_rx_pb_cnt(&rf_desc.pb_st,
|
|
mac_rx_att_get_pb_num(&plc_desc->att));
|
|
|
|
/* pb end */
|
|
mac_rf_rx_pb_end_set_rx_bcn_pld_crc_err(&rf_desc.pb_ed,
|
|
mac_rx_pb_end_get_rx_beacon_pld_crc_err(&plc_desc->pb_ed));
|
|
mac_rf_rx_pb_end_set_rx_pb_crc_err(&rf_desc.pb_ed,
|
|
mac_rx_pb_end_get_rx_pb_crc_err(&plc_desc->pb_ed));
|
|
mac_rf_rx_pb_end_set_pb_crc(&rf_desc.pb_ed,
|
|
mac_rx_pb_end_get_pb_crc(&plc_desc->pb_ed));
|
|
mac_rf_rx_pb_end_set_rx_pb_done(&rf_desc.pb_ed,
|
|
mac_rx_pb_end_get_rx_pb_done(&plc_desc->pb_ed));
|
|
|
|
os_mem_cpy(plc_desc, &rf_desc, sizeof(*plc_desc));
|
|
}
|
|
|
|
#endif
|
|
|
|
static int32_t mac_rf_cal_rf_64ppm(rf_rx_attention *att, int32_t ppm_hz)
|
|
{
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
IOT_ASSERT(att);
|
|
int32_t freq = phy_rf_get_channel_freq_by_id(att->option, att->channel_id);
|
|
int64_t tmp = (int64_t)ppm_hz << (PPM_CALC_MILLION_SHIFT +
|
|
PLC_NTB_PPM_SHIFT);
|
|
return (int32_t)(tmp/freq);
|
|
#else
|
|
(void)att;
|
|
return ppm_hz;
|
|
#endif
|
|
}
|
|
|
|
uint32_t mac_rf_desc_get_pb_head_from_rx_pb_st(uint8_t proto,
|
|
void *pb_st)
|
|
{
|
|
uint32_t pb_header = 0;
|
|
|
|
IOT_ASSERT(pb_st);
|
|
#if SUPPORT_SMART_GRID
|
|
if (PLC_PROTO_TYPE_SG == proto) {
|
|
sg_sof_pb_hdr_t *sg_pb_head = (sg_sof_pb_hdr_t *)&pb_header;
|
|
sg_pb_head->mac_frame_start =
|
|
(uint8_t)mac_rf_rx_pb_st_get_msdu_start(pb_st);
|
|
sg_pb_head->mac_frame_end =
|
|
(uint8_t)mac_rf_rx_pb_st_get_msdu_end(pb_st);
|
|
sg_pb_head->seq = (uint8_t)mac_rf_rx_pb_st_get_pb_ssn(pb_st);
|
|
} else
|
|
#endif
|
|
#if SUPPORT_SOUTHERN_POWER_GRID
|
|
if (PLC_PROTO_TYPE_SPG == proto) {
|
|
spg_sof_pb_hdr_t *spg_pb_head = (spg_sof_pb_hdr_t *)&pb_header;
|
|
spg_pb_head->seq = (uint16_t)mac_rf_rx_pb_st_get_pb_ssn(pb_st);
|
|
} else
|
|
#endif
|
|
{
|
|
//do not delete this case
|
|
}
|
|
|
|
return pb_header;
|
|
}
|
|
|
|
uint32_t mac_rf_rx_hw_mpdu_internal(void *pdev_in, uint32_t ring_id,
|
|
uint32_t quota_ms)
|
|
{
|
|
uint8_t delimiter_type = 0xFF;
|
|
uint8_t proto = (uint8_t)PHY_PROTO_TYPE_GET();
|
|
uint32_t is_retry_mpdu = 0;
|
|
uint32_t ret, cur_ts;
|
|
nid_t nid;
|
|
tei_t my_tei;
|
|
mac_vdev_t *plc_vdev;
|
|
mac_peer_t *peer;
|
|
mac_stream_t *stream;
|
|
mac_rf_pdev_t *rf_pdev;
|
|
mac_rf_vdev_t *rf_vdev;
|
|
iot_pkt_t *iot_pkt_array[1] = { 0 };
|
|
iot_pkt_t *cur_pkt_buf;
|
|
rx_buf_ring_t *ring;
|
|
mac_rx_info_t *rx_info;
|
|
rf_rx_attention *att;
|
|
rf_rx_mpdu_start *mpdu_st;
|
|
rf_rx_mpdu_end *mpdu_ed;
|
|
rf_rx_pb_start *pb_st;
|
|
rf_rx_pb_end *pb_ed;
|
|
uint8_t *payload;
|
|
rx_fc_msg_t rx_fc_msg = { 0 };
|
|
uint8_t is_vdev_found;
|
|
uint8_t is_not_my_ucast, is_hwcrc_err;
|
|
uint8_t *data;
|
|
uint32_t pbsz;
|
|
int8_t rssi;
|
|
int8_t snr;
|
|
int32_t ppm;
|
|
uint8_t cert_mode;
|
|
|
|
rf_pdev = (mac_rf_pdev_t*)pdev_in;
|
|
|
|
#if HW_PLATFORM == HW_PLATFORM_SIMU
|
|
ring = &rf_pdev->simu.rx_ring[ring_id];
|
|
#else
|
|
ring = &rf_pdev->ring_hdl.ring[ring_id];
|
|
#endif
|
|
|
|
cur_ts = os_boot_time32();
|
|
do {
|
|
/* check ring buffer is empty */
|
|
if (0 == rf_pop_buf_from_ring(ring, 1, iot_pkt_array)) {
|
|
break;
|
|
}
|
|
|
|
cur_pkt_buf = iot_pkt_array[0];
|
|
|
|
if (g_fw_mode != FTM_MODE && (rf_pdev->rf_vdev[0]->stop_flag ||
|
|
rf_pdev->rf_vdev[0]->tx_rx_suspend)) {
|
|
goto rf_free_pkt;
|
|
}
|
|
|
|
#if (HW_PLATFORM == HW_PLATFORM_SIMU)
|
|
mac_rf_rx_desc_plc_to_rf(cur_pkt_buf);
|
|
#endif
|
|
data = iot_pkt_data(cur_pkt_buf);
|
|
att = (rf_rx_attention *)(data + RF_RX_ATTENTION_OFFSET);
|
|
mpdu_st = (rf_rx_mpdu_start *)(data + RF_RX_MPDU_START_OFFSET);
|
|
mpdu_ed = (rf_rx_mpdu_end *)(data + RF_RX_MPDU_END_OFFSET);
|
|
pb_st = (rf_rx_pb_start *)(data + RF_RX_PB_START_OFFSET);
|
|
pb_ed = (rf_rx_pb_end *)(data + RF_RX_PB_END_OFFSET);
|
|
payload = data + RF_RX_PB_PAYLOAD_OFFSET;
|
|
|
|
if (!mac_rf_rx_pb_end_get_rx_pb_done(pb_ed)) {
|
|
iot_printf("-----RF: Not done PB!-----\n");
|
|
goto rf_free_pkt;
|
|
}
|
|
|
|
/* for sg rf protocol, 1mpdu contains 1pb */
|
|
if (!mac_rf_rx_att_get_rx_mpdu_done(att)) {
|
|
//TODO: add mpdu not done cnt
|
|
goto rf_free_pkt;
|
|
}
|
|
|
|
/* check rx exception */
|
|
if (mac_rf_rx_att_get_rx_status(att)) {
|
|
mac_rf_rx_debug_log_exception(iot_pkt_array[0]);
|
|
goto rf_free_pkt;
|
|
}
|
|
|
|
/* record ppm hz */
|
|
ppm = mac_rf_rx_mpdu_st_get_rx_ppmhz(mpdu_st);
|
|
/* record 1/64 ppm to mpdu */
|
|
mac_rf_rx_mpdu_st_set_rx_ppmhz(mpdu_st, mac_rf_cal_rf_64ppm(att, ppm));
|
|
|
|
//TODO: check ring overflow
|
|
|
|
/* process the pb if ring pb callback exist */
|
|
if (rf_pdev->ring_hdl.mpdu_pb_cb) {
|
|
ret = rf_pdev->ring_hdl.mpdu_pb_cb(rf_pdev, cur_pkt_buf);
|
|
if (CON_PKT_NOT_FREE == ret) {
|
|
/* cert mode loopback */
|
|
ring->cur_mpdu = NULL;
|
|
continue;
|
|
} else if(CON_PKT_FREE == ret) {
|
|
/* cert mode other test case */
|
|
goto rf_free_pkt;
|
|
} else if (CON_PKT_NOT_CARE == ret) {
|
|
/* continue rx path */
|
|
}
|
|
}
|
|
|
|
mac_rf_get_rx_frm_msg_from_fc(proto,
|
|
mac_rf_rx_mpdu_st_get_phr_addr(mpdu_st), &rx_fc_msg);
|
|
nid = mac_get_nid_from_fc(proto,
|
|
mac_rf_rx_mpdu_st_get_phr_addr(mpdu_st));
|
|
#if (ENA_RX_DIFF_NID_BCAST)
|
|
if ((FC_DELIM_SOF == delimiter_type)
|
|
&& (PLC_TEI_BCAST == rx_fc_msg.dst_tei)
|
|
&& !mac_get_cert_test_mode()) {
|
|
/* if bcast then force nid = local nid to rx in the
|
|
* same vdev.
|
|
*/
|
|
mac_vdev_t *dft_vdev = find_vdev_by_nid(PLC_PDEV_ID, nid);
|
|
if (NULL == dft_vdev) {
|
|
//TODO: maybe use reduced vdev
|
|
dft_vdev = get_vdev_ptr(PLC_PDEV_ID, PLC_PDEV_ID);
|
|
}
|
|
vdev_get_nid(dft_vdev, &nid);
|
|
}
|
|
#endif
|
|
|
|
/* sta spur check */
|
|
/* pb ok and fc valid */
|
|
if (pb_ed->rx_pb_crc_err == 0 &&
|
|
mac_rx_hw_check_fc_valid(
|
|
(uint32_t *)mac_rf_rx_mpdu_st_get_phr_addr(mpdu_st))) {
|
|
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
|
|
/* sta check spur restart */
|
|
mac_sta_check_spur_timer_restart(
|
|
&pdev->mac_check_spur_ctxt, (nid == mac_get_hw_nid()));
|
|
}
|
|
|
|
delimiter_type = (uint8_t)mac_get_rx_delimiter_from_fc(proto,
|
|
mac_rf_rx_mpdu_st_get_phr_addr(mpdu_st));
|
|
|
|
/* get plc vdev by nid */
|
|
plc_vdev = find_vdev_by_nid(PLC_PDEV_ID, nid);
|
|
if (plc_vdev) {
|
|
rf_vdev = rf_pdev->rf_vdev[0];
|
|
} else {
|
|
rf_vdev = NULL;
|
|
}
|
|
peer = NULL;
|
|
stream = NULL;
|
|
is_vdev_found = 0;
|
|
is_not_my_ucast = 0;
|
|
is_hwcrc_err = 0;
|
|
cert_mode = mac_get_cert_test_mode();
|
|
if (plc_vdev &&
|
|
(mac_vdev_cfg_get_node_role(plc_vdev) != PLC_DEV_ROLE_CCO)) {
|
|
mac_rf_scan_update_rx_status(plc_vdev, &rf_pdev->rf_scan,
|
|
rx_fc_msg.nid, (uint8_t)att->channel_id);
|
|
}
|
|
|
|
switch (delimiter_type) {
|
|
case FC_DELIM_SOF:
|
|
{
|
|
pbsz = phy_rf_get_pbsz(rx_fc_msg.rf_pb_sz_idx);
|
|
|
|
if (!rf_vdev) {
|
|
/* vdev not found, drop this SOF by force crc error */
|
|
mac_rf_rx_pb_end_set_rx_pb_crc_err(pb_ed, 1);
|
|
goto rf_handle_sof;
|
|
} else {
|
|
is_vdev_found = 1;
|
|
}
|
|
|
|
if (mac_rf_rx_pb_st_get_pb_ssn(pb_st) != 0 ||
|
|
mac_rf_rx_pb_st_get_msdu_start(pb_st) != 1 ||
|
|
mac_rf_rx_pb_st_get_msdu_end(pb_st) != 1) {
|
|
mac_rf_rx_pb_end_set_rx_pb_crc_err(pb_ed, 1);
|
|
goto rf_handle_sof;
|
|
}
|
|
|
|
/* fix spg msdu_start/msdu_end */
|
|
if (PLC_PROTO_TYPE_SPG == proto) {
|
|
/**
|
|
* sof msdu_start and msdu_end
|
|
* fields always 0 in SPG protocol
|
|
*/
|
|
if (0 == mac_rf_rx_pb_st_get_pb_ssn(pb_st)) {
|
|
mac_rf_rx_pb_st_set_msdu_start(pb_st, 1);
|
|
}
|
|
/* spg must be used long mpdu tx */
|
|
if (mac_rf_rx_pb_st_get_last_pb(pb_st) &&
|
|
(mac_rf_rx_pb_st_get_rx_pb_cnt(pb_st) ==
|
|
(mac_rf_rx_pb_st_get_pb_ssn(pb_st) + 1))){
|
|
mac_rf_rx_pb_st_set_msdu_end(pb_st, 1);
|
|
}
|
|
}
|
|
|
|
/* find peer information */
|
|
if (rx_fc_msg.dst_tei != PLC_TEI_BCAST) {
|
|
my_tei = vdev_get_tei(plc_vdev);
|
|
|
|
/* check unicast is dircet self */
|
|
if (rx_fc_msg.dst_tei != my_tei) {
|
|
if (mac_rf_rx_pb_end_get_rx_pb_crc_err(pb_ed)) {
|
|
/* if pb error, not check and handle sof */
|
|
goto rf_handle_sof;
|
|
}
|
|
|
|
uint8_t is_drop_chk = 0;
|
|
|
|
/* for cco, if the networking is not started
|
|
* (nid is not set), try to receive all unicast packets
|
|
*/
|
|
if (mac_vdev_cfg_get_node_role(plc_vdev)
|
|
== PLC_DEV_ROLE_CCO) {
|
|
nid_t tmp_nid;
|
|
if (ERR_OK == vdev_get_nid(plc_vdev, &tmp_nid)) {
|
|
is_drop_chk = 1;
|
|
}
|
|
} else {
|
|
is_drop_chk = (PLC_PROTO_TYPE_SPG == proto) ?
|
|
(vdev_get_tei(plc_vdev) != 0) : 1;
|
|
}
|
|
|
|
/* check mac header dtei */
|
|
if (is_drop_chk) {
|
|
if (mac_msdu_is_std_mac_header(payload)) {
|
|
tei_t mac_hd_dtei =
|
|
((mac_header_t *)payload)->org_dest_tei;
|
|
if ((mac_hd_dtei != PLC_TEI_INVAL)
|
|
&& (mac_hd_dtei != my_tei)) {
|
|
/* set pb error force drop this pb */
|
|
mac_rf_rx_pb_end_set_rx_pb_crc_err(pb_ed, 1);
|
|
is_not_my_ucast = 1;
|
|
goto rf_handle_sof;
|
|
}
|
|
} else {
|
|
/* for mac_short_header, not contain the dtei,
|
|
* need drop it.
|
|
*/
|
|
mac_rf_rx_pb_end_set_rx_pb_crc_err(pb_ed, 1);
|
|
is_not_my_ucast = 1;
|
|
goto rf_handle_sof;
|
|
}
|
|
}
|
|
}
|
|
|
|
peer = find_peer(plc_vdev, nid, (tei_t)rx_fc_msg.src_tei);
|
|
} else {
|
|
/* for bacast */
|
|
peer = plc_vdev->bcast_peer;
|
|
}
|
|
|
|
mac_rf_rx_debug_log_sof_info(rx_fc_msg, mpdu_st, mpdu_ed,
|
|
pb_st, pb_ed, att);
|
|
|
|
#if ENA_SW_PBCRC_CHECK
|
|
if (mac_rf_rx_pb_end_get_rx_pb_crc_err(pb_ed) == 0) {
|
|
uint32_t pb_head =
|
|
mac_rf_desc_get_pb_head_from_rx_pb_st(proto, pb_st);
|
|
uint32_t crc_cal;
|
|
crc_cal = mac_crc_get_pb_swcrc(proto, &pb_head,
|
|
payload, pbsz, FC_DELIM_SOF);
|
|
if (crc_cal != mac_rf_rx_pb_end_get_pb_crc(pb_ed)) {
|
|
iot_printf("crccal:0x%x, getcrc:0x%x\n", crc_cal,
|
|
mac_rf_rx_pb_end_get_pb_crc(pb_ed));
|
|
pb_ed->rx_pb_crc_err = 1;
|
|
is_hwcrc_err = 1;
|
|
goto rf_handle_sof;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!peer) {
|
|
/* if the peer is not exist, create it right now */
|
|
ret = mac_peer_alloc(plc_vdev, (tei_t)rx_fc_msg.src_tei,
|
|
0, 1, 0, 0, &peer);
|
|
if (ret) {
|
|
/* create peer failed */
|
|
IOT_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
/* find stream information */
|
|
stream = find_stream(peer, nid, (tei_t)rx_fc_msg.src_tei,
|
|
(lid_t)rx_fc_msg.lid, IS_RX_STREAM, IS_RF_STREAM);
|
|
if (!stream) {
|
|
/* if stream is not found create it now */
|
|
ret = mac_stream_alloc(peer, IS_RX_STREAM, (lid_t)rx_fc_msg.lid,
|
|
IS_RF_STREAM, &stream);
|
|
if ((ret != ERR_OK) && (ret != ERR_EXIST)) {
|
|
/* create stream failed */
|
|
IOT_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
is_retry_mpdu = rx_fc_msg.retry;
|
|
|
|
rf_handle_sof:
|
|
if (mac_rf_rx_pb_end_get_rx_pb_crc_err(pb_ed)) {
|
|
ppm = mac_rf_rx_mpdu_st_get_rx_ppmhz(mpdu_st);
|
|
iot_printf("rf sof pb dropped: is_hwcrc_err:%d, "
|
|
"not_my_ucast:%d, vdev_found:%d,"
|
|
"phrmcs:%d, pldmcs:%d, pbidx:%d, "
|
|
"dtei:%d, stei:%d, nid:0x%x, snr:%d, rssi:%d, "
|
|
"hwppm:%d - %d\n",
|
|
is_hwcrc_err, is_not_my_ucast, is_vdev_found,
|
|
att->phr_mcs, att->pld_mcs, pb_st->pb_sz_idx,
|
|
rx_fc_msg.dst_tei, rx_fc_msg.src_tei,
|
|
rx_fc_msg.nid, mpdu_st->avg_snr, mpdu_st->rssi,
|
|
/* 1/64 ppm */
|
|
ppm,
|
|
/* ppm */
|
|
ppm >> PLC_NTB_PPM_SHIFT
|
|
);
|
|
goto rf_free_pkt;
|
|
} else {
|
|
reorder_buf_insert(&stream->msdu.rx.reorder_buf,
|
|
cur_pkt_buf,
|
|
mac_rf_rx_pb_st_get_pb_ssn(pb_st),
|
|
mac_rf_rx_pb_st_get_msdu_start(pb_st),
|
|
mac_rf_rx_pb_st_get_msdu_end(pb_st),
|
|
is_retry_mpdu,
|
|
pbsz
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
case FC_DELIM_BEACON:
|
|
{
|
|
uint32_t local_ts = mac_rf_rx_mpdu_end_get_local_timestamp(mpdu_ed);
|
|
uint32_t ntb_ts = mac_rf_rx_mpdu_end_get_ntb_timestamp(mpdu_ed);
|
|
snr = mac_rf_rx_mpdu_st_get_avg_snr(mpdu_st);
|
|
uint8_t is_chk_bcn_ppm = 1;
|
|
uint8_t is_self_nid = 0;
|
|
|
|
mac_rf_rx_debug_log_bcn_info(&rx_fc_msg, mpdu_st, mpdu_ed, pb_ed);
|
|
|
|
if (!mac_rx_hw_check_fc_valid(
|
|
(uint32_t *)mac_rf_rx_mpdu_st_get_phr_addr(mpdu_st))) {
|
|
goto rf_free_pkt;
|
|
}
|
|
|
|
if (!plc_vdev) {
|
|
/* force first vdev, and upload all bcn */
|
|
plc_vdev = get_vdev_ptr(PLC_PDEV_ID, PLC_PDEV_ID);
|
|
rf_vdev = rf_pdev->rf_vdev[0];
|
|
}
|
|
|
|
if ((nid != PLC_NID_INVALID) && (rf_vdev_get_node_role(rf_vdev)
|
|
== PLC_DEV_ROLE_STA)) {
|
|
/* if STA mode we need to sync the crystal disparity */
|
|
nid_t sync_nid;
|
|
tei_t sync_proxy = mac_rf_vdev_get_sync_proxy(rf_vdev);
|
|
nid_t my_nid;
|
|
tei_t my_proxy = vdev_get_proxy_tei(plc_vdev);
|
|
|
|
mac_rf_vdev_get_sync_nid(rf_vdev, &sync_nid);
|
|
vdev_get_nid(plc_vdev, &my_nid);
|
|
|
|
if (my_nid == PLC_NID_INVALID && sync_nid == PLC_NID_INVALID) {
|
|
/* for sync nid not set case set first seen nid to
|
|
* be sync. Because at some large ppm case, the BCN
|
|
* PLD always CRC error and CVG can't decide which
|
|
* one to join, if CVG find this one is the correct
|
|
* one, CVG should notify mac the preferred the nid
|
|
* through PLC_VDEV_CFG_SET_PREFER_NID.
|
|
*/
|
|
if (nid != PLC_NID_INVALID && !vdev_is_bl_nid(plc_vdev, nid)
|
|
&& rx_fc_msg.src_tei != PLC_TEI_INVAL) {
|
|
mac_rf_vdev_set_sync_nid(rf_vdev, nid);
|
|
mac_rf_vdev_set_sync_proxy(rf_vdev,
|
|
(tei_t)rx_fc_msg.src_tei);
|
|
}
|
|
}
|
|
|
|
/* get rf ppm from wphy interface */
|
|
int16_t rfppm = (int16_t)mac_rf_rx_mpdu_st_get_rx_ppmhz(mpdu_st);
|
|
|
|
if (my_nid == nid) {
|
|
/* sync with joined network if available */
|
|
if (rx_fc_msg.src_tei == my_proxy) {
|
|
int16_t ppm_err = PLC_MAX_MAC_NTB_PPM;
|
|
mac_rf_ntb_ppm_sync(rf_vdev,
|
|
rx_fc_msg.time_stamp, local_ts, ntb_ts,
|
|
vdev_get_bc_period_ms(plc_vdev, proto),
|
|
&ppm_err, rfppm);
|
|
(void)ppm_err;
|
|
is_chk_bcn_ppm = 0;
|
|
}
|
|
is_self_nid = 1;
|
|
} else if (nid == sync_nid) {
|
|
/* sync with target nid */
|
|
if (rx_fc_msg.src_tei == sync_proxy) {
|
|
int16_t ppm_err = PLC_MAX_MAC_NTB_PPM;
|
|
/* if sta's nid is current syncing nid, and
|
|
* proxy and phase is match or is not assoc,
|
|
* just sync the crystal's freq disparity btw
|
|
* the nodes and the self node, we assume all
|
|
* the nodes in the network are all synced
|
|
*/
|
|
/* we are focus on the
|
|
* network, so we use SW calculation
|
|
* which is more accurate
|
|
*/
|
|
mac_rf_ntb_ppm_sync(rf_vdev,
|
|
rx_fc_msg.time_stamp, local_ts, ntb_ts,
|
|
vdev_get_bc_period_ms(plc_vdev, proto),
|
|
&ppm_err, rfppm);
|
|
(void)ppm_err;
|
|
}
|
|
}
|
|
}
|
|
|
|
//TODO: add sta sync the crystal disparity code
|
|
|
|
if (mac_rf_rx_pb_end_get_rx_pb_crc_err(pb_ed)) {
|
|
//TODO: add rx bcn pb error cnt
|
|
if (rx_fc_msg.src_tei == PLC_TEI_CCO) {
|
|
mac_sched_cco_snr_rx(plc_vdev, nid, snr,
|
|
(uint8_t)mac_rf_rx_att_get_channel_id(att),
|
|
(uint8_t)mac_rf_rx_att_get_option(att), 1,
|
|
BEACON_FREQ_BAND_ID_INVALID);
|
|
}
|
|
/* free the error pb */
|
|
goto rf_free_pkt;
|
|
}
|
|
|
|
pbsz = phy_rf_get_pbsz(rx_fc_msg.rf_pb_sz_idx);
|
|
if (rf_vdev->rf_start_cfg.mac_bc_rx_func) {
|
|
BUILD_BUG_ON(sizeof(mac_rx_info_t) < (RF_RX_PB_PAYLOAD_OFFSET
|
|
- sizeof(*att) - FC_LEN));
|
|
rx_info = (mac_rx_info_t *)iot_pkt_pull(cur_pkt_buf,
|
|
RF_RX_PB_PAYLOAD_OFFSET - sizeof(*rx_info));
|
|
uint8_t *bcn_pld = iot_pkt_pull(cur_pkt_buf, sizeof(*rx_info));
|
|
if (NULL == iot_pkt_set_tail(cur_pkt_buf, bcn_pld + pbsz)) {
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)cur_pkt_buf, 17);
|
|
goto rf_free_pkt;
|
|
}
|
|
|
|
/* todo: mac_convert_fc_rf_to_hplc() */
|
|
os_mem_cpy(rx_info->fc, mac_rf_rx_mpdu_st_get_phr_addr(mpdu_st),
|
|
FC_LEN);
|
|
rssi = mac_rf_rx_mpdu_st_get_rssi(mpdu_st);
|
|
if (rssi != INV_RSSI_RF) {
|
|
rssi = min(MAX_RSSI_RF, rssi);
|
|
rssi = max(MIN_RSSI_RF, rssi);
|
|
}
|
|
rx_info->delta_ntb = rx_fc_msg.time_stamp
|
|
- mac_rf_rx_mpdu_end_get_ntb_timestamp(mpdu_ed);
|
|
rx_info->phy.is_rf = 1;
|
|
rx_info->phy.band_id = BEACON_FREQ_BAND_ID_INVALID;
|
|
rx_info->phy.channel_id = (uint8_t)att->channel_id;
|
|
rx_info->phy.rf_option = (uint8_t)att->option;
|
|
rx_info->phy.phase = PLC_PHASE_ALL;
|
|
rx_info->phy.snr = snr;
|
|
rx_info->phy.rssi = rssi;
|
|
|
|
if ((mac_vdev_cfg_get_node_role(plc_vdev) != PLC_DEV_ROLE_CCO)
|
|
&& !cert_mode && is_self_nid) {
|
|
if (is_chk_bcn_ppm && plc_vdev->bcn_ctx.sta.ntb_sync_done) {
|
|
int16_t tmp_ppm;
|
|
mac_ntb_record_ctxt_t tmp_ntb_record;
|
|
os_mem_cpy(&tmp_ntb_record, &rf_vdev->sync_ntb_record,
|
|
sizeof(tmp_ntb_record));
|
|
tmp_ppm = mac_ppm_cal(&tmp_ntb_record,
|
|
rx_fc_msg.time_stamp, local_ts, ntb_ts, 1);
|
|
if (IOT_ABS(tmp_ppm) > RF_SYNC_NTB_MAX_PPM) {
|
|
rx_info->delta_ntb = 0;
|
|
} else {
|
|
os_mem_cpy(&rf_vdev->sync_ntb_record,
|
|
&tmp_ntb_record, sizeof(tmp_ntb_record));
|
|
}
|
|
} else {
|
|
os_mem_cpy(&rf_vdev->sync_ntb_record,
|
|
&rf_vdev->mac_rf_ppm,
|
|
sizeof(rf_vdev->sync_ntb_record));
|
|
}
|
|
}
|
|
|
|
mac_beacon_rx((uint8_t)proto, plc_vdev, cur_pkt_buf);
|
|
|
|
//TODO: add rx bcn ok cnt
|
|
} else {
|
|
goto rf_free_pkt;
|
|
}
|
|
break;
|
|
}
|
|
case FC_DELIM_SACK:
|
|
{
|
|
//TODO: later will handle rf ckq rx
|
|
//if ((rx_fc_msg.sack_ext_deli == SACK_EXT_TYPE_SYNC) ||
|
|
// (rx_fc_msg.sack_ext_deli == SACK_EXT_TYPE_SEARCH)) {
|
|
// mac_ckq_rx_and_ppm_sync(pdev, vdev, &rx_fc_msg,
|
|
// iot_pkt_array[0]);
|
|
// goto rf_free_pkt;
|
|
//} else
|
|
/* todo: mac_convert_fc_rf_to_hplc() */
|
|
{
|
|
if (!rf_vdev) {
|
|
/* vdev not found, drop this SACK
|
|
*/
|
|
goto rf_free_pkt;
|
|
}
|
|
if (rx_fc_msg.dst_tei != vdev_get_tei(plc_vdev)) {
|
|
/* if not dest for me, drop it */
|
|
goto rf_free_pkt;
|
|
}
|
|
|
|
peer = find_peer(plc_vdev, nid, (tei_t)rx_fc_msg.src_tei);
|
|
if (!peer) {
|
|
/* if the peer is not exist,
|
|
* create it right now
|
|
*/
|
|
ret = mac_peer_alloc(plc_vdev, (tei_t)rx_fc_msg.src_tei,
|
|
0, 1, 0, 0, &peer);
|
|
if (ret) {
|
|
/* create peer failed */
|
|
IOT_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
/* update the rate info in peer */
|
|
if (rf_vdev->ra_cb) {
|
|
rf_vdev->ra_cb(peer, &rx_fc_msg);
|
|
}
|
|
|
|
/* TODO: confirm should free temp peer or not */
|
|
mac_peer_del_temp_peer(peer);
|
|
|
|
goto rf_free_pkt;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
iot_printf("-----RF: Unknown MPDU-----\n");
|
|
goto rf_free_pkt;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
|
|
rf_free_pkt:
|
|
iot_pkt_free(cur_pkt_buf);
|
|
|
|
} while ((uint32_t)(os_boot_time32() - cur_ts) < quota_ms);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t mac_rf_rx_hw_mpdu(void *pdev, uint32_t ring_id, uint32_t quota_ms)
|
|
{
|
|
uint32_t ret = ERR_OK;
|
|
rx_buf_ring_t *ring; //TODO: fix to rf ring buffer context
|
|
#if HW_PLATFORM == HW_PLATFORM_SIMU
|
|
ring = &((mac_rf_pdev_t*)pdev)->simu.rx_ring[ring_id];
|
|
#else
|
|
ring = &((mac_rf_pdev_t*)pdev)->ring_hdl.ring[ring_id];
|
|
#endif
|
|
|
|
if (!ring->msg_delivered) {
|
|
/* if not delivered, queue the msg */
|
|
mac_msg_t *msg = mac_alloc_msg();
|
|
|
|
if (msg == NULL) {
|
|
IOT_ASSERT(0);
|
|
ret = ERR_NOMEM;
|
|
goto out;
|
|
}
|
|
|
|
msg->type = MAC_MSG_TYPE_DSR;
|
|
msg->id = MAC_MSG_ID_DSR_RX_TO_MSG;
|
|
/* bit0~bit15: ring id.
|
|
* bit16: indicate ring type. 0 - plc ring, 1 - rf ring.
|
|
*/
|
|
msg->data1 = (1 << 16) | (ring_id & 0xFFFF);
|
|
msg->data2 = pdev;
|
|
msg->data3 = (void*)quota_ms;
|
|
mac_queue_msg(msg, MAC_MSG_QUEUE_MP);
|
|
|
|
/* TODO: this is assume in the same task of MAC */
|
|
ring->msg_delivered = 1;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
#else
|
|
|
|
uint32_t mac_rf_rx_hw_mpdu_internal(void *pdev_in, uint32_t ring_id,
|
|
uint32_t quota_ms)
|
|
{
|
|
(void)pdev_in;
|
|
(void)ring_id;
|
|
(void)quota_ms;
|
|
return 0;
|
|
}
|
|
|
|
#endif /* HPLC_RF_DEV_SUPPORT */
|