/**************************************************************************** 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_task.h" #include "hw_reg_api.h" #include "mac_sys_reg.h" #include "mac_reset.h" #include "mpdu_header.h" #include "ahb.h" #include "plc_protocol.h" #include "dbg_msg_pop.h" #include "iot_io_api.h" #include "iot_clock.h" #include "iot_errno.h" #include "iot_module.h" #include "iot_ftm_msg.h" #include "iot_board.h" #if IOT_MP_SUPPORT == 1 && HPLC_RF_DEV_SUPPORT #include "rf_mac_int.h" #include "rf_mac_reg.h" #include "rfplc_reg_base.h" #include "rf_hw_tonemap.h" #include "phy_rf_init.h" #include "phy_rf_chn.h" #include "rf_mac_tx.h" #include "mac_rf_isr.h" #include "mac_rf_tx_hw.h" #include "mac_rf_rx_buf_ring.h" #include "mac_rf_common_hw.h" #include "mac_rf_txq_hw.h" #include "iot_system.h" /* hplc mac and phy Common header */ #include "phy_txrx_pwr.h" #include "phy_chn.h" #include "phy_bb.h" #include "mac_sys_reg.h" #include "mac_rx_descriptor_reg.h" #include "rx_desc_reg_api.h" #include "mpdu_header.h" #include "mac_rx_buf_ring.h" #include "tx_entry.h" #include "hw_rx.h" #include "bb_init.h" #include "bb_rf_cfg.h" #include "rf_phy_tx.h" #include "rf_phy_rx.h" #include "phy_ada_dump.h" #include "iot_pt_rf_func.h" #include "iot_gpio_api.h" #include "iot_led.h" #include "iot_board_api.h" #include "mp_mode.h" #include "math_log10.h" #include "iot_crc_api.h" #include "iot_bitmap_api.h" #include "hw_reg_api.h" #include "phy_reg.h" /* define mp rf tx descriptors count */ #define MP_RF_TX_DESC_CNT 2 /* test massage magic number */ #define MP_RF_TEST_MSG_MAGIC_NUMBER 0x55AA55AA /* define mp rf csr tx max count */ #define MP_RF_CSR_TX_MAX_COUNT 200 /* maximum number of TX EVM samples */ #define MP_RF_TX_EVM_SMAP_MAX_CNT 1000 /* default time limit of CSI test, unit: ms */ #define MP_RF_TEST_CASE_CSI_TIMEOUT_DEF 1000 /* default time limit of CSR test, unit: ms */ #define MP_RF_TEST_CASE_CSR_TIMEOUT_DEF 1000 /* max time limit of CSR test, unit: ms */ #define MP_RF_TEST_CASE_CSR_TIMEOUT_MAX 5000 /* default time limit of TX EVM test, unit: ms */ #define MP_RF_TEST_CASE_TX_EVM_TIMEOUT_DEF 1000 /* default time limit of change phy option test, unit: ms */ #define MP_RF_TEST_CASE_CHG_PHY_TIMEOUT_DEF 900 /* default time delay of change phy option, unit: ms */ #define MP_RF_TEST_CASE_CHG_PHY_EXEC_DELAY 600 /* define the number of times the command is sent repeatedly */ #define MP_RF_CMD_RETRY_COUNT 4 /* define the repeated sending interval of the command */ #define MP_RF_CMD_RETRY_INTERVAL 100 /* define invalid rssi of snr value */ #define MP_RF_INVAL_RSSI_SNR (-127) /* default snr threshold of CSI test */ #define MP_RF_CSI_TEST_SNR_THR 10 /* default snr threshold of CSI test */ #define MP_RF_CSI_TEST_RSSI_THR (-110) /* define mp rf golden common timer period, unit:ms*/ #define MP_RF_GOLDEN_COMMON_TIMER_PERIOD (100) /* default time limit of TX CALI test, unit: ms */ #define MP_RF_TEST_CASE_TX_CALI_TIMEOUT_DEF 1000 /* define rf phy iq phase compensation maximum code */ #define RF_PHY_IQ_PHASE_COMPEN_CODE_MAX 32 /* define rf phy iq magnitude compensation maximum code */ #define RF_PHY_IQ_MAG_COMPEN_CODE_MAX 16 /* define the size of tx cali data array */ #define MP_RF_TEST_CASE_TX_CALI_SNR_SAMP_BUF_SIZE \ (RF_PHY_IQ_PHASE_COMPEN_CODE_MAX * RF_PHY_IQ_PHASE_COMPEN_CODE_MAX) /* judge whether the value of phase is within the range */ #define rf_phy_iq_phase_compen_code_valid(v) (v >= 0 && \ v < RF_PHY_IQ_PHASE_COMPEN_CODE_MAX) /* judge whether the value of mag is within the range */ #define rf_phy_iq_mag_compen_code_valid(v) (v >= 0 && \ v < RF_PHY_IQ_MAG_COMPEN_CODE_MAX) /* The maximum number of best compensation results calculated from snr samples. */ #define MP_RF_TX_CALI_SNR_BEST_RESULT_MAX 3 /* how many i/q combinations of snr data can be recorded */ #define MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_SIZE 81 /* how many sets of data can be recorded for each i/q combination */ #define MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_DEPTH 30 /* define the size of tx cali bitmap array */ #define MP_RF_TX_CALI_SNR_BM_SIZE 128 /* convert the i/q combination to a large number */ #define MP_RF_IQ_CODE_TO_MAGIC(max_code, i, q) ((i) * (max_code) + (q)) /* minimum number of points required for linear fitting */ #define MP_RF_TX_CALI_SNR_LINER_FIT_VALID_SAMP_NUM 6 /* define MP rf test message id */ #define MP_RF_MSG_ID_CSI 0 #define MP_RF_MSG_ID_CSR 1 #define MP_RF_MSG_ID_TX_EVM_SAMP 2 #define MP_RF_MSG_ID_TX_EVM_STAT_QUERY 3 #define MP_RF_MSG_ID_CHG_PHY 4 #define MP_RF_MSG_ID_TX_CALI_STAT_QUERY 5 /* define event id */ #define MP_RF_EVT_ID_RF_RX 0 #define MP_RF_EVT_ID_PLC_RX 1 #define MP_RF_EVT_ID_TIMEROUT 2 /* enable/disable Calibration measurement data dump */ #define MP_RF_CAL_MEAS_DUMP_EN 0 /* define the maximum average number of calibration measurements */ #define MP_RF_CAL_MEAS_AVG_CNT_MAX 128 /* define the maximum average number of calibration measurements */ #define MP_RF_CAL_MEAS_AVG_CNT_DEFAULT 32 #if SUPPORT_SOUTHERN_POWER_GRID /* define the tmi used for PLC communication with less data */ #define MP_RF_PLC_NORMAL_PACKET_TMI MAC_TMI_6 /* define the tmi used for PLC communication with more data */ #define MP_RF_PLC_LARGE_PACKET_TMI MAC_TMI_0 /* define plc init band */ #define MP_RF_PLC_INIT_BAND IOT_SUPPORT_TONE_100_230 #else /* SUPPORT_SOUTHERN_POWER_GRID */ /* define the tmi used for PLC communication with less data */ #define MP_RF_PLC_NORMAL_PACKET_TMI MAC_TMI_13 /* define the tmi used for PLC communication with more data */ #define MP_RF_PLC_LARGE_PACKET_TMI MAC_TMI_12 /* define plc init band */ #define MP_RF_PLC_INIT_BAND IOT_SUPPORT_TONE_240_370 #endif #pragma pack(push) /* save the pack status */ #pragma pack(1) /* 1 byte align */ /* command message layout, from dut to golden */ typedef struct { /* magic number, fixed as MP_RF_TEST_MSG_MAGIC_NUMBER */ uint32_t magic; /* message id, see MP_RF_MSG_ID_XXX */ uint8_t msg_id; /* golden tx phr mcs, see MCS_ID_X */ uint8_t phr_mcs; /* golden tx payload mcs, see MCS_ID_X */ uint8_t pld_mcs; /* golden tx pb block size, see BLOCK_SIZE_XXX */ uint8_t pld_blkz; /* golden tx power, uint is dbm */ int8_t power; /* data payload label*/ uint8_t data[0]; } mp_rf_test_cmd_hdr_t; /* CSR cmd payload layout */ typedef struct { /* packet count */ uint16_t packet_num; /* mac address of dut */ uint8_t mac_addr[IOT_MAC_ADDR_LEN]; /* generation timestamp of the command */ uint32_t ts; /* if set, golden uses test mode power configuration. */ uint8_t is_test_mode : 1, /* reserved field 0 for further use */ rsvd0 : 7; /* time interval when Golden sending packets, unit: us. */ uint16_t interval; /* reserved field 1 for further use */ uint8_t rsvd1[5]; } mp_rf_test_cmd_csr_t; /* TX EVM cmd payload layout */ typedef struct { /* mac address of dut */ uint8_t mac_addr[IOT_MAC_ADDR_LEN]; /* generation timestamp of the command */ uint32_t ts; /* reserved for further use */ uint8_t rsvd[8]; } mp_rf_test_cmd_tx_evm_t; /* change phy cmd payload layout */ typedef struct { /* rf option, see RF_OPTION_XXX */ uint8_t option; /* rf channel, RF_CHANNEL_ID_XXX */ uint8_t channel; } mp_rf_test_cmd_chg_phy_t; /* TX CALI cmd payload layout */ typedef struct { /* magic number of dev_id */ uint16_t dev_id_magic; /* tx cali type, see RF_TEST_TX_CALI_REG_IQ_XXX */ uint8_t type; /* flag to mark whether to use original data */ uint8_t liner_fit_en; /* reserved for further use */ uint8_t rsvd[8]; } mp_rf_test_cmd_tx_cali_stat_qr_t; /* response message layout, from golden to dut */ typedef struct { /* magic number, fixed as MP_RF_TEST_MSG_MAGIC_NUMBER */ uint32_t magic; /* message id, see MP_RF_MSG_ID_XXX */ uint8_t msg_id; /* rssi for received from dut packets */ int8_t tx_rssi; /* snr for received from dut packets */ int8_t tx_snr; /* ppm for received from dut packets */ int8_t tx_ppm; /* adc gain for received from dut packets */ uint8_t tx_gain; /* data payload label */ uint8_t data[0]; } mp_rf_test_rsp_t; /* TX EVM response payload layout, from golden to dut */ typedef struct { /* rx success count */ uint16_t rx_cnt; /* 10 times the average RSSI of DUT tx evaluated by golden */ int16_t avg_rssi; /* 10 times the average snr of DUT tx evaluated by golden */ int16_t avg_snr; } mp_rf_rsp_tx_evm_t; /* TX CALI result structure */ typedef struct { /* rf phy i value of MAG/PHASE register */ int8_t i; /* rf phy q value of MAG/PHASE register */ int8_t q; /* snr */ float snr; } tx_cali_comen_result_t; /* TX CALI response payload layout, from golden to dut */ typedef struct { /* bitmap representing iq combination */ uint8_t bm[MP_RF_TX_CALI_SNR_BM_SIZE]; /* indicates how many sets of iq data are available next */ uint8_t cnt; /* TX CALI result payload */ tx_cali_comen_result_t result[0]; } mp_rf_rsp_tx_cali_t; /* csr response payload layout, from golden to dut */ typedef struct { /* packet serial number */ uint16_t sn; } mp_rf_rsp_csr_t; /* define MP rf calibration message id */ #define MP_RF_CAL_MSG_ID_MEAS_CFG 0 #define MP_RF_CAL_MSG_ID_MEAS_REQ 1 #define MP_RF_CAL_MSG_ID_GET_SNR 2 /* rf calibration response message header layout */ typedef struct { /* magic number, fixed as MP_RF_TEST_MSG_MAGIC_NUMBER */ uint32_t magic; /* message id, see MP_RF_CAL_MSG_ID_XXX */ uint8_t msg_id; /* dut address */ uint8_t dut_addr[IOT_MAC_ADDR_LEN]; /* Measurement sequence number */ uint32_t sn; /* 1. When the direction DUT-->golden, it is an invalid field. * 2. When the direction gold -->DUT, it is an error code, see ERR_XX */ uint8_t option; /* payload label */ uint8_t data[0]; } mp_rf_cal_msg_hdr_t; /* rf calibration config message layout, DUT --> golden */ typedef struct { /* configure golden to measurement mode, 1 - enable / 0 - disable */ uint8_t meas_en; /* rf option */ uint8_t option; /* rf channel */ uint8_t ch; /* communication power between DUT and golden (HPLC), uint is dBuV */ uint8_t comm_pwr; /* communication power between DUT and golden (HPLC), see MAC_TMI_XX */ uint8_t comm_tmi; /* reserved for further use */ uint8_t rsvd[8]; } mp_rf_cal_meas_cfg_t; /* rf calibration measurement req msg layout, including measurement, * DUT --> golden. */ typedef struct { /* receiving LO frequency used in measurement, uint is Hz */ uint32_t lo_freq; /* index of dc signal in fft result */ uint16_t dc_idx; /* index of img signal in fft result */ uint16_t img_idx; /* index of tone signal in fft result */ uint16_t tone_idx; /* measurements average number */ uint8_t avg_cnt; /* reserved for further use */ uint8_t rsvd[7]; } mp_rf_cal_meas_req_t; /* rf calibration measurement response msg layout, including measurement result * info, golden --> DUT. */ typedef struct { /* dut address */ uint8_t dut_addr[IOT_MAC_ADDR_LEN]; /* Measurement sequence number */ uint32_t sn; /* tone signal power, no gain compensation */ uint32_t tone_pwr; /* dc signal power, no gain compensation */ uint32_t dc_pwr; /* img signal power, no gain compensation */ uint32_t img_pwr; /* receive gain */ uint8_t gain; /* receive gain after 100x amplification */ uint16_t gain_x100; /* eserved for further use */ uint8_t rsvd[6]; } mp_rf_cal_meas_rsp_t; /* rf tx cali info. */ typedef struct { /* rf tx calibration register type, see RF_TEST_TX_CALI_REG_XXX */ uint8_t reg_type; /* rf phy i value of MAG/PHASE register */ int8_t i; /* rf phy q value of MAG/PHASE register */ int8_t q; /* dvice id magic number */ uint16_t dev_id_magic; /* raw snr */ uint16_t raw_snr; } mp_rf_tx_cali_samp_desc_t; #pragma pack(pop) /* restore the pack status */ /* NTB timestamp span calculation */ #define mp_rf_ntb_span_calc(ntb1, ntb2) ((uint32_t)((int32_t)(ntb1) - \ (int32_t)(ntb2))) /* rf tx cali real snr data */ typedef struct { /* i/q combination number */ uint16_t magic; /* how many groups of snr data have been stored */ uint8_t cnt; /* record real snr data */ uint16_t snr[MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_DEPTH]; } snr_record_desc_t; /* mp rf tx descriptor */ typedef struct { rf_tx_mpdu_start mpdu_start; rf_tx_mpdu_end mpdu_end; rf_tx_pb_start pb_start; rf_tx_dummy_node tx_dummy; } mp_rf_tx_desc_t; /* mp rf test context structure */ typedef struct { /* mp rf tx descriptor */ mp_rf_tx_desc_t tx_desc_buf[MP_RF_TX_DESC_CNT]; /* pointer to tx desc currently being sent */ mp_rf_tx_desc_t *cur_tx_desc; /* plc irq0 handle */ iot_irq_t plc_isr_0_h; /* plc irq1 handle */ iot_irq_t plc_isr_1_h; /* plc irq2 handle */ iot_irq_t plc_isr_2_h; /* rf irq handle */ iot_irq_t rf_isr_h; /* common timer */ timer_id_t common_timer; /* timer timeout times */ uint8_t timeout_count; /* option, see RF_OPTION_XXX */ uint8_t option; /* channel numbel */ uint8_t channel; /* target option, see RF_OPTION_XXX */ uint8_t target_option; /* target channel numbel */ uint8_t target_channel; /* phy header mcs, see MCS_ID_XXX */ uint8_t phr_mcs; /* payload mcs, see MCS_ID_XXX */ uint8_t pld_mcs; /* payload block size, see BLOCK_SIZE_XXX */ uint8_t pld_blkz; /* next allocable tx descriptor index */ uint8_t tx_desc_idx; /* flag to mark if rf phy has been initialized */ volatile uint32_t rf_phy_inited : 1, /* flag to mark if rf phy changing */ rf_phy_changing : 1, /* flag to mark if golden is in calibration mode */ is_cal_mode : 1, /* flag to mark if current device is golden */ is_golden : 1, /* flag to mark if led status of goolden */ led_status : 1, /* flag to mark if tx done */ tx_done : 1, /* flag to mark if rx done */ rx_done : 1, /* reserved for further use */ rsvd : 25; /* timestamp of rf phy change */ uint32_t rf_phy_chg_ts; /* rf receive ring buf config structure */ rx_buf_ring_t rx_ring; /* the dut address of the last tx evm test */ uint8_t dut_addr_in_tx_evm[IOT_MAC_ADDR_LEN]; /* generation timestamp of the last TX EVM command from DUT */ uint32_t tx_evm_ts; /* the dut address of the last CSR test */ uint8_t dut_addr_in_csr[IOT_MAC_ADDR_LEN]; /* generation timestamp of the last CSR command from DUT */ uint32_t csr_cmd_ts; /* marks the amount of data received in the TX EVM test */ uint16_t recv_data_cnt; /* record the SNR of the signal received in the TX EVM or CSR test */ int8_t snr_buf[max(MP_RF_CSR_TX_MAX_COUNT, \ MP_RF_TX_EVM_SMAP_MAX_CNT)]; /* record the RSSI of the signal received in the TX EVM or CSR test */ int8_t rssi_buf[max(MP_RF_CSR_TX_MAX_COUNT, \ MP_RF_TX_EVM_SMAP_MAX_CNT)]; uint8_t dut_addr_in_cal[IOT_MAC_ADDR_LEN]; /* measured buffer for tone power */ uint32_t tone_pwr_buf[MP_RF_CAL_MEAS_AVG_CNT_MAX]; /* measured buffer for dc power */ uint32_t dc_pwr_buf[MP_RF_CAL_MEAS_AVG_CNT_MAX]; /* measured buffer for inmage power */ uint32_t img_pwr_buf[MP_RF_CAL_MEAS_AVG_CNT_MAX]; /* measured buffer for rx gain */ uint8_t gain_buf[MP_RF_CAL_MEAS_AVG_CNT_MAX]; /* power information of the last golden measurement */ uint32_t last_meas_sn; uint32_t last_tone_pwr; uint32_t last_dc_pwr; uint32_t last_img_pwr; float last_gain; /* led gpio */ int led_gpio; /* tx pb buffer */ uint8_t rf_pb_buf[520]; /* rf tx packet count */ uint32_t tx_done_cnt; /* rf rx packet count */ uint32_t rx_done_cnt; /* store data generated after curve fitting */ float snr_fit_buf[MP_RF_TEST_CASE_TX_CALI_SNR_SAMP_BUF_SIZE]; /* array y for curve fitting */ float fit_y[RF_PHY_IQ_PHASE_COMPEN_CODE_MAX]; /* array x for curve fitting */ float fit_x[RF_PHY_IQ_PHASE_COMPEN_CODE_MAX]; /* the bit mapping of the i/q combination indicates whether the * corresponding i/q combination has received enough data packets * in the tx snr calibration test. */ uint8_t snr_samp_bitmap[MP_RF_TX_CALI_SNR_BM_SIZE]; /* temporarily save the maximum value */ tx_cali_comen_result_t max_snr_buf[MP_RF_TX_CALI_SNR_BEST_RESULT_MAX]; /* record up to 81 i/q combinations of snr data */ snr_record_desc_t real_snr[MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_SIZE]; /* magic number of current tx cali device */ uint16_t cur_tx_cali_dev; /* rf test tx calibration register type */ uint8_t cur_tx_cali_reg_type; } mp_rf_ctxt_t; /* global variable for mp rf ctxt */ static mp_rf_ctxt_t* g_mp_rf_ctxt = NULL; /* variable and function declarations */ extern os_task_h _init_handle; #if MP_RF_CAL_MEAS_DUMP_EN static void mp_rf_cal_meas_dump(const char *label, void *buf, uint32_t len, uint32_t elm_size) { uint32_t i, *p_uint32 = buf; uint16_t *p_uint16 = buf; uint8_t *p_uint8 = buf; uint32_t temp; uint8_t start = 0; for (i = 0; i < len; i++) { if (0 == (i % 64)) { iot_printf("%s", label); start = 1; } if (sizeof(uint32_t) == elm_size) { temp = *p_uint32++; } else if (sizeof(uint16_t) == elm_size) { temp = (uint32_t)*p_uint16++; } else { temp = (uint32_t)*p_uint8++; } iot_printf("%lu,", temp); if (0 == ((i + 1) % 64)) { start = 0; iot_printf("\n"); } } if (start) { iot_printf("\n"); } return; } #else /* MP_RF_CAL_MEAS_DUMP_EN */ #define mp_rf_cal_meas_dump(label, buf, len, elm_size) #endif /* MP_RF_CAL_MEAS_DUMP_EN */ static uint32_t IRAM_ATTR mp_rf_isr(uint32_t vector, iot_addrword_t data) { (void)vector; (void)data; uint32_t hwq_id; uint32_t irq_sts, txq_map = 0, ring_map = 0; uint32_t sw_sts = RF_MAC_READ_REG(CFG_RF_MAC_COMMON_INT_REG_26_ADDR); RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_24_ADDR, sw_sts); if (sw_sts & (1 << RF_MAC_SW_ISR_TX_MPDU_COMPLETE)) { irq_sts = RF_MAC_READ_REG(CFG_RF_MAC_COMMON_INT_REG_16_ADDR); txq_map = irq_sts & RF_MAC_INT_HWQ_BIT_MASK; RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_14_ADDR, txq_map); for (hwq_id = 0; txq_map && hwq_id < 7; hwq_id++) { if ((0x1 << hwq_id) & txq_map) { if (hwq_id == 0) { g_mp_rf_ctxt->tx_done = 1; g_mp_rf_ctxt->tx_done_cnt++; } } } } if (sw_sts & (1 << RF_MAC_SW_ISR_RX_MPDU_COMPLETE)) { irq_sts = RF_MAC_READ_REG(CFG_RF_MAC_COMMON_INT_REG_16_ADDR); ring_map = irq_sts & RF_MAC_INT_RX_RING_BIT_MASK; RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_14_ADDR, ring_map); g_mp_rf_ctxt->rx_done_cnt++; if (g_mp_rf_ctxt->is_golden) { os_set_task_event_with_v_from_isr(_init_handle, 1 << MP_RF_EVT_ID_RF_RX); } else { g_mp_rf_ctxt->rx_done = 1; } } return 0; } static void mp_rf_isr_start() { g_mp_rf_ctxt->rf_isr_h = iot_interrupt_create(HAL_VECTOR_RFMAC_INT0, HAL_INTR_PRI_7, (iot_addrword_t)NULL, mp_rf_isr); iot_interrupt_attach(g_mp_rf_ctxt->rf_isr_h); iot_interrupt_unmask(g_mp_rf_ctxt->rf_isr_h); RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_10_ADDR, 0xffffffff); RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_14_ADDR, 0xffffffff); RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_18_ADDR, 0xffffffff); RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_20_ADDR, 0xffffffff); RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_24_ADDR, 0xffffffff); RF_MAC_WRITE_REG(CFG_RF_MAC_COMMON_INT_REG_28_ADDR, 0xffffffff); } static void mp_rf_txq_init(void) { uint32_t tmp; tmp = RF_MAC_READ_REG(CFG_RF_MAC_DEBUG_CFG_ADDR); REG_FIELD_SET(RF_MAC_DEBUG_EN, tmp, 1); REG_FIELD_SET(RF_MAC_DEBUG_START, tmp, 1); REG_FIELD_SET(RF_MAC_DEBUG_TXQ_BITMAP, tmp, 1); RF_MAC_WRITE_REG(CFG_RF_MAC_DEBUG_CFG_ADDR, tmp); } static void mp_rf_recv_ring_clear() { iot_pkt_t *iot_pkt_array[1] = { 0 }; /* clear invalid data */ while(rf_pop_buf_from_ring(&g_mp_rf_ctxt->rx_ring, 1, iot_pkt_array)) { iot_pkt_free(iot_pkt_array[0]); } g_mp_rf_ctxt->rx_done = 0; g_mp_rf_ctxt->rx_done_cnt = 0; } static uint8_t mp_rf_check_rf_rx_done() { uint8_t temp; /* disable irq */ if (!g_mp_rf_ctxt->rx_done) { return 0; } os_disable_irq(); temp = g_mp_rf_ctxt->rx_done; g_mp_rf_ctxt->rx_done = 0; os_enable_irq(); return temp; } static uint8_t mp_rf_recv_ring_init() { uint8_t ret = 0; if (!g_mp_rf_ctxt->rx_ring.cfg_enabled) { ring_config config_sof[] = { { CONFIG_RX_ATTENTION, RF_RX_ATTENTION_OFFSET, 0}, { CONFIG_RX_MPDU_START, 0, 0 }, { CONFIG_RX_MPDU_END, 0, 0 }, { CONFIG_RX_PB_START, 0, 0 }, { CONFIG_RX_PB_END, 0, 0 }, { CONFIG_FC, 0, 0 }, { CONFIG_PAYLOAD, RF_RX_PB_PAYLOAD_OFFSET, 0}, }; ret = rf_rx_buf_ring_init(&g_mp_rf_ctxt->rx_ring, RF_RING_0, PLC_SHORT_RX_BUF_COUNT, PLC_SHORT_BUF_SIZE, NULL, config_sof, 0, 0); if (ERR_OK == ret) { mac_rf_rx_ring_enable(&g_mp_rf_ctxt->rx_ring, true); iot_printf("enable rf ring id %d\n", RF_RING_0); return ERR_OK; } } else { iot_printf("rf ring id %d re enable\n", RF_RING_0); rf_rx_ring_fill_hw_cfg(&g_mp_rf_ctxt->rx_ring); mac_rf_rx_ring_enable(&g_mp_rf_ctxt->rx_ring, true); } return ret; } void mp_rf_clear_rf_common() { uint32_t tmp; if (!g_mp_rf_ctxt) return; mac_rf_txq_force_disable(0); mac_rf_rx_ring_enable(&g_mp_rf_ctxt->rx_ring, 0); tmp = RF_MAC_READ_REG(CFG_RF_MAC_DEBUG_CFG_ADDR); REG_FIELD_SET(RF_MAC_DEBUG_EN, tmp, 0); REG_FIELD_SET(RF_MAC_DEBUG_START, tmp, 0); REG_FIELD_SET(RF_MAC_DEBUG_TXQ_BITMAP, tmp, 0); RF_MAC_WRITE_REG(CFG_RF_MAC_DEBUG_CFG_ADDR, tmp); /* if receiving a packet, wait for the last packet to be received */ os_delay(100); mp_rf_recv_ring_clear(); g_mp_rf_ctxt->rf_phy_inited = 0; } static void mp_rf_common_init(uint8_t option, uint8_t channel) { if (!PLC_RF_OPTION_IS_VALID(option)) { iot_printf("%s fail, invalid option %lu\n", __FUNCTION__, option); goto out; } /* check channel */ if (channel >= phy_rf_get_channel_id_max(option) || channel < RF_CHANNEL_ID_1) { iot_printf("%s fail, invalid channel %lu\n", __FUNCTION__, channel); goto out; } if (g_mp_rf_ctxt->rf_phy_inited) { if (option == g_mp_rf_ctxt->option && channel == g_mp_rf_ctxt->channel) { mac_rf_rx_ring_enable(&g_mp_rf_ctxt->rx_ring, 1); goto out; } else { mp_rf_clear_rf_common(); } } uint32_t proto = phy_proto_type_get(); /* plc cpu and bbcpu sync init, rf rxdc disable */ phy_rf_init(proto, option, channel, 1, 0, 0); mp_rf_recv_ring_init(); mp_rf_isr_start(); mp_rf_txq_init(); g_mp_rf_ctxt->option = option; g_mp_rf_ctxt->channel = channel; g_mp_rf_ctxt->phr_mcs = MCS_ID_0; g_mp_rf_ctxt->pld_mcs = MCS_ID_2; g_mp_rf_ctxt->pld_blkz = BLOCK_SIZE_3; g_mp_rf_ctxt->cur_tx_desc = NULL; g_mp_rf_ctxt->tx_desc_idx = 0; g_mp_rf_ctxt->rf_phy_inited = 1; iot_printf("%s ok, option %lu, channel %lu\n", __FUNCTION__, option, channel); out: return; } static mp_rf_tx_desc_t *mp_rf_alloc_tx_desc() { mp_rf_tx_desc_t *tx_desc = NULL; tx_desc = &g_mp_rf_ctxt->tx_desc_buf[g_mp_rf_ctxt->tx_desc_idx]; g_mp_rf_ctxt->tx_desc_idx++; if (g_mp_rf_ctxt->tx_desc_idx >= MP_RF_TX_DESC_CNT) { g_mp_rf_ctxt->tx_desc_idx = 0; } mac_rf_tx_mpdu_fill_dummy(&tx_desc->tx_dummy); os_mem_set(&tx_desc->mpdu_end, 0x0, sizeof(tx_desc->mpdu_end)); mac_rf_tx_mpdu_fill_pb_start(&tx_desc->pb_start, g_mp_rf_ctxt->rf_pb_buf, 0, 1, 1, PHY_PROTO_TYPE_GET()); return tx_desc; } static void mp_rf_tx_mpdu_with_tx_cali_samp(RF_TEST_TX_CALI_REG_T type, uint16_t i_reg, uint16_t q_reg, uint16_t dev_id_magic) { iot_ftm_mp_rf_tx_cal_update_t cal_update = { 0 }; uint32_t tmp; mp_rf_tx_desc_t *tx_desc; tx_desc = mp_rf_alloc_tx_desc(); /* reinit tx dummy node */ mac_rf_tx_mpdu_fill_macinfo( &tx_desc->mpdu_start, (rf_tx_mpdu_start*)&tx_desc->tx_dummy, NULL, &tx_desc->mpdu_end, PHY_PROTO_TYPE_GET(), /* protocol type */ 0, /* need ack */ 0, /* retry cnt */ 0, /* tx power */ 0, /* retry bit en */ 0, /* is msdu */ 0, /* pb buf reuse */ 0, /* tx desc reuse */ 0, /* sw buf offset */ 0, /* is list start */ 0, /* is list end */ g_mp_rf_ctxt->phr_mcs, /* payload hdr mcs */ 0, /* pts */ 0, /* pts off */ 0, /* payload mcs */ 0, /* payload block size */ 0, /* crc32 en */ 0, /* crc32 ofs */ 0, /* hwq id */ g_mp_rf_ctxt->option, /* option */ 0, /* pb num */ 0); /* tx frame len */ /* fill phyinfo */ mac_rf_tx_mpdu_fill_phyinfo(&tx_desc->mpdu_start, 0); /* fill tx cal update info */ if (type == RF_TEST_TX_CALI_REG_IQ_MAG) { cal_update.tx_iq_mag_update = 1; cal_update.tx_i_mag = i_reg; cal_update.tx_q_mag = q_reg; } else if (type == RF_TEST_TX_CALI_REG_IQ_PHASE) { cal_update.tx_iq_phase_update = 1; cal_update.tx_i_phase = i_reg; cal_update.tx_q_phase = q_reg; } else if (type == RF_TEST_TX_CALI_REG_IQ_DC) { cal_update.tx_iq_dc_update = 1; cal_update.tx_i_dc = i_reg; cal_update.tx_q_dc = q_reg; } else { IOT_ASSERT(0); } mp_rf_dut_cal_reg_update(&cal_update); mac_rf_fill_rftest_txcali_phrinfo(&tx_desc->mpdu_start, PHY_PROTO_TYPE_GET(), glb_cfg.nid, type, dev_id_magic, i_reg | q_reg << 16); if (g_mp_rf_ctxt->cur_tx_desc == NULL) { RF_MAC_WRITE_REG(CFG_RF_MAC_TXQ0_PTR_ADDR, (uint32_t)&tx_desc->mpdu_start); tmp = RF_MAC_READ_REG(CFG_RF_MAC_TXQ_ENABLE_LOAD_REG_ADDR); REG_FIELD_SET(RF_MAC_TXQ_LOAD, tmp, 1); REG_FIELD_SET(RF_MAC_TXQ_ENABLE, tmp, 1); RF_MAC_WRITE_REG(CFG_RF_MAC_TXQ_ENABLE_LOAD_REG_ADDR, tmp); } else { g_mp_rf_ctxt->cur_tx_desc->tx_dummy.next = &tx_desc->mpdu_start; } g_mp_rf_ctxt->cur_tx_desc = tx_desc; iot_printf("--tx cali phr,mcs:%lu,reg_type:%lu,tx_cali_reg:[%d %d]" ",tx_done_cnt:%lu\n", g_mp_rf_ctxt->phr_mcs, type, (int16_t)i_reg, (int16_t)q_reg, g_mp_rf_ctxt->tx_done_cnt); while (g_mp_rf_ctxt->tx_done == 0); g_mp_rf_ctxt->tx_done = 0; } static void mp_rf_tx_mpdu(void) { uint32_t tmp; mp_rf_tx_desc_t *tx_desc; tx_desc = mp_rf_alloc_tx_desc(); /* reinit tx dummy node */ mac_rf_tx_mpdu_fill_macinfo( &tx_desc->mpdu_start, (rf_tx_mpdu_start*)&tx_desc->tx_dummy, &tx_desc->pb_start, &tx_desc->mpdu_end, PHY_PROTO_TYPE_GET(), /* protocol type */ 0, /* need ack */ 0, /* retry cnt */ 0, /* tx power */ 0, /* retry bit en */ 0, /* is msdu */ 0, /* pb buf reuse */ 0, /* tx desc reuse */ 0, /* sw buf offset */ 1, /* is list start */ 1, /* is list end */ g_mp_rf_ctxt->phr_mcs, /* payload hdr mcs */ 0, /* pts */ 0, /* pts off */ g_mp_rf_ctxt->pld_mcs, /* payload mcs */ g_mp_rf_ctxt->pld_blkz, /* payload block size */ 1, /* crc32 en */ 0, /* crc32 ofs */ 0, /* hwq id */ g_mp_rf_ctxt->option, /* option */ 1, /* pb num */ 0); /* tx frame len */ /* fill phyinfo */ mac_rf_tx_mpdu_fill_phyinfo(&tx_desc->mpdu_start, 0); /* fill fc */ mac_rf_tx_mpdu_fill_phrinfo(&tx_desc->mpdu_start, PHY_PROTO_TYPE_GET(), /* protocol type */ FC_DELIM_SOF, /* delimiter type */ 0, /* network */ glb_cfg.nid, /* nid */ 0, /* bcn_period_cnt */ 0, /* src tei */ PLC_TEI_BCAST, /* dst tei */ g_mp_rf_ctxt->pld_mcs, /* payload mcs */ 0, /* link id */ g_mp_rf_ctxt->pld_blkz, /* payload pb size */ 0, /* is retry */ 0, /* is enrcy */ 1); /* is bcast */ if (g_mp_rf_ctxt->cur_tx_desc == NULL) { RF_MAC_WRITE_REG(CFG_RF_MAC_TXQ0_PTR_ADDR, (uint32_t)&tx_desc->mpdu_start); tmp = RF_MAC_READ_REG(CFG_RF_MAC_TXQ_ENABLE_LOAD_REG_ADDR); REG_FIELD_SET(RF_MAC_TXQ_LOAD, tmp, 1); REG_FIELD_SET(RF_MAC_TXQ_ENABLE, tmp, 1); RF_MAC_WRITE_REG(CFG_RF_MAC_TXQ_ENABLE_LOAD_REG_ADDR, tmp); } else { g_mp_rf_ctxt->cur_tx_desc->tx_dummy.next = &tx_desc->mpdu_start; } g_mp_rf_ctxt->cur_tx_desc = tx_desc; iot_printf("--tx sof,mcs:%lu-%lu,pbsz:%lu,ts:%lu,tx_done_cnt:%lu\n", g_mp_rf_ctxt->phr_mcs, g_mp_rf_ctxt->pld_mcs, g_mp_rf_ctxt->pld_blkz, RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), g_mp_rf_ctxt->tx_done_cnt); while (g_mp_rf_ctxt->tx_done == 0); g_mp_rf_ctxt->tx_done = 0; } static void mp_rf_tx_packet(uint32_t interval) { mp_rf_tx_mpdu(); if (interval) { iot_delay_us(interval); } } static uint8_t mp_rf_check_rx_packet(iot_pkt_t *pkt_buf) { IOT_ASSERT(pkt_buf); rf_rx_buf_hdr_t *rx_buf; rf_rx_attention *att; rf_rx_pb_end *pb_ed; rx_buf = (rf_rx_buf_hdr_t *)iot_pkt_data(pkt_buf); att = &(rx_buf->att); pb_ed = &(rx_buf->pb_ed); if (!mac_rf_rx_pb_end_get_rx_pb_done(pb_ed)) { iot_printf("%s not done PB\n", __FUNCTION__); return 1; } if (!mac_rf_rx_att_get_rx_mpdu_done(att)) { iot_printf("%s not done RX MPDU\n", __FUNCTION__); return 1; } if (mac_rf_rx_att_get_rx_status(att)) { iot_printf("%s RX STATUS err=%d\n", __FUNCTION__, mac_rf_rx_att_get_rx_status(att)); return 1; } return 0; } static uint8_t mp_rf_test_tx_cali_info_parse(rf_rx_mpdu_start *rx_mpdu, uint32_t proto, mp_rf_tx_cali_samp_desc_t *cali_info) { int8_t i = 0, q = 0; uint8_t reg_type = 0, test_type, ret = ERR_OK; uint16_t dev_id_magic = 0; switch (proto) { #if SUPPORT_SMART_GRID case PLC_PROTO_TYPE_SG: { frame_control_t *sg_fc; sg_fc = (frame_control_t *)mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu); test_type = sg_fc->vf.rf_test_tx_cali.test_type; if (test_type != RF_TEST_TYPE_TX_CALI) { ret = ERR_FAIL; goto out; } dev_id_magic = sg_fc->vf.rf_test_tx_cali.dev_id_magic; reg_type = sg_fc->vf.rf_test_tx_cali.reg_type; i = (int8_t)(sg_fc->vf.rf_test_tx_cali.reg_magic & 0xFF); q = (int8_t)((sg_fc->vf.rf_test_tx_cali.reg_magic >> 16) & 0xFF); break; } #endif #if SUPPORT_SOUTHERN_POWER_GRID case PLC_PROTO_TYPE_SPG: { spg_frame_control_t *spg_fc; spg_fc = (spg_frame_control_t *)mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu); test_type = spg_fc->vf.rf_test_tx_cali.test_type; if (test_type != RF_TEST_TYPE_TX_CALI) { ret = ERR_FAIL; goto out; } dev_id_magic = spg_fc->vf.rf_test_tx_cali.dev_id_magic; reg_type = spg_fc->vf.rf_test_tx_cali.reg_type; i = (int8_t)(spg_fc->vf.rf_test_tx_cali.reg_magic & 0xFF); q = (int8_t)((spg_fc->vf.rf_test_tx_cali.reg_magic >> 16) & 0xFF); break; } #endif default: { IOT_ASSERT(0); break; } } switch (reg_type) { case RF_TEST_TX_CALI_REG_IQ_MAG: { if (!rf_phy_iq_mag_compen_code_valid(i) || !rf_phy_iq_mag_compen_code_valid(q)) { ret = ERR_FAIL; goto out; } break; } case RF_TEST_TX_CALI_REG_IQ_PHASE: { if (!rf_phy_iq_phase_compen_code_valid(i) || !rf_phy_iq_phase_compen_code_valid(q)) { ret = ERR_FAIL; goto out; } break; } default: ret = ERR_FAIL; goto out; } cali_info->reg_type = reg_type; cali_info->i = i; cali_info->q = q; cali_info->dev_id_magic = dev_id_magic; cali_info->raw_snr = mac_rf_rx_mpdu_st_get_raw_snr(rx_mpdu); out: return ret; } static void mp_rf_rx_show_message_info(iot_pkt_t *pkt_buf) { IOT_ASSERT(pkt_buf); int8_t rssi, snr, i; uint8_t rx_gain; uint8_t *data; int16_t dlt; int32_t ppm; /* mac proto */ uint32_t proto = PHY_PROTO_TYPE_GET(); rf_rx_buf_hdr_t *rx_buf = (rf_rx_buf_hdr_t *)iot_pkt_data(pkt_buf); rf_rx_attention *rx_att = &(rx_buf->att); rf_rx_mpdu_start *rx_mpdu = &(rx_buf->mpdu_st); rf_rx_pb_start *pb_st = &(rx_buf->pb_st); rf_rx_pb_end *pb_end = &(rx_buf->pb_ed); /* get rx fc message */ rx_fc_msg_t rx_fc_msg = {0}; mac_rf_get_rx_frm_msg_from_fc(proto, mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu), &rx_fc_msg); rssi = mac_rf_rx_mpdu_st_get_rssi(rx_mpdu); snr = mac_rf_rx_mpdu_st_get_avg_snr(rx_mpdu); rx_gain = mac_rf_rx_mpdu_st_get_rx_gain(rx_mpdu); dlt = mac_rf_rx_pb_end_get_mismatch_dlt(pb_end); ppm = mac_rf_rx_mpdu_st_get_rx_ppmhz(rx_mpdu); switch(rx_fc_msg.delimiter) { case FC_DELIM_BEACON: { iot_printf("rx_bcn nid:0x%x, stei:%d, dtei:%d, phr_mcs:%d, " "pld_mcs:%d, gain:%d, rssi:%d, snr:%d, dlt:%d, ppm:%d, " "pb_crc_err:%lu\n", rx_fc_msg.nid, rx_fc_msg.src_tei, rx_fc_msg.dst_tei, rx_att->phr_mcs, rx_fc_msg.rf_mcs, rx_gain, rssi, snr, dlt, ppm, pb_end->rx_beacon_pld_crc_err); break; } case FC_DELIM_SOF: { iot_printf("rx_sof nid:0x%x, stei:%d, dtei:%d, phr_mcs:%d" ", pld_mcs:%d, ssn:%d, gain:%d, rssi:%d, " "snr:%d, dlt:%d, ppm:%d, pb_crc_err:%lu\n", rx_fc_msg.nid, rx_fc_msg.src_tei, rx_fc_msg.dst_tei, rx_att->phr_mcs, rx_fc_msg.rf_mcs, pb_st->ssn, rx_gain, rssi, snr, dlt, ppm, pb_end->rx_pb_crc_err); break; } case FC_DELIM_RF_TEST: { iot_printf("rx_rf_test nid:0x%x, phr_mcs:%d, gain:%d, rssi:%d," " snr:%d, ppm:%d, phr_info:", rx_fc_msg.nid, rx_att->phr_mcs, rx_gain, rssi, snr, ppm); data = (uint8_t *)mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu); for (i = 0; i < 16; i++) iot_printf("%x ", data[i]); iot_printf("\n"); break; } default: break; } } static void mp_rf_recover_def_rate() { if (g_mp_rf_ctxt->option == RF_OPTION_3) { g_mp_rf_ctxt->phr_mcs = MCS_ID_2; g_mp_rf_ctxt->pld_mcs = MCS_ID_2; g_mp_rf_ctxt->pld_blkz = BLOCK_SIZE_1; } else { g_mp_rf_ctxt->phr_mcs = MCS_ID_0; g_mp_rf_ctxt->pld_mcs = MCS_ID_1; g_mp_rf_ctxt->pld_blkz = BLOCK_SIZE_1; } } static int16_t mp_rf_calc_avg_value(int8_t *data, uint16_t cnt) { uint16_t i; int32_t sum = 0, avg; if (!cnt) { avg = 0; goto ret; } if (cnt <= 6) { for (i = 0; i < cnt; i++) { sum += data[i]; } avg = 10 * sum / cnt; goto ret; } iot_bubble_sort_int8(data, cnt, 1); for (i = 2; i < cnt - 2; i++) { sum += data[i]; } avg = 10 * sum / (cnt - 4); ret: return (int16_t)avg; } static uint32_t mp_rf_calc_avg_u32(uint32_t *data, uint8_t cnt) { uint8_t i; uint64_t sum = 0; for (i = 0; i < cnt; i++) { sum += (uint64_t)data[i]; } return (uint32_t)((float)sum / cnt + 0.5); } static float mp_rf_calc_avg_u8(uint8_t *data, uint8_t cnt) { uint8_t i; uint32_t sum = 0; for (i = 0; i < cnt; i++) { sum += (uint32_t)data[i]; } return (float)sum / cnt; } static void mp_rf_add_tx_evm_samp(mp_rf_test_cmd_tx_evm_t *dut, int8_t snr, int8_t rssi) { if (g_mp_rf_ctxt->tx_evm_ts != dut->ts || !iot_mac_addr_cmp(g_mp_rf_ctxt->dut_addr_in_tx_evm, dut->mac_addr)) { g_mp_rf_ctxt->tx_evm_ts = dut->ts; iot_mac_addr_cpy(g_mp_rf_ctxt->dut_addr_in_tx_evm, dut->mac_addr); g_mp_rf_ctxt->recv_data_cnt = 0; } g_mp_rf_ctxt->snr_buf[g_mp_rf_ctxt->recv_data_cnt] = snr; g_mp_rf_ctxt->rssi_buf[g_mp_rf_ctxt->recv_data_cnt] = rssi; g_mp_rf_ctxt->recv_data_cnt++; } static void mp_rf_get_tx_evm_res(mp_rf_test_cmd_tx_evm_t *dut, mp_rf_rsp_tx_evm_t *resp) { if (g_mp_rf_ctxt->tx_evm_ts != dut->ts || !iot_mac_addr_cmp(g_mp_rf_ctxt->dut_addr_in_tx_evm, dut->mac_addr)) { g_mp_rf_ctxt->tx_evm_ts = dut->ts; iot_mac_addr_cpy(g_mp_rf_ctxt->dut_addr_in_tx_evm, dut->mac_addr); g_mp_rf_ctxt->recv_data_cnt = 0; resp->rx_cnt = 0; resp->avg_snr = 0; resp->avg_rssi = 0; return; } resp->rx_cnt = g_mp_rf_ctxt->recv_data_cnt; resp->avg_snr = mp_rf_calc_avg_value(g_mp_rf_ctxt->snr_buf, g_mp_rf_ctxt->recv_data_cnt); resp->avg_rssi = mp_rf_calc_avg_value(g_mp_rf_ctxt->rssi_buf, g_mp_rf_ctxt->recv_data_cnt); } static void mp_rf_add_tx_cali_samp(mp_rf_tx_cali_samp_desc_t *cali_info) { uint16_t i, q, pos, max_code; snr_record_desc_t *record; i = cali_info->i; q = cali_info->q; if (g_mp_rf_ctxt->cur_tx_cali_dev != cali_info->dev_id_magic || g_mp_rf_ctxt->cur_tx_cali_reg_type != cali_info->reg_type) { os_mem_set(g_mp_rf_ctxt->real_snr, 0, sizeof(g_mp_rf_ctxt->real_snr)); iot_printf("%s data buf clear\n", __FUNCTION__); g_mp_rf_ctxt->cur_tx_cali_dev = cali_info->dev_id_magic; g_mp_rf_ctxt->cur_tx_cali_reg_type = cali_info->reg_type; } iot_printf("%s reg_type=%d, i=%d, q=%d, snr=%d\n", __FUNCTION__, cali_info->reg_type, i, q, cali_info->raw_snr); max_code = (cali_info->reg_type == RF_TEST_TX_CALI_REG_IQ_MAG) ? RF_PHY_IQ_MAG_COMPEN_CODE_MAX : RF_PHY_IQ_PHASE_COMPEN_CODE_MAX; pos = MP_RF_IQ_CODE_TO_MAGIC(max_code, i, q); record = g_mp_rf_ctxt->real_snr; for (i = 0; i < MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_SIZE; i++) { if (record[i].magic == pos || record[i].cnt == 0) { record[i].magic = pos; if (record[i].cnt < MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_DEPTH) { record[i].snr[record[i].cnt] = cali_info->raw_snr; record[i].cnt++; } break; } } return; } /* polynomial fitting, y=a0 + a1*x + a2*x*x */ void mp_rf_least_squarel_liner_fit(float *x, float *y, uint8_t n, float *a0, float *a1, float *a2) { float temp = 0; float x0 = n, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x0y1 = 0, x1y1 = 0, x2y1 = 0; float x0x2, x0x3, x0x4, x1x1, x1x2, x1x3, x1x4, x2x2, x2x3, x2x4, x3x3; float a_banshui[3][3], a_ni[3][3]; float a_abs; uint8_t i, j; for (i = 0; i < n; i++) { x0y1 += *(y + i); temp = *(x + i); x1 += temp; x1y1 += temp*(*(y + i)); temp *= *(x + i); x2 += temp; x2y1 += temp*(*(y + i)); temp *= *(x + i); x3 += temp; temp *= *(x + i); x4 += temp; } x0x2 = x0 * x2; x0x3 = x0 * x3; x0x4 = x0 * x4; x1x1 = x1 * x1; x1x2 = x1 * x2; x1x3 = x1 * x3; x1x4 = x1 * x4; x2x2 = x2 * x2; x2x3 = x2 * x3; x2x4 = x2 * x4; x3x3 = x3 * x3; a_banshui[0][0] = (x2x4 - x3x3); a_banshui[0][1] = -(x1x4 - x2x3); a_banshui[0][2] = (x1x3 - x2x2); a_banshui[1][0] = -(x1x4 - x2x3); a_banshui[1][1] = (x0x4 - x2x2); a_banshui[1][2] = -(x0x3 - x1x2); a_banshui[2][0] = (x1x3 - x2x2); a_banshui[2][1] = -(x0x3 - x1x2); a_banshui[2][2] = (x0x2 - x1x1); a_abs = (x0 * a_banshui[0][0] + x1 * a_banshui[0][1] + x2 * a_banshui[0][2]); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { a_ni[i][j] = a_banshui[i][j] / a_abs; } } *a0 = a_ni[0][0] * x0y1 + a_ni[0][1] * x1y1 + a_ni[0][2] * x2y1; *a1 = a_ni[1][0] * x0y1 + a_ni[1][1] * x1y1 + a_ni[1][2] * x2y1; *a2 = a_ni[2][0] * x0y1 + a_ni[2][1] * x1y1 + a_ni[2][2] * x2y1; iot_printf("%s a0:%f a1:%f a2:%f\n", __FUNCTION__, *a0, *a1, *a2); } static int32_t mp_rf_calculate_expection(int32_t *data, uint8_t cnt) { uint8_t i; int32_t sum = 0, avg; if (!cnt) { avg = 0; goto ret; } if (cnt <= 10) { for (i = 0; i < cnt; i++) { sum += data[i]; } avg = sum / cnt; goto ret; } iot_bubble_sort_int32(data, cnt, 1); for (i = 3; i < cnt - 3; i++) { sum += data[i]; } avg = sum / (cnt - 6); ret: return (int16_t)avg; } static uint8_t mp_rf_tx_cali_update_best_iq(int8_t max_code) { int8_t i, q; uint16_t pos, count = 0, k, j, max_pos; float max_snr; for(i = 0; i < MP_RF_TX_CALI_SNR_BEST_RESULT_MAX; i++) { g_mp_rf_ctxt->max_snr_buf[i].snr = MP_RF_INVAL_RSSI_SNR; g_mp_rf_ctxt->max_snr_buf[i].i = RF_PHY_IQ_PHASE_COMPEN_CODE_MAX; g_mp_rf_ctxt->max_snr_buf[i].q = RF_PHY_IQ_PHASE_COMPEN_CODE_MAX; } for(i = 0; i < max_code; i++) { pos = i * max_code; max_snr = MP_RF_INVAL_RSSI_SNR; for (q = 0, max_pos = 0; q < max_code; q++) { if (iot_bitmap_is_set(g_mp_rf_ctxt->snr_samp_bitmap, MP_RF_TX_CALI_SNR_BM_SIZE, pos + q + 1) && max_snr < g_mp_rf_ctxt->snr_fit_buf[pos + q]) { max_pos = q; max_snr = g_mp_rf_ctxt->snr_fit_buf[pos + q]; } } if (max_snr == MP_RF_INVAL_RSSI_SNR) { continue; } for (k = 0; k < MP_RF_TX_CALI_SNR_BEST_RESULT_MAX; k++) { if (max_snr > g_mp_rf_ctxt->max_snr_buf[k].snr) { count++; for (j = MP_RF_TX_CALI_SNR_BEST_RESULT_MAX - 1; j > k; j--) { g_mp_rf_ctxt->max_snr_buf[j].snr = g_mp_rf_ctxt->max_snr_buf[j - 1].snr; g_mp_rf_ctxt->max_snr_buf[j].i = g_mp_rf_ctxt->max_snr_buf[j - 1].i; g_mp_rf_ctxt->max_snr_buf[j].q = g_mp_rf_ctxt->max_snr_buf[j - 1].q; } g_mp_rf_ctxt->max_snr_buf[k].snr = max_snr; g_mp_rf_ctxt->max_snr_buf[k].i = i; g_mp_rf_ctxt->max_snr_buf[k].q = max_pos; iot_printf("%s pos=%d, i=%d, q=%d, snr=%f, count=%d\n", __FUNCTION__, k, i, max_pos, max_snr, count); break; } } } count = min(count, MP_RF_TX_CALI_SNR_BEST_RESULT_MAX); return count; } static void mp_rf_get_tx_cali_res(mp_rf_test_cmd_tx_cali_stat_qr_t *rf_cmd, mp_rf_rsp_tx_cali_t *rsp) { int8_t i = 0, q = 0, max_code, loop; uint8_t m, n, cnt; uint8_t *bm; uint16_t pos, bm_size = MP_RF_TX_CALI_SNR_BM_SIZE; float a0, a1, a2, *fit_x, *fit_y, *fit_buf; uint32_t timer_start, time_span; int32_t snr[MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_DEPTH]; iot_printf("%s tx cali type:%d liner_fit_en:%d\n", __FUNCTION__, rf_cmd->type, rf_cmd->liner_fit_en); switch (rf_cmd->type) { case RF_TEST_TX_CALI_REG_IQ_MAG: { max_code = RF_PHY_IQ_MAG_COMPEN_CODE_MAX; break; } case RF_TEST_TX_CALI_REG_IQ_PHASE: { max_code = RF_PHY_IQ_PHASE_COMPEN_CODE_MAX; break; } default: return; } /* at least half of the packets received can be considered valid */ n = rf_cmd->liner_fit_en ? 2 : 10; fit_x = g_mp_rf_ctxt->fit_x; fit_y = g_mp_rf_ctxt->fit_y; fit_buf = g_mp_rf_ctxt->snr_fit_buf; os_mem_set(fit_buf, 0, sizeof(g_mp_rf_ctxt->snr_fit_buf)); bm = g_mp_rf_ctxt->snr_samp_bitmap; os_mem_set(bm, 0, bm_size); timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); for (i = 0; i < MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_SIZE; i++) { if (g_mp_rf_ctxt->real_snr[i].cnt <= n) continue; /* calculate the mathematical expectation of snr */ for (m = 0; m < g_mp_rf_ctxt->real_snr[i].cnt; m++) { snr[m] = g_mp_rf_ctxt->real_snr[i].snr[m]; } pos = g_mp_rf_ctxt->real_snr[i].magic; iot_bitmap_set(bm, bm_size, pos + 1); fit_buf[pos] = mp_rf_calculate_expection(snr, g_mp_rf_ctxt->real_snr[i].cnt); } if (!rf_cmd->liner_fit_en) { goto get_res; } /* smooth curve, at least twice */ for(loop = 0; loop < 2; loop++) { /* keep i unchanged, fit the q curve, and record the fitted data */ for (i = 0; i < max_code; i++) { for (q = 0, cnt = 0; q < max_code; q++) { pos = MP_RF_IQ_CODE_TO_MAGIC(max_code, i, q); if (iot_bitmap_is_set(bm, bm_size, pos + 1)) { fit_y[cnt] = fit_buf[pos]; fit_x[cnt] = q; cnt++; } } if (cnt) { iot_printf("%s i:%d, cnt:%d, fit_x[%d, %d]\n", __FUNCTION__, i, cnt, (uint8_t)fit_x[0], (uint8_t)fit_x[cnt - 1]); } /* curve fitting, required data points cannot be too few */ if (cnt >= MP_RF_TX_CALI_SNR_LINER_FIT_VALID_SAMP_NUM) { mp_rf_least_squarel_liner_fit(fit_x, fit_y, cnt, &a0, &a1, &a2); /* Generate new data according to fitting parameters */ for (q = fit_x[0]; q <= fit_x[cnt - 1]; q++) { pos = MP_RF_IQ_CODE_TO_MAGIC(max_code, i, q); if (iot_bitmap_is_set(bm, bm_size, pos + 1)) { fit_buf[pos] = a0 + a1 * q + a2 * q * q; } } } } /* keep q unchanged, fit the i curve, and record the fitted data */ for (q = 0; q < max_code; q++) { for (i = 0, cnt = 0; i < max_code; i++) { pos = MP_RF_IQ_CODE_TO_MAGIC(max_code, i, q); if (iot_bitmap_is_set(bm, bm_size, pos + 1)) { fit_y[cnt] = fit_buf[pos]; fit_x[cnt] = i; cnt++; } } if (cnt) { iot_printf("%s q:%d, cnt:%d, fit_x[%d, %d]\n", __FUNCTION__, q, cnt, (uint8_t)fit_x[0], (uint8_t)fit_x[cnt - 1]); } if (cnt >= MP_RF_TX_CALI_SNR_LINER_FIT_VALID_SAMP_NUM) { mp_rf_least_squarel_liner_fit(fit_x, fit_y, cnt, &a0, &a1, &a2); for (i = fit_x[0]; i < fit_x[cnt - 1]; i++) { pos = MP_RF_IQ_CODE_TO_MAGIC(max_code, i, q); if (iot_bitmap_is_set(bm, bm_size, pos + 1)) { fit_buf[pos] = a0 + a1 * i + a2 * i * i; } } } } } get_res: cnt = rf_cmd->liner_fit_en ? MP_RF_TX_CALI_SNR_BEST_RESULT_MAX : 1; rsp->cnt = mp_rf_tx_cali_update_best_iq(max_code); rsp->cnt = min(cnt, rsp->cnt); os_mem_cpy(rsp->bm, bm, bm_size); time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), timer_start); time_span = MAC_NTB_TO_MS(time_span); iot_printf("%s time consuming is %d, best_result:", __FUNCTION__, time_span); for (i = 0; i < rsp->cnt; i++) { rsp->result[i].i = g_mp_rf_ctxt->max_snr_buf[i].i; rsp->result[i].q = g_mp_rf_ctxt->max_snr_buf[i].q; rsp->result[i].snr = g_mp_rf_ctxt->max_snr_buf[i].snr / 10.0; iot_printf("[%f, %d, %d], ", rsp->result[i].snr, rsp->result[i].i, rsp->result[i].q); } iot_printf("\n"); } static void mp_rf_golden_rf_rx() { int8_t rssi, snr; uint16_t num, i; iot_pkt_t *iot_pkt_array[1] = { 0 }; mp_rf_test_cmd_hdr_t *test_cmd; mp_rf_test_cmd_chg_phy_t *phy_para; rf_rx_pb_end *pb_end; rf_rx_buf_hdr_t *rx_buf; mp_rf_test_rsp_t* golden_rsp; rf_rx_mpdu_start *rx_mpdu; /* rx fc message */ rx_fc_msg_t rx_fc_msg = {0}; mp_rf_test_cmd_csr_t* csr_cmd; mp_rf_rsp_csr_t* csr_rsp; mp_rf_tx_cali_samp_desc_t cali_info = { 0 }; golden_rsp = (mp_rf_test_rsp_t *)g_mp_rf_ctxt->rf_pb_buf; golden_rsp->magic = MP_RF_TEST_MSG_MAGIC_NUMBER; golden_rsp->tx_ppm = 0; for (; ;) { if (0 == rf_pop_buf_from_ring(&g_mp_rf_ctxt->rx_ring, 1, iot_pkt_array)) { break; } if (mp_rf_check_rx_packet(iot_pkt_array[0])) goto free_packet; mp_rf_rx_show_message_info(iot_pkt_array[0]); rx_buf = (rf_rx_buf_hdr_t *)iot_pkt_data(iot_pkt_array[0]); test_cmd = (mp_rf_test_cmd_hdr_t *)((uint8_t *)rx_buf + PB_PAYLOAD_OFFSET); rx_mpdu = &rx_buf->mpdu_st; mac_rf_get_rx_frm_msg_from_fc(PHY_PROTO_TYPE_GET(), mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu), &rx_fc_msg); pb_end = &rx_buf->pb_ed; snr = mac_rf_rx_mpdu_st_get_avg_snr(rx_mpdu); rssi = mac_rf_rx_mpdu_st_get_rssi(rx_mpdu); if (rx_fc_msg.delimiter == FC_DELIM_RF_TEST && rx_fc_msg.nid == glb_cfg.nid) { if (mp_rf_test_tx_cali_info_parse(rx_mpdu, PHY_PROTO_TYPE_GET(), &cali_info) == ERR_OK) { mp_rf_add_tx_cali_samp(&cali_info); } goto free_packet; } if (rx_fc_msg.delimiter != FC_DELIM_SOF || pb_end->rx_pb_crc_err || test_cmd->magic != MP_RF_TEST_MSG_MAGIC_NUMBER || rx_fc_msg.nid != glb_cfg.nid) { goto free_packet; } if (g_mp_rf_ctxt->rf_phy_changing && test_cmd->msg_id != MP_RF_MSG_ID_CHG_PHY) { goto free_packet; } switch (test_cmd->msg_id) { case MP_RF_MSG_ID_CSR: { csr_cmd = (mp_rf_test_cmd_csr_t*)test_cmd->data; /* do not execute duplicate csr commands */ if (iot_mac_addr_cmp(g_mp_rf_ctxt->dut_addr_in_csr, csr_cmd->mac_addr) && g_mp_rf_ctxt->csr_cmd_ts == csr_cmd->ts) { iot_printf("%s discard the same csr command received\n", __FUNCTION__); break; } iot_mac_addr_cpy(g_mp_rf_ctxt->dut_addr_in_csr, csr_cmd->mac_addr); g_mp_rf_ctxt->csr_cmd_ts = csr_cmd->ts; golden_rsp->msg_id = MP_RF_MSG_ID_CSR; golden_rsp->tx_snr = snr; golden_rsp->tx_rssi = rssi; golden_rsp->tx_gain = 0; g_mp_rf_ctxt->phr_mcs = test_cmd->phr_mcs; g_mp_rf_ctxt->pld_mcs = test_cmd->pld_mcs; g_mp_rf_ctxt->pld_blkz = test_cmd->pld_blkz; if (csr_cmd->is_test_mode) { /* use the cert test mode power configuration */ mac_rf_set_cert_mode(CERT_TEST_CMD_ENTER_PHY_HPLC2RF_LP); if (g_mp_rf_ctxt->phr_mcs == MCS_ID_5 || g_mp_rf_ctxt->phr_mcs == MCS_ID_6 || g_mp_rf_ctxt->pld_mcs == MCS_ID_5 || g_mp_rf_ctxt->pld_mcs == MCS_ID_6) { /* mcs 5/6 need special config */ mac_rf_set_cert_16qam_flag(1); } else { mac_rf_set_cert_16qam_flag(0); } } else { /* cfg tx power */ mac_rf_set_target_tx_power(test_cmd->power); } csr_rsp = (mp_rf_rsp_csr_t*)golden_rsp->data; num = min(MP_RF_CSR_TX_MAX_COUNT, csr_cmd->packet_num); for (i = 0; i < num; i++) { csr_rsp->sn = i; mp_rf_tx_packet(csr_cmd->interval); } if (csr_cmd->is_test_mode) { /* after sending samples, restore the power config. */ mac_rf_set_cert_mode(0); mac_rf_set_cert_16qam_flag(0); mac_rf_set_target_tx_power(test_cmd->power); } break; } case MP_RF_MSG_ID_CSI: { g_mp_rf_ctxt->phr_mcs = test_cmd->phr_mcs; g_mp_rf_ctxt->pld_mcs = test_cmd->pld_mcs; g_mp_rf_ctxt->pld_blkz = test_cmd->pld_blkz; /* cfg tx power */ mac_rf_set_target_tx_power(test_cmd->power); golden_rsp->msg_id = MP_RF_MSG_ID_CSI; golden_rsp->tx_snr = snr; golden_rsp->tx_rssi = rssi; golden_rsp->tx_gain = mac_rf_rx_mpdu_st_get_rx_gain(rx_mpdu); mp_rf_tx_packet(0); break; } case MP_RF_MSG_ID_TX_EVM_SAMP: { mp_rf_add_tx_evm_samp((mp_rf_test_cmd_tx_evm_t *)test_cmd->data, snr, rssi); break; } case MP_RF_MSG_ID_TX_EVM_STAT_QUERY: { golden_rsp->msg_id = MP_RF_MSG_ID_TX_EVM_STAT_QUERY; mp_rf_get_tx_evm_res((mp_rf_test_cmd_tx_evm_t *)test_cmd->data, (mp_rf_rsp_tx_evm_t *)golden_rsp->data); /* cfg tx power */ mac_rf_set_target_tx_power(test_cmd->power); mp_rf_recover_def_rate(); for (i = 0; i < 3; i++) mp_rf_tx_packet(0); break; } case MP_RF_MSG_ID_CHG_PHY: { phy_para = (mp_rf_test_cmd_chg_phy_t *)test_cmd->data; golden_rsp->msg_id = MP_RF_MSG_ID_CHG_PHY; golden_rsp->tx_snr = 0; golden_rsp->tx_rssi = 0; golden_rsp->tx_gain = 0; /* cfg tx power */ mac_rf_set_target_tx_power(test_cmd->power); mp_rf_recover_def_rate(); mp_rf_tx_packet(0); g_mp_rf_ctxt->rf_phy_changing = 1; g_mp_rf_ctxt->rf_phy_chg_ts = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); g_mp_rf_ctxt->target_option = phy_para->option; g_mp_rf_ctxt->target_channel = phy_para->channel; iot_printf("%s -- current phy para[option:%d channel:%d]," " target phy para[option:%d channel:%d]\n", __FUNCTION__, g_mp_rf_ctxt->option, g_mp_rf_ctxt->channel, phy_para->option, phy_para->channel); break; } default: { break; } } free_packet: iot_pkt_free(iot_pkt_array[0]); } return; } void mp_rf_plc_massage_show(uint8_t *rx_buf) { /* mac proto */ uint32_t proto = PHY_PROTO_TYPE_GET(); /* rx fc message */ rx_fc_msg_t rx_fc_msg = {0}; rx_buf_hdr_t *rx_buf_t = (rx_buf_hdr_t *)rx_buf; rx_mpdu_start *rx_mpdu = &(rx_buf_t->mpdu_st); rx_pb_start *pb_st = &(rx_buf_t->pb_st); rx_pb_end *pb_end = &(rx_buf_t->pb_ed); if (mac_rx_att_get_is_fcserr(&rx_buf_t->att) == 1) { return; } mac_get_rx_frm_msg_from_fc(proto, mac_rx_mpdu_st_get_fc_addr(rx_mpdu), &rx_fc_msg); switch(rx_fc_msg.delimiter){ case FC_DELIM_BEACON: { iot_printf("rx bcn nid:0x%x,stei:%d,tmi:%d-%d,fc_phase:%d," "rx_phase:%d,rssi:%d,gain:%d,snr:%d,pb_crc:%lu\n", rx_fc_msg.nid, rx_fc_msg.src_tei, rx_fc_msg.tmi,rx_fc_msg.tmi_ext, rx_fc_msg.phase, mac_rx_mpdu_st_get_rx_phase(rx_mpdu), PHY_RSSI_FROM_RMI_GAIN(mac_rx_mpdu_st_get_adc_power(rx_mpdu), mac_rx_mpdu_st_get_agc_gain_entry(rx_mpdu)), PHY_GET_AGC_POWER(mac_rx_mpdu_st_get_agc_gain_entry(rx_mpdu)), mac_rx_mpdu_st_get_avg_snr(rx_mpdu), pb_end->rx_pb_crc_err); break; } case FC_DELIM_SOF: { iot_printf("rx sof nid:0x%x,stei:%lu,dtei:%lu,tmi:%d-%d," "rx_phase:%d,pb_num:%lu,ssn:%lu,rssi:%d,gain:%d,snr:%d,pb_crc:%lu\n", rx_fc_msg.nid, rx_fc_msg.src_tei, rx_fc_msg.dst_tei, rx_fc_msg.tmi, rx_fc_msg.tmi_ext, mac_rx_mpdu_st_get_rx_phase(rx_mpdu), mac_rx_mpdu_st_get_rx_pb_num(rx_mpdu), mac_rx_pb_st_get_ssn(pb_st), PHY_RSSI_FROM_RMI_GAIN(mac_rx_mpdu_st_get_adc_power(rx_mpdu), mac_rx_mpdu_st_get_agc_gain_entry(rx_mpdu)), PHY_GET_AGC_POWER(mac_rx_mpdu_st_get_agc_gain_entry(rx_mpdu)), mac_rx_mpdu_st_get_avg_snr(rx_mpdu), pb_end->rx_pb_crc_err); break; } case FC_DELIM_SACK: { iot_printf("rx a ack,stei:%d,dtei:%d,nid:0x%x,result:%d,status:%x\n", rx_fc_msg.src_tei, rx_fc_msg.dst_tei, rx_fc_msg.nid, rx_fc_msg.result_in_sack, rx_fc_msg.bitmap_in_sack); break; } default: { iot_printf("rx other frame type: %d\n", rx_fc_msg.delimiter); break; } } } static void mp_rf_comm_test_info_clear() { g_mp_rf_ctxt->csr_cmd_ts = 0; g_mp_rf_ctxt->tx_evm_ts = 0; g_mp_rf_ctxt->rf_phy_changing = 0; g_mp_rf_ctxt->rf_phy_chg_ts = 0; g_mp_rf_ctxt->recv_data_cnt = 0; os_mem_set(g_mp_rf_ctxt->dut_addr_in_tx_evm, 0x0, IOT_MAC_ADDR_LEN); os_mem_set(g_mp_rf_ctxt->dut_addr_in_csr, 0x0, IOT_MAC_ADDR_LEN); os_mem_set(g_mp_rf_ctxt->dut_addr_in_cal, 0x0, IOT_MAC_ADDR_LEN); g_mp_rf_ctxt->last_meas_sn = 0; g_mp_rf_ctxt->option = RF_OPTION_INVALID; g_mp_rf_ctxt->channel = RF_CHANNEL_ID_INVALID; g_mp_rf_ctxt->target_option = MP_RF_GOLDEN_DEF_OPTION; g_mp_rf_ctxt->target_channel = MP_RF_GOLDEN_DEF_CHANNEL; } static void mp_rf_cal_mode_enter(uint8_t option, uint8_t ch, uint8_t comm_pwr, uint8_t comm_tmi) { uint32_t freq; if (!g_mp_rf_ctxt->is_cal_mode) { /* phy tx common init interface */ rf_phy_tx_init(phy_rf_get_band_sel(), option); freq = phy_rf_get_channel_freq_by_id(option, ch); /* phy channel setting */ bb_rf_reset(); bb_rf_set_tx_dc(0, 0); bb_rf_set_tx_iq_mag(0, 0); bb_rf_set_tx_iq_phase(0, 0); bb_rf_rx_cfg(option, freq); /* Note: here is to increase the rx filter bandwidth, which can improve * the accuracy of golden measurement power. */ bb_rf_set_filter(0x10); bb_rf_debug_rx_immd(); g_mp_rf_ctxt->is_cal_mode = 1; mp_rf_comm_test_info_clear(); } phy_pwr_adjust_set(comm_pwr); glb_cfg.tmi = comm_tmi; iot_printf("%s - option:%lu, ch:%lu, pwr:%lu, tmi:%lu\n", __FUNCTION__, option, ch, comm_pwr, comm_tmi); } static uint32_t mp_rf_cal_mode_exit() { if (g_mp_rf_ctxt->is_cal_mode) { iot_printf("%s\n", __FUNCTION__); g_mp_rf_ctxt->is_cal_mode = 0; return ERR_OK; } return ERR_EXIST; } static uint8_t mp_rf_cal_pwr_meas(uint8_t *dut_addr, uint32_t sn, uint32_t lo_freq, uint16_t tone_idx, uint16_t dc_idx, uint16_t img_idx, uint32_t *tone_pwr, uint32_t *dc_pwr, uint32_t *img_pwr, float *gain, uint8_t try_cnt) { uint32_t dump_addr; uint32_t dump_len; uint32_t sample_cnt = 1024 * 8; uint32_t *fft_raw; uint32_t start_ntb, end_ntb; uint8_t i, fix_gain; if (!g_mp_rf_ctxt->is_cal_mode) { /* golden is not in calibration mode, not ready, and returns * error code to DUT. */ iot_printf("%s error golden not ready!!!\n", __FUNCTION__); return ERR_NOT_READY; } start_ntb = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); if (iot_mac_addr_cmp(dut_addr, g_mp_rf_ctxt->dut_addr_in_cal) == 1 && g_mp_rf_ctxt->last_meas_sn == sn) { /* repeated measurement request from DUT, directly returning the * latest test results. */ iot_printf("%s repeat req-dut[%02x:%02x:%02x:%02x:%02x:%02x], sn:%lu\n", __FUNCTION__, dut_addr[0], dut_addr[1], dut_addr[2], dut_addr[3], dut_addr[4], dut_addr[5], sn); goto out; } bb_rf_rx_reset(); bb_rf_set_fchz(lo_freq); fix_gain = rf_phy_rx_gain_lock(-1); bb_rf_debug_rx_immd(); try_cnt = min(try_cnt, MP_RF_CAL_MEAS_AVG_CNT_MAX); if (try_cnt == 0) { try_cnt = MP_RF_CAL_MEAS_AVG_CNT_DEFAULT; } dump_len = phy_ada_dump_addr_get(&dump_addr); IOT_ASSERT((sample_cnt << 2) <= dump_len); for (i = 0; i < try_cnt; i++) { g_mp_rf_ctxt->gain_buf[i] = fix_gain; rf_phy_ada_dump_entry(dump_addr, sample_cnt << 2); fft_raw = rf_phy_ada_dump_fft_cal((uint32_t *)dump_addr, sample_cnt, 512, tone_idx, dc_idx, img_idx); g_mp_rf_ctxt->tone_pwr_buf[i] = fft_raw[tone_idx]; g_mp_rf_ctxt->dc_pwr_buf[i] = fft_raw[dc_idx]; g_mp_rf_ctxt->img_pwr_buf[i] = fft_raw[img_idx]; } mp_rf_cal_meas_dump("golden_meas gain:", g_mp_rf_ctxt->gain_buf, (uint32_t)try_cnt, sizeof(g_mp_rf_ctxt->gain_buf[0])); mp_rf_cal_meas_dump("golden_meas pwr1:", g_mp_rf_ctxt->tone_pwr_buf, (uint32_t)try_cnt, sizeof(g_mp_rf_ctxt->tone_pwr_buf[0])); mp_rf_cal_meas_dump("golden_meas pwr2:", g_mp_rf_ctxt->dc_pwr_buf, (uint32_t)try_cnt, sizeof(g_mp_rf_ctxt->dc_pwr_buf[0])); mp_rf_cal_meas_dump("golden_meas pwr3:", g_mp_rf_ctxt->img_pwr_buf, (uint32_t)try_cnt, sizeof(g_mp_rf_ctxt->img_pwr_buf[0])); iot_mac_addr_cpy(g_mp_rf_ctxt->dut_addr_in_cal, dut_addr); g_mp_rf_ctxt->last_meas_sn = sn; g_mp_rf_ctxt->last_tone_pwr = mp_rf_calc_avg_u32(g_mp_rf_ctxt->tone_pwr_buf, try_cnt); g_mp_rf_ctxt->last_dc_pwr = mp_rf_calc_avg_u32(g_mp_rf_ctxt->dc_pwr_buf, try_cnt); g_mp_rf_ctxt->last_img_pwr = mp_rf_calc_avg_u32(g_mp_rf_ctxt->img_pwr_buf, try_cnt); g_mp_rf_ctxt->last_gain = mp_rf_calc_avg_u8(g_mp_rf_ctxt->gain_buf, try_cnt); out: *tone_pwr = g_mp_rf_ctxt->last_tone_pwr; *dc_pwr = g_mp_rf_ctxt->last_dc_pwr; *img_pwr = g_mp_rf_ctxt->last_img_pwr; *gain = g_mp_rf_ctxt->last_gain; end_ntb = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); iot_printf("%s - lo_freq:%luHz, idx:[%d,%d,%d], power[%d,%d,%d]," "gain %f, cons:%lums\n", __FUNCTION__, lo_freq, tone_idx, dc_idx, img_idx, *tone_pwr, *dc_pwr, *img_pwr, *gain, MAC_NTB_TO_MS(mp_rf_ntb_span_calc(end_ntb, start_ntb))); rf_phy_rx_gain_unlock(); return ERR_OK; } static uint32_t IRAM_ATTR mp_plc_isr_handler(uint32_t vector, iot_addrword_t data) { uint32_t int_status, tmp; (void)vector; (void)data; /* read pending interrupt status */ int_status = RGF_MAC_READ_REG(CFG_MAC_INT_STS_ADDR); int_status >>= MAC_INT_STATUS_OFFSET; /* clear pending interrupt status */ RGF_MAC_WRITE_REG(CFG_MAC_INT_CLR_ADDR, (int_status << MAC_INT_CLR_0_OFFSET)); tmp = RGF_MAC_READ_REG(CFG_RX_INT_CLR_ADDR); REG_FIELD_SET(CFG_RX_MPDU_INT_CLR_0, tmp, 1); RGF_MAC_WRITE_REG(CFG_RX_INT_CLR_ADDR, tmp); if (int_status & (1 << MAC_ISR_MPDU_RX_ID)) { os_set_task_event_with_v_from_isr(_init_handle, 1 << MP_RF_EVT_ID_PLC_RX); } return 0; } static void mp_plc_isr_reset() { uint32_t prio_mask; /* disable all mac interrupt and clean up any pending interrupt */ RGF_MAC_WRITE_REG(CFG_INT_ENA_MASK_ADDR, 0); /* clean up all pending interrupt */ RGF_MAC_WRITE_REG(CFG_MAC_INT_CLR_ADDR, CFG_INT_ENABLE_MASK_MASK); /* assign priority 0 interrupts, CPU0 & CPU1 use the interrupt */ prio_mask = 1 << (MAC_ISR_MPDU_RX_ID + CFG_INT_PRI0_MASK_OFFSET); RGF_MAC_WRITE_REG(CFG_INT_PRI0_MASK_ADDR, prio_mask); } void mp_plc_isr_init(void) { /* allocate soc irq resource */ g_mp_rf_ctxt->plc_isr_0_h = iot_interrupt_create(HAL_VECTOR_MAC_0, HAL_INTR_PRI_7, (iot_addrword_t)NULL, mp_plc_isr_handler); g_mp_rf_ctxt->plc_isr_1_h = iot_interrupt_create(HAL_VECTOR_MAC_1, HAL_INTR_PRI_7, (iot_addrword_t)NULL, mp_plc_isr_handler); g_mp_rf_ctxt->plc_isr_2_h = iot_interrupt_create(HAL_VECTOR_MAC_2, HAL_INTR_PRI_7, (iot_addrword_t)NULL, mp_plc_isr_handler); /* attach soc irq resource */ iot_interrupt_attach(g_mp_rf_ctxt->plc_isr_0_h); iot_interrupt_attach(g_mp_rf_ctxt->plc_isr_1_h); iot_interrupt_attach(g_mp_rf_ctxt->plc_isr_2_h); /* enable soc irq */ iot_interrupt_unmask(g_mp_rf_ctxt->plc_isr_0_h); iot_interrupt_unmask(g_mp_rf_ctxt->plc_isr_1_h); iot_interrupt_unmask(g_mp_rf_ctxt->plc_isr_2_h); /* enable interrupt: MAC_ISR_MPDU_RX_ID */ RGF_MAC_WRITE_REG(CFG_INT_ENA_MASK_ADDR, 1 << MAC_ISR_MPDU_RX_ID); } static uint8_t mp_rf_golden_plc_rx(void) { uint8_t *rx_buf = NULL, *rx_pb_buf, *tx_pb_buf, *data; uint8_t ret = ERR_OK; uint8_t reinit = 0; float gain = 0.0; mp_rf_cal_msg_hdr_t *cmd_hdr, *rsp_hdr; mp_rf_cal_meas_cfg_t *meas_cfg; mp_rf_cal_meas_req_t *meas_req; mp_rf_cal_meas_rsp_t *meas_rsp; uint32_t tone_pwr, dc_pwr, img_pwr; rx_buf_hdr_t *hdr = NULL; rx_fc_msg_t rx_fc_msg = {0}; mp_rf_rsp_tx_cali_t* tx_cali_res; while (!is_rx_ring0_empty()) { rx_buf = pop_rx_buf_from_ring(0); if (!rx_buf) { continue; } mp_rf_plc_massage_show(rx_buf); hdr = (rx_buf_hdr_t *)rx_buf; rx_pb_buf = (uint8_t *)(rx_buf + PB_PAYLOAD_OFFSET); data = rx_pb_buf; cmd_hdr = (mp_rf_cal_msg_hdr_t *)data; data += sizeof(*cmd_hdr); mac_get_rx_frm_msg_from_fc(PHY_PROTO_TYPE_GET(), mac_rx_mpdu_st_get_fc_addr(&hdr->mpdu_st), &rx_fc_msg); if (rx_fc_msg.delimiter != FC_DELIM_SOF || rx_fc_msg.nid != glb_cfg.nid || cmd_hdr->magic != MP_RF_TEST_MSG_MAGIC_NUMBER) { continue; } tx_pb_buf = (uint8_t *)phy_get_pb_buf_ptr_from_mpdu(mpdu_start); rsp_hdr = (mp_rf_cal_msg_hdr_t *)tx_pb_buf; rsp_hdr->msg_id = cmd_hdr->msg_id; rsp_hdr->magic = cmd_hdr->magic; iot_mac_addr_cpy(rsp_hdr->dut_addr, cmd_hdr->dut_addr); rsp_hdr->sn = cmd_hdr->sn; switch (cmd_hdr->msg_id) { case MP_RF_CAL_MSG_ID_MEAS_CFG: { meas_cfg = (mp_rf_cal_meas_cfg_t *)data; if (meas_cfg->meas_en) { mp_rf_cal_mode_enter(meas_cfg->option, meas_cfg->ch, meas_cfg->comm_pwr, meas_cfg->comm_tmi); } else { ret = mp_rf_cal_mode_exit(); if (ret == ERR_OK) { /* golden exit calibration mode */ reinit = 1; } } rsp_hdr->option = ERR_OK; tx_send_packet_interval(10); break; } case MP_RF_CAL_MSG_ID_MEAS_REQ: { meas_req = (mp_rf_cal_meas_req_t *)data; meas_rsp = (mp_rf_cal_meas_rsp_t *)rsp_hdr->data; ret = mp_rf_cal_pwr_meas(cmd_hdr->dut_addr, cmd_hdr->sn, meas_req->lo_freq, meas_req->tone_idx, meas_req->dc_idx, meas_req->img_idx, &tone_pwr, &dc_pwr, &img_pwr, &gain, meas_req->avg_cnt); rsp_hdr->option = ret; if (ret == ERR_OK) { meas_rsp->tone_pwr = tone_pwr; meas_rsp->dc_pwr = dc_pwr; meas_rsp->img_pwr = img_pwr; meas_rsp->gain = (uint8_t)(gain + 0.5); meas_rsp->gain_x100 = (uint16_t)(gain * 100.0 + 0.5); os_mem_set(meas_rsp->rsvd, 0, sizeof(meas_rsp->rsvd)); } else { os_mem_set(meas_rsp, 0x0, sizeof(*meas_rsp)); } tx_send_packet_interval(10); break; } case MP_RF_MSG_ID_TX_CALI_STAT_QUERY: { tx_cali_res = (mp_rf_rsp_tx_cali_t*)rsp_hdr->data; mp_rf_get_tx_cali_res((mp_rf_test_cmd_tx_cali_stat_qr_t *)data, tx_cali_res); glb_cfg.tmi = MP_RF_PLC_LARGE_PACKET_TMI; tx_send_packet_interval(10); glb_cfg.tmi = MP_RF_PLC_NORMAL_PACKET_TMI; break; } default: break; } } return reinit; } static void mp_rf_cal_plc_comm_init(uint8_t band) { uint32_t tmp; static uint8_t first_flag = 0; if (!first_flag) { g_phy_cpu_share_ctxt.pt_mode_entry = 1; dut_flag_set(!g_mp_rf_ctxt->is_golden); /* mac rx common init interface */ rx_common_init(band); /* mac tx common init interface */ tx_common_init(band); /* setup the rx ring */ rx_ring_setup_hw(0, NULL); /* enable the rx ring */ rx_ring_enable(0, true); mp_plc_isr_reset(); if (g_mp_rf_ctxt->is_golden) { mp_plc_isr_init(); phy_rxfd_pkt_det_thd_set(32, 32); } /* update flag */ first_flag = 1; glb_cfg.p_type = FC_DELIM_SOF; glb_cfg.tmi = MP_RF_PLC_NORMAL_PACKET_TMI; glb_cfg.ack_en = false; tmp = PHY_READ_REG(CFG_BB_DBG_BUS_SEL_ADDR); REG_FIELD_SET(SW_TX_PILOT_PSS_OVR_EN, tmp, 1); REG_FIELD_SET(SW_RX_PILOT_PSS_OVR_EN, tmp, 1); REG_FIELD_SET(SW_TX_PILOT_PSS, tmp, 6); REG_FIELD_SET(SW_RX_PILOT_PSS, tmp, 6); PHY_WRITE_REG(CFG_BB_DBG_BUS_SEL_ADDR, tmp); } } static uint8_t mp_rf_dut_test_case_csr(iot_ftm_mp_rf_cmd_hdr_t *cmd, void *rsp) { rf_rx_pb_end *pb_end; rf_rx_buf_hdr_t *rx_buf; mp_rf_test_cmd_hdr_t *hdr; mp_rf_test_rsp_t* golden_rsp; mp_rf_test_cmd_csr_t* cmd_csr; iot_ftm_mp_rf_cmd_csr_t* test_csr_cmd; rf_rx_mpdu_start *rx_mpdu = NULL; iot_pkt_t *iot_pkt_array[1] = { 0 }; uint32_t time_span, timeout, timer_start, count = 0; iot_ftm_mp_rf_rsp_csr_t *csr_rsp = (iot_ftm_mp_rf_rsp_csr_t *)rsp; uint32_t proto = PHY_PROTO_TYPE_GET(); /* get rx fc message */ rx_fc_msg_t rx_fc_msg = {0}; uint8_t ret = ERR_TIMEOVER, done = 0, rx_done_tmp = 0; mp_rf_rsp_csr_t* csr_info; uint32_t time0, package_dur; /* cfg DUT tx power */ mac_rf_set_target_tx_power(cmd->dut_power); os_mem_set(csr_rsp, 0, sizeof(*csr_rsp)); mp_rf_recover_def_rate(); hdr = (mp_rf_test_cmd_hdr_t *)g_mp_rf_ctxt->rf_pb_buf; hdr->msg_id = MP_RF_MSG_ID_CSR; hdr->power = cmd->golden_power; hdr->pld_blkz = cmd->pld_blkz; hdr->phr_mcs = cmd->phr_mcs; hdr->pld_mcs = cmd->pld_mcs; hdr->magic = MP_RF_TEST_MSG_MAGIC_NUMBER; cmd_csr = (mp_rf_test_cmd_csr_t*)hdr->data; test_csr_cmd = (iot_ftm_mp_rf_cmd_csr_t*)cmd->data; cmd_csr->packet_num = min(test_csr_cmd->packet_num, MP_RF_CSR_TX_MAX_COUNT); cmd_csr->is_test_mode = test_csr_cmd->is_test_mode; cmd_csr->interval = test_csr_cmd->interval; iot_chip_get_mac_addr(cmd_csr->mac_addr); cmd_csr->ts = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); cmd_csr->rsvd0 = 0; os_mem_set(cmd_csr->rsvd1, 0, sizeof(cmd_csr->rsvd1)); package_dur = phy_rf_get_g_stf_ltf_fl() + phy_rf_get_g_sig_fl() + phy_rf_get_g_phr_fl(hdr->phr_mcs) + phy_rf_get_g_psdu_fl(hdr->pld_mcs, hdr->pld_blkz); iot_printf("%s start -- phr_mcs:%lu, pld_mcs:%lu, pld_blkz:%lu, pwr:%d," " is_tets_mode:%lu, packet_num:%lu, package_dur:%luus, interval:%lu\n", __FUNCTION__, hdr->phr_mcs, hdr->pld_mcs, hdr->pld_blkz, hdr->power, cmd_csr->is_test_mode, cmd_csr->packet_num, package_dur, cmd_csr->interval); timeout = min(max(test_csr_cmd->timeout, MP_RF_TEST_CASE_CSR_TIMEOUT_DEF), MP_RF_TEST_CASE_CSR_TIMEOUT_MAX); mp_rf_tx_packet(0); timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); time0 = timer_start; do { time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), timer_start); time_span = MAC_NTB_TO_MS(time_span); if (!csr_rsp->rx_cnt && time_span >= MP_RF_CMD_RETRY_INTERVAL && count < MP_RF_CMD_RETRY_COUNT) { count++; mp_rf_tx_packet(0); timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); timeout -= MP_RF_CMD_RETRY_INTERVAL; } if (!rx_done_tmp) { rx_done_tmp = mp_rf_check_rf_rx_done(); if (!rx_done_tmp) { continue; } } if (0 == rf_pop_buf_from_ring(&g_mp_rf_ctxt->rx_ring, 1, iot_pkt_array)) { rx_done_tmp = 0; continue; } if (mp_rf_check_rx_packet(iot_pkt_array[0])) goto free_packet; mp_rf_rx_show_message_info(iot_pkt_array[0]); rx_buf = (rf_rx_buf_hdr_t *)iot_pkt_data(iot_pkt_array[0]); golden_rsp = (mp_rf_test_rsp_t *)((uint8_t *)rx_buf + PB_PAYLOAD_OFFSET); pb_end = &rx_buf->pb_ed; rx_mpdu = &rx_buf->mpdu_st; mac_rf_get_rx_frm_msg_from_fc(proto, mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu), &rx_fc_msg); csr_info = (mp_rf_rsp_csr_t*)golden_rsp->data; if ((rx_fc_msg.delimiter == FC_DELIM_SOF) && (!pb_end->rx_pb_crc_err) && (rx_fc_msg.nid == glb_cfg.nid) && (golden_rsp->magic == MP_RF_TEST_MSG_MAGIC_NUMBER) && (golden_rsp->msg_id == MP_RF_MSG_ID_CSR)) { g_mp_rf_ctxt->snr_buf[csr_rsp->rx_cnt] = mac_rf_rx_mpdu_st_get_avg_snr(rx_mpdu); g_mp_rf_ctxt->rssi_buf[csr_rsp->rx_cnt] = mac_rf_rx_mpdu_st_get_rssi(rx_mpdu); /* estimate the remaining time for golden to send data. */ if (!csr_rsp->rx_cnt && csr_info->sn < cmd_csr->packet_num) { timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); time_span = 0; /* each package plus 3ms fixed consumption */ timeout = (package_dur + 3000 + cmd_csr->interval) * (cmd_csr->packet_num - csr_info->sn) / 1000; } csr_rsp->rx_cnt++; if (csr_rsp->rx_cnt >= cmd_csr->packet_num || csr_info->sn >= cmd_csr->packet_num - 1) { done = 1; } } free_packet: iot_pkt_free(iot_pkt_array[0]); } while (time_span < timeout && !done); if (csr_rsp->rx_cnt) { ret = ERR_OK; csr_rsp->avg_snr = mp_rf_calc_avg_value(g_mp_rf_ctxt->snr_buf, csr_rsp->rx_cnt) / 10; csr_rsp->avg_rssi = mp_rf_calc_avg_value(g_mp_rf_ctxt->rssi_buf, csr_rsp->rx_cnt) / 10; } time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), time0); time_span = MAC_NTB_TO_MS(time_span); iot_printf("%s csr_rsp: rx_cnt=%lu avg_rssi=%d avg_snr=%d consumed=%lums\n", __FUNCTION__, csr_rsp->rx_cnt, csr_rsp->avg_rssi, csr_rsp->avg_snr, time_span); return ret; } static uint8_t mp_rf_dut_test_case_csi(iot_ftm_mp_rf_cmd_hdr_t *cmd, void *rsp) { rf_rx_pb_end *pb_end; rf_rx_buf_hdr_t *rx_buf; rf_rx_mpdu_start *rx_mpdu; mp_rf_test_cmd_hdr_t *hdr; mp_rf_test_rsp_t* golden_rsp; iot_pkt_t *iot_pkt_array[1] = { 0 }; uint32_t timer_start, time_span, timeout, count = 0, done = 0; iot_ftm_mp_rf_rsp_csi_t *csi_rsp = (iot_ftm_mp_rf_rsp_csi_t *)rsp; uint32_t package_dur, proto = PHY_PROTO_TYPE_GET(); iot_ftm_mp_rf_cmd_csi_t *csi_cmd; /* get rx fc message */ rx_fc_msg_t rx_fc_msg = {0}; uint8_t ret = ERR_TIMEOVER, rx_count = 0, rx_done_tmp = 0;; int8_t tx_rssi_thr, rx_rssi_thr, tx_snr_thr, rx_snr_thr; /* cfg DUT tx power */ mac_rf_set_target_tx_power(cmd->dut_power); g_mp_rf_ctxt->phr_mcs = cmd->phr_mcs; g_mp_rf_ctxt->pld_mcs = cmd->pld_mcs; g_mp_rf_ctxt->pld_blkz = cmd->pld_blkz; hdr = (mp_rf_test_cmd_hdr_t *)g_mp_rf_ctxt->rf_pb_buf; hdr->msg_id = MP_RF_MSG_ID_CSI; hdr->power = cmd->golden_power; hdr->pld_blkz = g_mp_rf_ctxt->pld_blkz; hdr->phr_mcs = g_mp_rf_ctxt->phr_mcs; hdr->pld_mcs = g_mp_rf_ctxt->pld_mcs; hdr->magic = MP_RF_TEST_MSG_MAGIC_NUMBER; csi_cmd = (iot_ftm_mp_rf_cmd_csi_t *)cmd->data; package_dur = phy_rf_get_g_stf_ltf_fl() + phy_rf_get_g_sig_fl() + phy_rf_get_g_phr_fl(hdr->phr_mcs) + phy_rf_get_g_psdu_fl(hdr->pld_mcs, hdr->pld_blkz); iot_printf("%s start -- phr_mcs:%lu, pld_mcs:%lu, pld_blkz:%lu, pwr:%d, " "package_dur:%luus, tx_rssi_thr=%d, rx_rssi_thr=%d, tx_snr_thr=%d, " "rx_snr_thr=%d\n", __FUNCTION__, hdr->phr_mcs, hdr->pld_mcs, hdr->pld_blkz, hdr->power, package_dur, csi_cmd->tx_rssi_thr, csi_cmd->rx_rssi_thr, csi_cmd->tx_snr_thr, csi_cmd->rx_snr_thr); timeout = MP_RF_TEST_CASE_CSI_TIMEOUT_DEF; mp_rf_tx_packet(0); os_mem_set(csi_rsp, 0, sizeof(*csi_rsp)); csi_rsp->tx_rssi = MP_RF_INVAL_RSSI_SNR; csi_rsp->rx_rssi = MP_RF_INVAL_RSSI_SNR; csi_rsp->tx_snr = MP_RF_INVAL_RSSI_SNR; csi_rsp->rx_snr = MP_RF_INVAL_RSSI_SNR; tx_rssi_thr = csi_cmd->tx_rssi_thr == MP_RF_INVAL_RSSI_SNR ? MP_RF_CSI_TEST_RSSI_THR : csi_cmd->tx_rssi_thr; rx_rssi_thr = csi_cmd->rx_rssi_thr == MP_RF_INVAL_RSSI_SNR ? MP_RF_CSI_TEST_RSSI_THR : csi_cmd->rx_rssi_thr; tx_snr_thr = csi_cmd->tx_snr_thr == MP_RF_INVAL_RSSI_SNR ? MP_RF_CSI_TEST_SNR_THR : csi_cmd->tx_snr_thr; rx_snr_thr = csi_cmd->rx_snr_thr == MP_RF_INVAL_RSSI_SNR ? MP_RF_CSI_TEST_SNR_THR : csi_cmd->rx_snr_thr; timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); do { time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), timer_start); time_span = MAC_NTB_TO_MS(time_span); if (time_span >= MP_RF_CMD_RETRY_INTERVAL && count < MP_RF_CMD_RETRY_COUNT) { count++; mp_rf_tx_packet(0); timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); timeout -= MP_RF_CMD_RETRY_INTERVAL; } if (!rx_done_tmp) { rx_done_tmp = mp_rf_check_rf_rx_done(); if (!rx_done_tmp) { continue; } } if (0 == rf_pop_buf_from_ring(&g_mp_rf_ctxt->rx_ring, 1, iot_pkt_array)) { rx_done_tmp = 0; continue; } if (mp_rf_check_rx_packet(iot_pkt_array[0])) goto free_packet; mp_rf_rx_show_message_info(iot_pkt_array[0]); rx_buf = (rf_rx_buf_hdr_t *)iot_pkt_data(iot_pkt_array[0]); golden_rsp = (mp_rf_test_rsp_t *)((uint8_t *)rx_buf + PB_PAYLOAD_OFFSET); pb_end = &rx_buf->pb_ed; rx_mpdu = &rx_buf->mpdu_st; mac_rf_get_rx_frm_msg_from_fc(proto, mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu), &rx_fc_msg); if ((rx_fc_msg.delimiter == FC_DELIM_SOF) && (!pb_end->rx_pb_crc_err) && (rx_fc_msg.nid == glb_cfg.nid) && (golden_rsp->magic == MP_RF_TEST_MSG_MAGIC_NUMBER) && (golden_rsp->msg_id == MP_RF_MSG_ID_CSI)) { csi_rsp->tx_rssi = max(csi_rsp->tx_rssi, golden_rsp->tx_rssi); csi_rsp->tx_snr = max(csi_rsp->tx_snr, golden_rsp->tx_snr); csi_rsp->tx_gain = max(golden_rsp->tx_gain, csi_rsp->tx_gain); csi_rsp->rx_snr = max(csi_rsp->rx_snr, mac_rf_rx_mpdu_st_get_avg_snr(rx_mpdu)); csi_rsp->rx_rssi = max(csi_rsp->rx_rssi, mac_rf_rx_mpdu_st_get_rssi(rx_mpdu)); csi_rsp->rx_gain = max(csi_rsp->rx_gain, mac_rf_rx_mpdu_st_get_rx_gain(rx_mpdu)); rx_count++; if (rx_count >= 3 || (csi_rsp->tx_rssi >= tx_rssi_thr && csi_rsp->rx_rssi >= rx_rssi_thr && csi_rsp->tx_snr >= tx_snr_thr && csi_rsp->rx_snr >= rx_snr_thr)) { done = 1; } ret = ERR_OK; iot_printf("csi_recv: tx_rssi=%d, rx_rssi=%d, tx_snr=%d," " rx_snr=%d, tx_gain=%d, rx_gain=%d\n", csi_rsp->tx_rssi, csi_rsp->rx_rssi, csi_rsp->tx_snr, csi_rsp->rx_snr, csi_rsp->tx_gain, csi_rsp->rx_gain); } free_packet: iot_pkt_free(iot_pkt_array[0]); } while (time_span < timeout && !done); if (!done) { iot_printf("%s fail....\n", __FUNCTION__); } return ret; } static uint8_t mp_rf_dut_test_case_tx_evm(iot_ftm_mp_rf_cmd_hdr_t *cmd, void *rsp) { rf_rx_pb_end *pb_end; rf_rx_buf_hdr_t *rx_buf; rf_rx_mpdu_start *rx_mpdu; mp_rf_test_cmd_hdr_t *hdr; iot_ftm_mp_rf_rsp_tx_evm_t *dut_rsp = (iot_ftm_mp_rf_rsp_tx_evm_t *)rsp; mp_rf_test_cmd_tx_evm_t *tx_evm_cmd; iot_ftm_mp_rf_cmd_tx_evm_t *test_cmd; mp_rf_rsp_tx_evm_t *tx_evm_rsp; mp_rf_test_rsp_t* golden_rsp; iot_pkt_t *iot_pkt_array[1] = { 0 }; uint32_t timer_start, time_span, timeout, count = 0, done = 0; uint32_t proto = PHY_PROTO_TYPE_GET(); /* get rx fc message */ rx_fc_msg_t rx_fc_msg = {0}; uint8_t ret = ERR_TIMEOVER, rx_done_tmp = 0; uint16_t packet_num, i; hdr = (mp_rf_test_cmd_hdr_t *)g_mp_rf_ctxt->rf_pb_buf; hdr->pld_blkz = 0; hdr->phr_mcs = 0; hdr->pld_mcs = 0; hdr->power = cmd->golden_power; hdr->magic = MP_RF_TEST_MSG_MAGIC_NUMBER; hdr->msg_id = MP_RF_MSG_ID_TX_EVM_SAMP; tx_evm_cmd = (mp_rf_test_cmd_tx_evm_t *)hdr->data; iot_chip_get_mac_addr(tx_evm_cmd->mac_addr); tx_evm_cmd->ts = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); test_cmd = (iot_ftm_mp_rf_cmd_tx_evm_t *)cmd->data; packet_num = test_cmd->packet_num; packet_num = min(MP_RF_TX_EVM_SMAP_MAX_CNT, packet_num); iot_printf("%s start -- phr_mcs:%lu, pld_mcs:%lu, pld_blkz:%lu, " "is_nor_pwr:%lu, dut_pwr:%d, golden_pwr:%d, packet_num:%lu, " "no_req_flag:%d, interval:%lu\n", __FUNCTION__, cmd->phr_mcs, cmd->pld_mcs, cmd->pld_blkz, test_cmd->is_nor_pwr, cmd->dut_power, cmd->golden_power, packet_num, test_cmd->no_req_flag, test_cmd->interval); /* step1: send tx evm sample data to golden */ if (!test_cmd->is_nor_pwr) { /* use the cert test mode power configuration */ mac_rf_set_cert_mode(CERT_TEST_CMD_ENTER_PHY_HPLC2RF_LP); if (cmd->phr_mcs == MCS_ID_5 || cmd->phr_mcs == MCS_ID_6 || cmd->pld_mcs == MCS_ID_5 || cmd->pld_mcs == MCS_ID_6) { /* mcs 5/6 need special config */ mac_rf_set_cert_16qam_flag(1); } else { mac_rf_set_cert_16qam_flag(0); } } else { /* use the power configuration specified by the test script. */ mac_rf_set_target_tx_power(cmd->dut_power); } g_mp_rf_ctxt->phr_mcs = cmd->phr_mcs; g_mp_rf_ctxt->pld_mcs = cmd->pld_mcs; g_mp_rf_ctxt->pld_blkz = cmd->pld_blkz; for (i = 0; i < packet_num; i++) { mp_rf_tx_packet(test_cmd->interval); } /* step2: send command MP_RF_MSG_ID_TX_EVM_STAT_QUERY to get results from * golden and wait for a response. */ timeout = MP_RF_TEST_CASE_TX_EVM_TIMEOUT_DEF; timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); mp_rf_recover_def_rate(); if (!test_cmd->is_nor_pwr) { /* after sending the evm samples, restore the power configuration. * for some DUT, the success rate of query results can be improved. */ mac_rf_set_cert_mode(0); mac_rf_set_cert_16qam_flag(0); mac_rf_set_target_tx_power(cmd->dut_power); } if (test_cmd->no_req_flag) { return ERR_OK; } hdr->msg_id = MP_RF_MSG_ID_TX_EVM_STAT_QUERY; mp_rf_tx_packet(0); do { time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), timer_start); time_span = MAC_NTB_TO_MS(time_span); if (time_span >= MP_RF_CMD_RETRY_INTERVAL && count < MP_RF_CMD_RETRY_COUNT) { count++; timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); timeout -= MP_RF_CMD_RETRY_INTERVAL; mp_rf_tx_packet(0); } if (!rx_done_tmp) { rx_done_tmp = mp_rf_check_rf_rx_done(); if (!rx_done_tmp) { continue; } } if (0 == rf_pop_buf_from_ring(&g_mp_rf_ctxt->rx_ring, 1, iot_pkt_array)) { rx_done_tmp = 0; continue; } if (mp_rf_check_rx_packet(iot_pkt_array[0])) goto free_packet; mp_rf_rx_show_message_info(iot_pkt_array[0]); rx_buf = (rf_rx_buf_hdr_t *)iot_pkt_data(iot_pkt_array[0]); golden_rsp = (mp_rf_test_rsp_t *)((uint8_t *)rx_buf + PB_PAYLOAD_OFFSET); pb_end = &rx_buf->pb_ed; rx_mpdu = &rx_buf->mpdu_st; mac_rf_get_rx_frm_msg_from_fc(proto, mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu), &rx_fc_msg); if ((rx_fc_msg.delimiter == FC_DELIM_SOF) && (!pb_end->rx_pb_crc_err) && (rx_fc_msg.nid == glb_cfg.nid) && (golden_rsp->msg_id == MP_RF_MSG_ID_TX_EVM_STAT_QUERY) && (golden_rsp->magic == MP_RF_TEST_MSG_MAGIC_NUMBER)) { tx_evm_rsp = (mp_rf_rsp_tx_evm_t *)golden_rsp->data; dut_rsp->avg_rssi = tx_evm_rsp->avg_rssi; dut_rsp->avg_snr = tx_evm_rsp->avg_snr; dut_rsp->rx_cnt = tx_evm_rsp->rx_cnt; os_mem_set(dut_rsp->rsvd, 0, sizeof(dut_rsp->rsvd)); iot_printf("%s rx_count=%lu, rssi=%f, snr=%f\n", __FUNCTION__, tx_evm_rsp->rx_cnt, (float)tx_evm_rsp->avg_rssi / 10, (float)tx_evm_rsp->avg_snr / 10); ret = ERR_OK; done = 1; } free_packet: iot_pkt_free(iot_pkt_array[0]); } while (time_span < timeout && !done); return ret; } static uint8_t mp_rf_cal_rsp_poll(uint8_t msg_id, uint8_t **buf, uint32_t timeout, mp_rf_cal_msg_hdr_t *req_hdr) { uint8_t *rx_buf, *rx_pb_buf, *data; rx_buf_hdr_t *hdr = NULL; mp_rf_cal_msg_hdr_t *rsp_hdr; rx_fc_msg_t rx_fc_msg = {0}; uint32_t start_ntb, time_sapn; rx_pb_end *pb_end; start_ntb = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); for (; ;) { if (is_rx_ring0_empty()) { goto next; } rx_buf = pop_rx_buf_from_ring(0); if (!rx_buf) { goto next; } mp_rf_plc_massage_show(rx_buf); hdr = (rx_buf_hdr_t *)rx_buf; rx_pb_buf = (uint8_t *)(rx_buf + PB_PAYLOAD_OFFSET); pb_end = &(hdr->pb_ed); data = rx_pb_buf; rsp_hdr = (mp_rf_cal_msg_hdr_t *)data; data += sizeof(*rsp_hdr); mac_get_rx_frm_msg_from_fc(PHY_PROTO_TYPE_GET(), mac_rx_mpdu_st_get_fc_addr(&hdr->mpdu_st), &rx_fc_msg); if (rx_fc_msg.delimiter == FC_DELIM_SOF && !pb_end->rx_pb_crc_err && rx_fc_msg.nid == glb_cfg.nid && rsp_hdr->magic == MP_RF_TEST_MSG_MAGIC_NUMBER && rsp_hdr->msg_id == msg_id) { if (iot_mac_addr_cmp(req_hdr->dut_addr, rsp_hdr->dut_addr) == 1 && req_hdr->sn == rsp_hdr->sn) { *buf = rx_pb_buf; return ERR_OK; } } next: time_sapn = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), start_ntb); if (MAC_NTB_TO_MS(time_sapn) > timeout) { break; } } return ERR_TIMEOVER; } static uint8_t mp_rf_dut_test_case_tx_cali_exec( iot_ftm_mp_rf_cmd_tx_cali_t* test_cmd, uint8_t** buf, uint16_t dev_id_magic) { uint32_t pos; mp_rf_test_cmd_tx_cali_stat_qr_t *rf_cmd; /* get rx fc message */ int8_t i, q, ret = ERR_TIMEOVER; uint8_t *tx_pb_buf; uint8_t repeat_cnt, max_code; mp_rf_cal_msg_hdr_t *rsp_hdr; mp_rf_cal_msg_hdr_t *req_hdr; uint8_t *bm = g_mp_rf_ctxt->snr_samp_bitmap; uint8_t bm_size = MP_RF_TX_CALI_SNR_BM_SIZE; max_code = (test_cmd->type == RF_TEST_TX_CALI_REG_IQ_MAG) ? RF_PHY_IQ_MAG_COMPEN_CODE_MAX : RF_PHY_IQ_PHASE_COMPEN_CODE_MAX; repeat_cnt = test_cmd->repeat_cnt; while (repeat_cnt-- > 0) { for (i = 0; i < max_code; i++) { for (q = 0; q < max_code; q++) { pos = MP_RF_IQ_CODE_TO_MAGIC(max_code, i, q); if (iot_bitmap_is_set(bm, bm_size, pos + 1)) { mp_rf_tx_mpdu_with_tx_cali_samp(test_cmd->type, i, q, dev_id_magic); } } } } /* step 2: query result */ tx_pb_buf = (uint8_t *)phy_get_pb_buf_ptr_from_mpdu(mpdu_start); req_hdr = (mp_rf_cal_msg_hdr_t *)tx_pb_buf; req_hdr->magic = MP_RF_TEST_MSG_MAGIC_NUMBER; req_hdr->msg_id = MP_RF_MSG_ID_TX_CALI_STAT_QUERY; req_hdr->sn = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); iot_chip_get_mac_addr(req_hdr->dut_addr); rf_cmd = (mp_rf_test_cmd_tx_cali_stat_qr_t*)req_hdr->data; rf_cmd->dev_id_magic = dev_id_magic; rf_cmd->type = test_cmd->type; rf_cmd->liner_fit_en = test_cmd->liner_fit_en; for (i = 0; i < 5; i++) { tx_send_packet_interval(10); ret = mp_rf_cal_rsp_poll(MP_RF_MSG_ID_TX_CALI_STAT_QUERY, buf, 50, req_hdr); if (ret == ERR_OK) { rsp_hdr = (mp_rf_cal_msg_hdr_t *)(*buf); *buf = rsp_hdr->data; break; } } return ret; } static uint8_t mp_rf_dut_test_case_tx_cali(iot_ftm_mp_rf_cmd_hdr_t *cmd, void *rsp, uint8_t *len) { iot_ftm_mp_rf_cmd_tx_cali_t *test_cmd; uint8_t ret = ERR_TIMEOVER, step; int8_t i, q, min_i, max_i, min_q, max_q, min_code, max_code, code; uint16_t dev_id_magic, j; uint8_t buf[IOT_MAC_ADDR_LEN + 4]; uint8_t i_sweep_list[RF_PHY_IQ_PHASE_COMPEN_CODE_MAX]; uint8_t q_sweep_list[RF_PHY_IQ_PHASE_COMPEN_CODE_MAX], i_cnt = 0, q_cnt = 0; uint8_t *data_buf; mp_rf_rsp_tx_cali_t *rsp_hdr; iot_ftm_mp_rf_rsp_tx_cali_t* dut_rsp; uint32_t timer_start; g_mp_rf_ctxt->phr_mcs = cmd->phr_mcs; test_cmd = (iot_ftm_mp_rf_cmd_tx_cali_t*)cmd->data; iot_chip_get_mac_addr(buf); timer_start = (uint16_t)RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); os_mem_cpy(buf + IOT_MAC_ADDR_LEN, &timer_start, 4); dev_id_magic = iot_getcrc16(buf, sizeof(buf), 0); switch (test_cmd->type) { case RF_TEST_TX_CALI_REG_IQ_MAG: { min_code = 0; max_code = RF_PHY_IQ_MAG_COMPEN_CODE_MAX; step = min(2, test_cmd->step); break; } case RF_TEST_TX_CALI_REG_IQ_PHASE: { min_code = 0; max_code = RF_PHY_IQ_PHASE_COMPEN_CODE_MAX; step = min(4, test_cmd->step); break; } default: iot_printf("%s parameters error\n", __FUNCTION__); ret = ERR_INVAL; goto out; } min_i = min(max_code, max(min_code, test_cmd->i_min)); max_i = min(max_code, max(min_code, test_cmd->i_max)); min_q = min(max_code, max(min_code, test_cmd->q_min)); max_q = min(max_code, max(min_code, test_cmd->q_max)); if (!step) step = 1; iot_printf("%s tx cali type:%d, i:[%d, %d], q:[%d, %d], step:%d, " "liner_fit_en:%d, is_nor_pwr:%d, power:%d, phr_mcs:%d, rounds:%d\n", __FUNCTION__, test_cmd->type, min_i, max_i, min_q, max_q, step, test_cmd->liner_fit_en, test_cmd->is_nor_pwr, cmd->dut_power, cmd->phr_mcs, test_cmd->rounds); if (max_i < min_i || max_q < min_q || !test_cmd->rounds) { ret = ERR_INVAL; goto out; } if (!test_cmd->is_nor_pwr) { /* use the cert test mode power configuration */ mac_rf_set_cert_mode(CERT_TEST_CMD_ENTER_PHY_HPLC2RF_LP); if (cmd->phr_mcs == MCS_ID_5 || cmd->phr_mcs == MCS_ID_6 || cmd->pld_mcs == MCS_ID_5 || cmd->pld_mcs == MCS_ID_6) { /* mcs 5/6 need special config */ mac_rf_set_cert_16qam_flag(1); } else { mac_rf_set_cert_16qam_flag(0); } } else { /* use the power configuration specified by the test script. */ mac_rf_set_target_tx_power(cmd->dut_power); } os_mem_set(g_mp_rf_ctxt->snr_samp_bitmap, 0, MP_RF_TX_CALI_SNR_BM_SIZE); if (test_cmd->iq_delta_en) { for (code = max_i - 1; code > -max_q; code -= step) { if (code > 0) { j = MP_RF_IQ_CODE_TO_MAGIC(max_code, code, 0); } else { j = MP_RF_IQ_CODE_TO_MAGIC(max_code, 0, -code); } iot_bitmap_set(g_mp_rf_ctxt->snr_samp_bitmap, MP_RF_TX_CALI_SNR_BM_SIZE, j + 1); } } else { iot_printf("%s i_sweep_list[", __FUNCTION__); for (i = min_i; i < max_i; i += step) { i_sweep_list[i_cnt] = i; iot_printf("%d, ", i_sweep_list[i_cnt]); i_cnt++; } if (i_sweep_list[i_cnt - 1] < max_i - 1) { i_sweep_list[i_cnt] = max_i - 1; iot_printf("%d", i_sweep_list[i_cnt]); i_cnt++; } iot_printf("], q_sweep_list["); for (q = min_q; q < max_q; q += step) { q_sweep_list[q_cnt] = q; iot_printf("%d, ", q_sweep_list[q_cnt]); q_cnt++; } if (q_sweep_list[q_cnt - 1] < max_q - 1) { q_sweep_list[q_cnt] = max_q - 1; iot_printf("%d", q_sweep_list[q_cnt]); q_cnt++; } iot_printf("]\n"); if (q_cnt * i_cnt > MP_RF_TX_CALI_SNR_REAL_DATA_GROUP_SIZE) { ret = ERR_NOMEM; goto out; } for (i = 0; i < i_cnt; i++) { for (q = 0; q < q_cnt; q++) { j = MP_RF_IQ_CODE_TO_MAGIC(max_code, i_sweep_list[i], q_sweep_list[q]); iot_bitmap_set(g_mp_rf_ctxt->snr_samp_bitmap, MP_RF_TX_CALI_SNR_BM_SIZE, j + 1); } } } for (i = 0; i < test_cmd->rounds; i++) { ret = mp_rf_dut_test_case_tx_cali_exec(test_cmd, &data_buf, dev_id_magic); if (ret == ERR_OK) { rsp_hdr = (mp_rf_rsp_tx_cali_t *)data_buf; for (j = 0; j < MP_RF_TX_CALI_SNR_BM_SIZE; j++) { g_mp_rf_ctxt->snr_samp_bitmap[j] &= ~rsp_hdr->bm[j]; } if (iot_bitmap_cbs(g_mp_rf_ctxt->snr_samp_bitmap, MP_RF_TX_CALI_SNR_BM_SIZE) == 0) { iot_printf("%s bitmap all clear, retry=%d\n", __FUNCTION__, i); break; } } } if (ret == ERR_OK) { *len = sizeof(iot_ftm_mp_rf_rsp_tx_cali_t); dut_rsp = (iot_ftm_mp_rf_rsp_tx_cali_t *)rsp; dut_rsp->cnt = min(rsp_hdr->cnt, MP_RF_TX_CALI_SNR_BEST_RESULT_MAX); *len += sizeof(iot_ftm_mp_rf_tx_cali_comen_result_t) * dut_rsp->cnt; iot_printf("%s best_result:", __FUNCTION__); for (i = 0; i < dut_rsp->cnt; i++) { dut_rsp->result[i].i = rsp_hdr->result[i].i; dut_rsp->result[i].q = rsp_hdr->result[i].q; dut_rsp->result[i].snr = rsp_hdr->result[i].snr; iot_printf("[%f, %d, %d], ", __FUNCTION__, dut_rsp->result[i].snr, dut_rsp->result[i].i, dut_rsp->result[i].q); } iot_printf("\n"); } if (!test_cmd->is_nor_pwr) { /* after sending the evm samples, restore the power configuration. * for some DUT, the success rate of query results can be improved. */ mac_rf_set_cert_mode(0); mac_rf_set_cert_16qam_flag(0); mac_rf_set_target_tx_power(cmd->dut_power); } out: return ret; } static uint8_t mp_rf_dut_test_case_chg_phy(iot_ftm_mp_rf_cmd_hdr_t *cmd, void *rsp) { rf_rx_pb_end *pb_end; rf_rx_buf_hdr_t *rx_buf; rf_rx_mpdu_start *rx_mpdu; mp_rf_test_cmd_hdr_t *hdr; mp_rf_test_rsp_t* golden_rsp; iot_pkt_t *iot_pkt_array[1] = { 0 }; iot_ftm_mp_rf_cmd_chg_phy_t *target_para; mp_rf_test_cmd_chg_phy_t *phy_para; uint32_t timer_start, time_span, timeout, count = 0, done = 0; uint32_t proto = PHY_PROTO_TYPE_GET(); /* get rx fc message */ rx_fc_msg_t rx_fc_msg = {0}; uint8_t ret = ERR_TIMEOVER, rx_done_tmp = 0; /* cfg DUT tx power */ mac_rf_set_target_tx_power(cmd->dut_power); hdr = (mp_rf_test_cmd_hdr_t *)g_mp_rf_ctxt->rf_pb_buf; hdr->pld_blkz = 0; hdr->phr_mcs = 0; hdr->pld_mcs = 0; hdr->power = cmd->golden_power; hdr->magic = MP_RF_TEST_MSG_MAGIC_NUMBER; hdr->msg_id = MP_RF_MSG_ID_CHG_PHY; target_para = (iot_ftm_mp_rf_cmd_chg_phy_t *)cmd->data; phy_para = (mp_rf_test_cmd_chg_phy_t *)hdr->data; phy_para->option = target_para->option; phy_para->channel = target_para->channel; iot_printf("%s start -- current phy para[option:%d channel:%d], " "target phy para[option:%d channel:%d]\n", __FUNCTION__, cmd->option, cmd->channel, target_para->option, target_para->channel); if (target_para->option == g_mp_rf_ctxt->option && target_para->channel == g_mp_rf_ctxt->channel) { iot_printf("%s no need change phy parameters\n", __FUNCTION__); ret = ERR_OK; goto out; } /* step1: notify golden to switch option and channel */ mp_rf_recover_def_rate(); mp_rf_tx_packet(0); timeout = MP_RF_TEST_CASE_CHG_PHY_TIMEOUT_DEF; timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); do { time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), timer_start); time_span = MAC_NTB_TO_MS(time_span); if (!done && time_span >= MP_RF_CMD_RETRY_INTERVAL && count < MP_RF_CMD_RETRY_COUNT) { count++; timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); timeout -= MP_RF_CMD_RETRY_INTERVAL; mp_rf_tx_packet(0); } if (!rx_done_tmp) { rx_done_tmp = mp_rf_check_rf_rx_done(); if (!rx_done_tmp) { continue; } } if (0 == rf_pop_buf_from_ring(&g_mp_rf_ctxt->rx_ring, 1, iot_pkt_array)) { rx_done_tmp = 0; continue; } /* after receiving the correct reply, discard all packets received * during the waiting period. If the correct response is not received, * discard the received exception packet. */ if (mp_rf_check_rx_packet(iot_pkt_array[0])) goto free_packet; mp_rf_rx_show_message_info(iot_pkt_array[0]); if (done) goto free_packet; rx_buf = (rf_rx_buf_hdr_t *)iot_pkt_data(iot_pkt_array[0]); golden_rsp = (mp_rf_test_rsp_t *)((uint8_t *)rx_buf + PB_PAYLOAD_OFFSET); pb_end = &rx_buf->pb_ed; rx_mpdu = &rx_buf->mpdu_st; mac_rf_get_rx_frm_msg_from_fc(proto, mac_rf_rx_mpdu_st_get_phr_addr(rx_mpdu), &rx_fc_msg); if ((rx_fc_msg.delimiter == FC_DELIM_SOF) && (!pb_end->rx_pb_crc_err) && (rx_fc_msg.nid == glb_cfg.nid) && (golden_rsp->magic == MP_RF_TEST_MSG_MAGIC_NUMBER) && (golden_rsp->msg_id == MP_RF_MSG_ID_CHG_PHY)) { iot_printf("%s golden response successfully\n", __FUNCTION__); ret = ERR_OK; done = 1; timeout = MP_RF_TEST_CASE_CHG_PHY_TIMEOUT_DEF; timer_start = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); } free_packet: iot_pkt_free(iot_pkt_array[0]); } while (time_span < timeout); out: return ret; } uint8_t mp_rf_dut_cal_cfg(iot_ftm_mp_rf_cal_meas_cfg_t *cfg) { uint8_t *tx_pb_buf, *rx_pb_buf, i; uint8_t *data, result; mp_rf_cal_msg_hdr_t *req_hdr, *rsp_hdr; mp_rf_cal_meas_cfg_t *meas_cfg; mp_rf_cal_plc_comm_init(MP_RF_PLC_INIT_BAND); tx_pb_buf = (uint8_t *)phy_get_pb_buf_ptr_from_mpdu(mpdu_start); data = tx_pb_buf; req_hdr = (mp_rf_cal_msg_hdr_t *)data; req_hdr->magic = MP_RF_TEST_MSG_MAGIC_NUMBER; req_hdr->msg_id = MP_RF_CAL_MSG_ID_MEAS_CFG; req_hdr->sn = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); iot_chip_get_mac_addr(req_hdr->dut_addr); /* update DUT communication power and tmi */ phy_pwr_adjust_set(cfg->comm_pwr); glb_cfg.tmi = MP_RF_PLC_NORMAL_PACKET_TMI; data += sizeof(*req_hdr); meas_cfg = (mp_rf_cal_meas_cfg_t *)data; meas_cfg->meas_en = cfg->meas_en; meas_cfg->option = cfg->option; meas_cfg->ch = cfg->ch; meas_cfg->comm_pwr = cfg->comm_pwr; meas_cfg->comm_tmi = MP_RF_PLC_NORMAL_PACKET_TMI; iot_printf("%s en:%lu,option:%lu,ch:%lu,comm_pwr:%lu,comm_tmi:%lu\n", __FUNCTION__, cfg->meas_en, cfg->option, cfg->ch, cfg->comm_pwr, cfg->comm_tmi); for (i = 0; i < 5; i++) { tx_send_packet_interval(10); result = mp_rf_cal_rsp_poll(req_hdr->msg_id, &rx_pb_buf, 50, req_hdr); if (result == ERR_OK) { rsp_hdr = (mp_rf_cal_msg_hdr_t *)rx_pb_buf; result = rsp_hdr->option; break; } } if (i >= 5) { result = ERR_TIMEOVER; } iot_printf("%s result:%lu\n", __FUNCTION__, result); return result; } void mp_rf_dut_cal_reg_update(iot_ftm_mp_rf_tx_cal_update_t *cal_update) { #define TX_CAL_UPDATE_TIMEOUT 5000000 uint32_t start_ntb, time_span; if (cal_update->tx_iq_mag_update) { mac_rf_set_tx_iqm_cali(cal_update->tx_i_mag, cal_update->tx_q_mag); iot_printf("%s, iq_mag[%d %d]\n", __FUNCTION__, cal_update->tx_i_mag, cal_update->tx_q_mag); } if (cal_update->tx_iq_phase_update) { mac_rf_set_tx_iqp_cali(cal_update->tx_i_phase, cal_update->tx_q_phase); iot_printf("%s, iq_phase[%d %d]\n", __FUNCTION__, cal_update->tx_i_phase, cal_update->tx_q_phase); } if (cal_update->tx_iq_dc_update) { mac_rf_set_tx_dc_cali(cal_update->tx_i_dc, cal_update->tx_q_dc); iot_printf("%s, iq_dc[%d %d]\n ", __FUNCTION__, cal_update->tx_i_dc, cal_update->tx_q_dc); } if (cal_update->filter_update) { mac_rf_set_tx_filter_cali(cal_update->filter_option, 1, cal_update->filter_bw_sel); iot_printf("%s, option:%lu, filter:%lu\n", __FUNCTION__, cal_update->filter_option, cal_update->filter_bw_sel); } mac_rf_set_tx_cal_update_status(0); mac_rf_set_sw_irq_to_bbcpu(RF_MAC_SW_ISR_TX_CAL_UPDATE); /* wait bbcpu update RF calibration register */ start_ntb = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); while (!mac_rf_get_tx_cal_update_status()) { time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), start_ntb); if (time_span > TX_CAL_UPDATE_TIMEOUT) { IOT_ASSERT(0); } } return; } void mp_rf_dut_cal_meas_pwr(iot_ftm_mp_rf_cal_meas_req_t *req, iot_ftm_mp_rf_cal_meas_rsp_t *rsp) { uint8_t *tx_pb_buf, *rx_pb_buf, i; uint8_t *data, ret = ERR_OK; mp_rf_cal_msg_hdr_t *req_hdr, *rsp_hdr; mp_rf_cal_meas_req_t *meas_req; mp_rf_cal_meas_rsp_t *meas_rsp; uint32_t start_ntb, time_span; uint32_t timeout; /* initialize HPLC phy */ mp_rf_cal_plc_comm_init(MP_RF_PLC_INIT_BAND); start_ntb = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); tx_pb_buf = (uint8_t *)phy_get_pb_buf_ptr_from_mpdu(mpdu_start); data = tx_pb_buf; req_hdr = (mp_rf_cal_msg_hdr_t *)data; req_hdr->magic = MP_RF_TEST_MSG_MAGIC_NUMBER; req_hdr->msg_id = MP_RF_CAL_MSG_ID_MEAS_REQ; req_hdr->sn = start_ntb; iot_chip_get_mac_addr(req_hdr->dut_addr); /* step1: update the specified tx calibration register before measuring * power. */ mp_rf_dut_cal_reg_update(&req->tx_cal); data += sizeof(*req_hdr); meas_req = (mp_rf_cal_meas_req_t *)data; meas_req->lo_freq = req->lo_freq; meas_req->tone_idx = req->tone_idx; meas_req->dc_idx = req->dc_idx; meas_req->img_idx = req->img_idx; meas_req->avg_cnt = req->avg_cnt; os_mem_set(meas_req->rsvd, 0, sizeof(meas_req->rsvd)); /* TODO: it is necessary to adjust the optimal retry policy to balance the * communication reliability and efficiency. */ timeout = req->timeout; for (i = 0; i < req->try_cnt; i++) { tx_send_packet_interval(10); ret = mp_rf_cal_rsp_poll(req_hdr->msg_id, &rx_pb_buf, timeout, req_hdr); if (ret) { continue; } rsp_hdr = (mp_rf_cal_msg_hdr_t *)rx_pb_buf; ret = rsp_hdr->option; if (ret) { rsp->err_no = ret; break; } ret = ERR_OK; meas_rsp = (mp_rf_cal_meas_rsp_t *)rsp_hdr->data; rsp->gain = meas_rsp->gain_x100; rsp->tone_pwr = meas_rsp->tone_pwr; rsp->dc_pwr = meas_rsp->dc_pwr; rsp->img_pwr = meas_rsp->img_pwr; os_mem_set(rsp->rsvd, 0x0, sizeof(rsp->rsvd)); break; } rsp->err_no = ret; time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), start_ntb); iot_printf("%s result:%lu, cons:%lums, lo_freq:%luHz, idx:[%d, %d, %d], " "power[%d, %d, %d], gain %lu\n", __FUNCTION__, ret, MAC_NTB_TO_MS(time_span), req->lo_freq, req->tone_idx, req->dc_idx, req->img_idx, rsp->tone_pwr, rsp->dc_pwr, rsp->img_pwr, rsp->gain); } static void mp_rf_common_timer_func(uint32_t id, void *arg) { (void)id; (void)arg; os_set_task_event_with_v(_init_handle, 1 << MP_RF_EVT_ID_TIMEROUT); } void mp_rf_ctxt_init(uint8_t is_golden, uint8_t option, uint8_t channel) { if (!g_mp_rf_ctxt) { g_mp_rf_ctxt = (mp_rf_ctxt_t*)os_mem_malloc(IOT_FTM_MID, sizeof(mp_rf_ctxt_t)); if (!g_mp_rf_ctxt) IOT_ASSERT(0); } if (is_golden) { rf_phy_power_meas_init(); g_mp_rf_ctxt->is_golden = 1; g_mp_rf_ctxt->target_option = option; g_mp_rf_ctxt->target_channel = channel; g_mp_rf_ctxt->common_timer = os_create_timer(IOT_FTM_MID, true, mp_rf_common_timer_func, NULL); mp_rf_cal_plc_comm_init(MP_RF_PLC_INIT_BAND); g_mp_rf_ctxt->led_gpio = iot_board_get_led(IOT_PLC_RX_LED); iot_gpio_open_as_output(g_mp_rf_ctxt->led_gpio); os_start_timer(g_mp_rf_ctxt->common_timer, MP_RF_GOLDEN_COMMON_TIMER_PERIOD); } } uint32_t mp_rf_dut_test_phy_cfg(uint8_t option, uint8_t channel) { if (!g_mp_rf_ctxt) { mp_rf_ctxt_init(0, 0, 0); } mp_rf_common_init(option, channel); return ERR_OK; } void mp_rf_dut_test_case_handle(iot_ftm_mp_rf_cmd_hdr_t *cmd, iot_ftm_mp_rf_rsp_hdr_t *rsp_hdr, uint8_t *len) { uint8_t ret, tmp = 0; *len = sizeof(*rsp_hdr); mp_rf_dut_test_phy_cfg(cmd->option, cmd->channel); mp_rf_cal_plc_comm_init(MP_RF_PLC_INIT_BAND); switch (cmd->id) { case IOT_FTM_MP_RF_CASE_ID_CSR: { ret = mp_rf_dut_test_case_csr(cmd, rsp_hdr->data); tmp = sizeof(iot_ftm_mp_rf_rsp_csr_t); break; } case IOT_FTM_MP_RF_CASE_ID_CSI: { ret = mp_rf_dut_test_case_csi(cmd, rsp_hdr->data); tmp = sizeof(iot_ftm_mp_rf_rsp_csi_t); break; } case IOT_FTM_MP_RF_CASE_ID_TX_EVM: { ret = mp_rf_dut_test_case_tx_evm(cmd, rsp_hdr->data); tmp = sizeof(iot_ftm_mp_rf_rsp_tx_evm_t); break; } case IOT_FTM_MP_RF_CASE_ID_CHG_PHY: { ret = mp_rf_dut_test_case_chg_phy(cmd, rsp_hdr->data); break; } case IOT_FTM_MP_RF_CASE_ID_TX_CALI_BY_SNR: { ret = mp_rf_dut_test_case_tx_cali(cmd, rsp_hdr->data, &tmp); break; } default: { ret = ERR_NOSUPP; break; } } rsp_hdr->id = cmd->id; rsp_hdr->result = ret; if (ret == ERR_OK) { *len += tmp; } if (g_mp_rf_ctxt->rf_phy_inited) { mac_rf_rx_ring_enable(&g_mp_rf_ctxt->rx_ring, 0); } } static uint8_t mp_rf_common_timer_handle() { uint8_t toggle_flag = 0; uint32_t time_span; if (g_mp_rf_ctxt->rf_phy_changing) { time_span = mp_rf_ntb_span_calc(RGF_MAC_READ_REG(CFG_RD_NTB_ADDR), g_mp_rf_ctxt->rf_phy_chg_ts); time_span = MAC_NTB_TO_MS(time_span); if (time_span >= MP_RF_TEST_CASE_CHG_PHY_EXEC_DELAY) { g_mp_rf_ctxt->rf_phy_changing = 0; return 1; } } g_mp_rf_ctxt->timeout_count++; /* blinking cycle 100ms */ if (g_mp_rf_ctxt->is_cal_mode) { toggle_flag = 1; } else { /* blinking cycle 500ms */ if (g_mp_rf_ctxt->timeout_count % 5 == 1) { toggle_flag = 1; } } if (toggle_flag) { iot_gpio_value_set(g_mp_rf_ctxt->led_gpio, (int)g_mp_rf_ctxt->led_status); g_mp_rf_ctxt->led_status = !g_mp_rf_ctxt->led_status; } return 0; } void mp_rf_golden_unit_main(uint32_t option, uint32_t channel) { uint8_t reinit_req; uint32_t events; mp_rf_ctxt_init(1, option, channel); /* set nid by gpio status */ glb_cfg.nid = mp_pt_golden_nid_config(); #if SUPPORT_SOUTHERN_POWER_GRID if (glb_cfg.nid > PLC_NID_MAX_SPG) glb_cfg.nid = PLC_NID_MAX_SPG; #endif if (iot_board_is_overseas_rf_band()) { phy_rf_band_info_init(PHY_RF_BAND_OVERSEAS); } else { phy_rf_band_info_init(PHY_RF_BAND_NSG); } iot_printf("Global nid has been set to %d.\n", glb_cfg.nid); reinit: mp_rf_common_init(g_mp_rf_ctxt->target_option, g_mp_rf_ctxt->target_channel); for (; ;) { events = os_wait_task_event_with_v(MAX_TIME); if (events & (1 << MP_RF_EVT_ID_PLC_RX)) { reinit_req = mp_rf_golden_plc_rx(); if (reinit_req) { goto reinit; } } if (events & (1 << MP_RF_EVT_ID_RF_RX)) { mp_rf_golden_rf_rx(); } if (events & (1 << MP_RF_EVT_ID_TIMEROUT)) { reinit_req = mp_rf_common_timer_handle(); if (reinit_req) { goto reinit; } } } } #else /* IOT_MP_SUPPORT == 1 && HPLC_RF_DEV_SUPPORT */ uint32_t mp_rf_dut_test_phy_cfg(uint8_t option, uint8_t channel) { (void)option; (void)channel; return ERR_FAIL; } void mp_rf_dut_test_case_handle(iot_ftm_mp_rf_cmd_hdr_t *cmd, iot_ftm_mp_rf_rsp_hdr_t *rsp_hdr, uint8_t *len) { (void)cmd; *len = sizeof(*rsp_hdr); rsp_hdr->result = ERR_NOSUPP; rsp_hdr->id = cmd->id; } void mp_rf_golden_unit_main(uint32_t option, uint32_t channel) { (void)option; (void)channel; } uint8_t mp_rf_dut_cal_cfg(iot_ftm_mp_rf_cal_meas_cfg_t *cfg) { (void)cfg; return ERR_NOSUPP; } void mp_rf_dut_cal_reg_update(iot_ftm_mp_rf_tx_cal_update_t *cal_update) { (void)cal_update; } void mp_rf_dut_cal_meas_pwr(iot_ftm_mp_rf_cal_meas_req_t *req, iot_ftm_mp_rf_cal_meas_rsp_t *rsp) { (void)req; (void)rsp; } void mp_rf_clear_rf_common() { } #endif