Files
kunlun/plc/halphy/phy_bbai_calu.c
2024-09-28 14:24:04 +08:00

1023 lines
35 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "iot_config.h"
#include "phy_bbai_calu.h"
#include "phy_dump.h"
#include "phy_bb.h"
#include "os_types.h"
#include "hw_reg_api.h"
#include "iot_io.h"
#include "mac_sys_reg.h"
#include "iot_errno_api.h"
#include "hw_tonemask.h"
#include "phy_ana.h"
#include "phy_bb.h"
#include "phy_dfe_reg.h"
#include "phy_data.h"
#include "hw_phy_api.h"
#include "phy_phase.h"
#include "math.h"
#include "phy_ana.h"
#include "math_log10.h"
#include "hw_phy_api.h"
#include "phy_dump_hw.h"
#include "phy_tools.h"
#include "phy_perf.h"
#include "phy_math_tb.h"
#if PHY_BBAI_ALGORITHM == PHY_BBAI_FIX_WINDOWS
#define PHY_CHN_EST_AI_SPUR_LEN 500
/* spur array */
typedef struct _iot_phy_spur{
/* notch filter enable */
uint8_t notch_filter_en_cnt;
/* PHY_BBAI_FIX_WINDOWS :color
* PHY_BBAI_SLIDE_WINDOWS: is max spur
*/
uint8_t color;
/* tone number */
uint16_t tone_id;
/* center/sidelobe */
uint32_t spur_ratio;
/* spur occur cnt */
uint16_t spur_cnt;
} iot_phy_spur_t;
static uint32_t phy_spur_arry_append(iot_phy_spur_t *spur_buf, uint32_t buf_len,
uint16_t tone_id, uint32_t pwr_ratio, bool_t notch_en)
{
uint32_t ret = ERR_OK;
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t i = 0;
bool_t tone_find_en = false;
uint32_t spur_buf_size = buf_len/sizeof(iot_phy_spur_t);
/* valid check */
IOT_ASSERT(spur_buf != NULL && buf_len > 0);
/*
* spur mask valid for inband only, notch filter for all.
*/
if (spur_buf[spur_buf_size - 1].tone_id != 0) {
/* check same tone_id */
for(i = 0; i < spur_buf_size; i++)
{
/* tone exist */
if (spur_buf[i].tone_id == tone_id) {
spur_buf[i].spur_cnt++;
spur_buf[i].spur_ratio = (spur_buf[i].spur_ratio > pwr_ratio) ?
spur_buf[i].spur_ratio :
pwr_ratio;
spur_buf[i].notch_filter_en_cnt += notch_en;
tone_find_en = true;
break;
}
}
/* if not exist */
if (tone_find_en != true) {
/* find the minimal spur */
uint32_t min_spur_idx = 0;
uint32_t min_spur_ratio = spur_buf[0].spur_ratio;
for (i = 0; i < spur_buf_size; i++) {
if (min_spur_ratio > spur_buf[i].spur_ratio) {
min_spur_ratio = spur_buf[i].spur_ratio;
min_spur_idx = i;
}
}
/* fill */
spur_buf[min_spur_idx].tone_id = tone_id;
spur_buf[min_spur_idx].spur_cnt = 1;
spur_buf[min_spur_idx].spur_ratio = pwr_ratio;
spur_buf[min_spur_idx].notch_filter_en_cnt = notch_en;
}
} else {
for(i = 0; i < spur_buf_size; i++)
{
/* tone exist */
if (spur_buf[i].tone_id == tone_id) {
spur_buf[i].spur_cnt++;
spur_buf[i].spur_ratio = (spur_buf[i].spur_ratio > pwr_ratio) ?
spur_buf[i].spur_ratio :
pwr_ratio;
spur_buf[i].notch_filter_en_cnt += notch_en;
break;
} else if (spur_buf[i].tone_id == 0) {
/* add new */
spur_buf[i].tone_id = tone_id;
spur_buf[i].spur_cnt++;
spur_buf[i].spur_ratio = pwr_ratio;
spur_buf[i].notch_filter_en_cnt += notch_en;
break;
}
}
}
#else
(void *)spur_buf;
(void)buf_len;
(void)tone_id;
(void)pwr_ratio;
(void)notch_en;
#endif
return ret;
}
static void phy_chn_spur_arry_peak_extract(iot_phy_spur_t *spur_buf,
uint32_t buf_len, uint32_t est_rty_cnt)
{
uint32_t i = 0;
uint16_t spur_idx = 2;
uint32_t spur_total_len = 0;
/* valid check */
IOT_ASSERT(spur_buf != NULL && buf_len > 0);
/* clr current cnt */
g_phy_ctxt.dep.phy_status.spur_array[1] = 0;
/* cal total spur len */
spur_total_len = buf_len/sizeof(iot_phy_spur_t);
/* init first color */
if(spur_buf[0].tone_id == 0) {
return;
} else {
spur_buf[0].color = 1;
}
/* color the neighbouring tone */
for(i = 1; i < spur_total_len; i++)
{
if(spur_buf[i].tone_id == 0) {
break;
}
if(spur_buf[i].tone_id == (spur_buf[i-1].tone_id + 1)) {
spur_buf[i].color = spur_buf[i-1].color;
} else {
spur_buf[i].color = spur_buf[i-1].color + 1;
}
}
/* find peak by loop */
for(i = 0; i < spur_total_len -1; i++)
{
if(spur_buf[i].tone_id == 0) {
break;
}
if(spur_buf[i].color == (spur_buf[i+1].color)){
if(spur_buf[i].spur_ratio <= spur_buf[i+1].spur_ratio) {
spur_buf[i].tone_id = 0;
} else {
spur_buf[i+1].tone_id = spur_buf[i].tone_id;
spur_buf[i+1].spur_cnt = spur_buf[i].spur_cnt;
spur_buf[i+1].spur_ratio = spur_buf[i].spur_ratio;
spur_buf[i+1].notch_filter_en_cnt = spur_buf[i].notch_filter_en_cnt;
spur_buf[i].tone_id = 0;
}
}
}
/* save peak */
for(i = 0; i < spur_total_len; i++)
{
if(spur_buf[i].spur_cnt > (est_rty_cnt >> 1) &&
spur_buf[i].tone_id != 0) {
/* spur total num */
g_phy_ctxt.dep.phy_status.spur_array[0] += 1;
/* spur current num */
g_phy_ctxt.dep.phy_status.spur_array[1] += 1;
/* spur id */
if(spur_idx < PHY_LOG_SPUR_MAX_CNT) {
g_phy_ctxt.dep.phy_status.spur_array[spur_idx++] =
(uint16_t)(spur_buf[i].tone_id);
}
}
}
}
static void phy_spur_high_pwr_handler(bool_t pulse_flag, uint16_t base_spur_id)
{
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint16_t notch_alpha = 0;
uint32_t band_id = phy_band_id_get();
/* find harmonic */
if ((pulse_flag == true) && (band_id == IOT_SUPPORT_TONE_100_230 ||
base_spur_id < PHY_SPUR_3M_DET_START)) {
/* dc block hp */
phy_dc_blk_alpha_step3_set(32);
iot_printf("dc blk alpha 32!\n");
if (band_id == IOT_SUPPORT_TONE_100_230) {
notch_alpha = phy_alpha_cal(123);
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
notch_alpha = phy_alpha_cal(164);
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
} else if (band_id == IOT_SUPPORT_TONE_32_120 ||
band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
notch_alpha = phy_alpha_cal(82);
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
notch_alpha = phy_alpha_cal(123);
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
}
} else {
/* if nf > 100 shutdown sw-agc */
if (g_phy_ctxt.dep.nf >= 100) {
/* 3M special */
if ((base_spur_id >= PHY_SPUR_3M_DET_START) &&
(base_spur_id <= PHY_SPUR_3M_DET_END)) {
/* shut dwon sw-agc */
phy_swagc_set(false);
g_phy_ctxt.indep.sw_agc_force_off = true;
/* dc block hp */
phy_dc_blk_alpha_step3_set(253);
} else if ((band_id == IOT_SUPPORT_TONE_100_230) &&
(base_spur_id >= PHY_SPUR_6M_DET_START) &&
(base_spur_id <= PHY_SPUR_6M_DET_END)) {
/* 6M pulse tgt pwr to 110 */
g_phy_cpu_share_ctxt.spur_exist = 0;
}
}
notch_alpha = phy_alpha_cal(base_spur_id);
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
}
phy_anf_sel_set(2);
phy_anf2_sel_set(2);
#else
(void)pulse_flag;
(void)base_spur_id;
#endif
}
static bool_t phy_pulse_check(iot_phy_spur_t *spur_buf,
uint32_t spur_total_len, uint16_t base_spur_id)
{
bool_t pulse_flag = false;
uint32_t harmonic_cnt = 0, harmonic1_cnt = 0, harmonic2_cnt = 0;
if (base_spur_id != 0) {
for(uint32_t i = 0; i < spur_total_len; i++)
{
/* find harmonic */
if ((spur_buf[i].tone_id / base_spur_id >= 1) &&
(spur_buf[i].tone_id % base_spur_id == 0)) {
harmonic_cnt++;
}
/* find harmonic1 -1 */
if ((spur_buf[i].tone_id / (base_spur_id - 1) >= 1) &&
(spur_buf[i].tone_id % (base_spur_id - 1) == 0)) {
harmonic1_cnt++;
}
/* find harmonic2 +1 */
if ((spur_buf[i].tone_id / (base_spur_id + 1) >= 1) &&
(spur_buf[i].tone_id % (base_spur_id + 1) == 0)) {
harmonic2_cnt++;
}
}
/* check pulse or spur */
if (harmonic_cnt >= PHY_PULSE_HARMONIC_THD ||
harmonic1_cnt >= PHY_PULSE_HARMONIC_THD ||
harmonic2_cnt >= PHY_PULSE_HARMONIC_THD) {
pulse_flag = true;
}
iot_printf("tone %d harmonic cnt:%d-%d-%d!\n",
base_spur_id, harmonic_cnt, harmonic1_cnt, harmonic2_cnt);
}
return pulse_flag;
}
static uint16_t phy_spur_arry_base_id_find(iot_phy_spur_t *spur_buf,
uint16_t max_spur_id)
{
uint32_t base_spur_id = 0;
if (max_spur_id != 0) {
for(uint32_t i = 0; i < max_spur_id; i++)
{
/* check */
if (max_spur_id%spur_buf[i].tone_id == 0 ||
(max_spur_id + 1)%spur_buf[i].tone_id == 0 ||
(max_spur_id - 1)%spur_buf[i].tone_id == 0) {
base_spur_id = spur_buf[i].tone_id;
break;
}
}
/* if not find */
if (base_spur_id == 0) {
base_spur_id = max_spur_id;
}
}
return (uint16_t)base_spur_id;
}
static uint32_t phy_spur_arry_peak_handler(iot_phy_spur_t *spur_buf,
uint32_t buf_len, uint32_t est_rty_cnt)
{
uint32_t ret = ERR_OK;
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t spur_total_len = 0;
uint32_t max_ratio = 0;
uint16_t max_spur_id = 0, base_spur_id = 0;
uint16_t notch_alpha = 0;
uint16_t inband_tone_mask_curr = 0;
uint16_t inband_tone_mask_total = 0;
uint32_t cmp_thd_cnt = est_rty_cnt >> 1;
bool_t pulse_flag = false, spur_flag = false, spur6m_flag = false;
uint32_t band_id = phy_band_id_get();
uint32_t end_tone;
if (g_phy_cpu_share_ctxt.pt_mode_entry == 1) {
return ERR_NOSUPP;
}
/* valid check */
IOT_ASSERT(spur_buf != NULL && buf_len > 0);
/* first fft pwr full for band narrow */
if (band_id == IOT_SUPPORT_TONE_32_120 ||
band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
cmp_thd_cnt = (cmp_thd_cnt > 0) ? (cmp_thd_cnt - 1) : 0;
}
/* cal total spur len */
spur_total_len = buf_len/sizeof(iot_phy_spur_t);
/* cal max mask tone number */
inband_tone_mask_total = all_mask_band_table_r0_full.valid_tone_number/3;
/* scan all spur */
for (uint32_t i = 0; i < spur_total_len; i++) {
if (spur_buf[i].tone_id != 0) {
iot_printf("[BB_AI] spur: %u, cnt: %u!\n",
spur_buf[i].tone_id, spur_buf[i].spur_cnt);
/* check cnt */
if (spur_buf[i].spur_cnt > cmp_thd_cnt) {
/* check inband max masked number */
if (
(spur_buf[i].tone_id >= all_mask_band_table_r0_full.start_tone &&
spur_buf[i].tone_id <= all_mask_band_table_r0_full.end_tone) ||
(spur_buf[i].tone_id >= all_mask_band_table_r1_full.start_tone &&
spur_buf[i].tone_id <= all_mask_band_table_r1_full.end_tone)) {
if (inband_tone_mask_curr < inband_tone_mask_total) {
inband_tone_mask_curr++;
/* mask spur */
phy_spur_mask_set(spur_buf[i].tone_id,0);
iot_printf("[BB_AI] spur tone: %u mask done!\n",
spur_buf[i].tone_id);
} else {
/* do nothing for other inband tone */
continue;
}
} else {
/* mask spur */
phy_spur_mask_set(spur_buf[i].tone_id,0);
iot_printf("[BB_AI] spur tone: %u mask done!\n",
spur_buf[i].tone_id);
}
/* notch filter set */
if (spur_buf[i].notch_filter_en_cnt > cmp_thd_cnt) {
/* find max spur */
if (!g_phy_ctxt.indep.notch_filter_en) {
g_phy_ctxt.indep.notch_filter_en = true;
max_ratio = spur_buf[i].spur_ratio;
max_spur_id = spur_buf[i].tone_id;
} else if(max_ratio < spur_buf[i].spur_ratio &&
spur_buf[i].tone_id < 512) {
/* compare max */
max_ratio = spur_buf[i].spur_ratio;
max_spur_id = spur_buf[i].tone_id;
}
}
#if PHY_BB_AI_WITH_PULSE_CHECK_EN
if (spur_buf[i].tone_id == IOT_SPUR_8M_CENTER_TONE) {
phy_anti_spur_set(IOT_SUPPORT_TONE_80_490);
} else if(spur_buf[i].tone_id == IOT_SPUR_3M_CENTER_TONE) {
phy_anti_spur_set(IOT_SUPPORT_TONE_100_230);
} else if(spur_buf[i].tone_id == IOT_SPUR_2M_CENTER_TONE) {
phy_anti_spur_set(IOT_SUPPORT_TONE_32_120);
}
#endif
/* maybe 6M not detect because of notch thd */
if ((band_id == IOT_SUPPORT_TONE_100_230 ||
band_id == IOT_SUPPORT_TONE_MULTI_BAND021) &&
spur_buf[i].tone_id >= PHY_SPUR_6M_DET_START &&
spur_buf[i].tone_id <= PHY_SPUR_6M_DET_END) {
spur6m_flag = true;
}
spur_flag = true;
}
}
}
/* not work for cert and other low pwr scenario */
if (phy_get_nf_of_bbai() >= PHY_CHN_HIGH_NOISE_NF_THD) {
/* find spur base id */
base_spur_id = phy_spur_arry_base_id_find(spur_buf, max_spur_id);
/* check pulse */
pulse_flag = phy_pulse_check(spur_buf, spur_total_len, base_spur_id);
/* diff noise and spur/pulse */
if (spur_flag) {
/* reduce warning */
if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
phy_rxfd_pkt_det_thd_set(32, 32);
} else {
phy_rxfd_pkt_det_thd_set(16, 32);
}
phy_band_tone_range_get(NULL, &end_tone);
if (end_tone <= 230) {
phy_ana_filter_set(63);
}
} else {
/* big nf, but not spur */
g_phy_ctxt.dep.big_nf_handle = 1;
if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
phy_rxfd_pkt_det_thd_set(32, 32);
} else {
/* more sensitive */
phy_rxfd_pkt_det_thd_set(8, 16);
}
/* dc block hp */
phy_dc_blk_alpha_step3_set(253);
/* clean notch filter */
phy_perf_common_init();
/* Must recover 8M high pass filter for att and noise
if not will worsen performance index */
phy_ana_filter_set(
(g_phy_ctxt.dep.band_8m_cap_set > 0) ?
g_phy_ctxt.dep.band_8m_cap_set : 36);
iot_printf("[BB_AI]spur flag:%d, bf 8M\n", spur_flag);
}
/* notch filter set */
if (max_ratio) {
g_phy_cpu_share_ctxt.spur_exist = 1;
/* spur handler */
phy_spur_high_pwr_handler(pulse_flag, base_spur_id);
} else if (spur6m_flag) {
/* tgt pwr to 110 */
g_phy_cpu_share_ctxt.spur_exist = 0;
/* 6M spur */
notch_alpha = phy_alpha_cal(246);
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
}
/* for kl1 */
#if !PHY_HW_SPIKE_OPTIMIZATION
if (band_id == IOT_SUPPORT_TONE_100_230) {
/* dc block hp */
phy_dc_blk_alpha_step3_set(32);
}
#endif
iot_printf("[BB_AI]ratio:%d, 6m:%d, max=%u, base=%u!\n",
max_ratio, spur6m_flag, max_spur_id, base_spur_id);
} else {
/* if big_nf_handle is true,
* indicates that nf has been recover,
* and recover threshold
*/
if (g_phy_ctxt.dep.big_nf_handle) {
g_phy_ctxt.dep.big_nf_handle = 0;
/* reduce warning */
if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
phy_rxfd_pkt_det_thd_set(32, 32);
} else {
phy_rxfd_pkt_det_thd_set(16, 32);
}
#if PHY_HW_SPIKE_OPTIMIZATION
if (IOT_SUPPORT_TONE_32_120 == band_id) {
phy_rxfd_pkt_det_thd_set(8, 16);
}
#endif
/* filter reset */
phy_ana_set_filter_init(band_id);
}
/* notch filter set */
if (max_ratio) {
g_phy_cpu_share_ctxt.spur_exist = 1;
notch_alpha = phy_alpha_cal(max_spur_id);
if (PHY_DFE_READ_REG(CFG_BB_ANF_1_ALPHA_BETA_ADDR) &
SW_ANF_OPTION1_MASK) {
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
} else {
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
}
phy_check_spur_cert_handle(notch_alpha);
iot_printf("[BB_AI] notch filter: %u enable!\n", max_spur_id);
}
}
/* find peak and output log */
phy_chn_spur_arry_peak_extract(spur_buf, buf_len, est_rty_cnt);
#else
(void *)spur_buf;
(void)buf_len;
(void)est_rty_cnt;
#endif
return ret;
}
static uint32_t phy_chn_est_data_process(uint32_t *csi_buf,
iot_phy_spur_t *spur_buf, int8_t *current_gain, uint8_t pkt_idx)
{
uint32_t ret = ERR_OK;
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t j = 0;
int16_t csi_i = 0, csi_q = 0;
uint32_t center_pwr = 0;
uint32_t sidelobe_pwr = 0;
uint32_t dump_valid_cnt = 0;
uint64_t inband_pwr = 0;
uint64_t outband_pwr = 0;
uint32_t tone_idx = 0;
bool_t full_flag = false;
uint8_t pwr_ratio = 0;
uint32_t bbai_nf = phy_get_nf_of_bbai();
bool_t is_w_size_6 = false;
uint32_t ext_pwr = 0;
#if PHY_DEBUG_EN
/* cal csi for every tone for debug*/
for (tone_idx = 0; tone_idx < (IOT_PHY_CSI_BUF_LEN >> 2); tone_idx++) {
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
iot_printf("tone:%u, csi_i:%d, csi_q:%d, dB:%u\n",
tone_idx + pkt_idx * 512,
csi_i,
csi_q,
(uint32_t)(10 * mlog10(csi_i * csi_i + csi_q * csi_q + 1)));
}
#endif
/* cal outband total pwr */
outband_pwr = 0;
for (j = 1; j < PHY_CHN_VALID_TONE_NUM + 1; j++) {
csi_i = (int16_t)(*(csi_buf +
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone - j) & 0xFFFF);
csi_q = (int16_t)(*(csi_buf +
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone - j) >> 16);
outband_pwr += csi_i * csi_i + csi_q * csi_q;
}
/* cal outband average pwr */
outband_pwr = outband_pwr/PHY_CHN_VALID_TONE_NUM;
/* check outband pwr */
if (!outband_pwr) {
return ERR_FAIL;
}
/* cal inband pwr */
for (j = 0; j < PHY_CHN_VALID_TONE_NUM; j++) {
csi_i = (int16_t)(*(csi_buf +
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone + j) & 0xFFFF);
csi_q = (int16_t)(*(csi_buf +
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone + j) >> 16);
inband_pwr = csi_i * csi_i + csi_q * csi_q;
/* pkt feature: inband > outband 10dB */
if (10 * mlog10(inband_pwr/outband_pwr) < PHY_FD_PKT_CHECK_THD) {
dump_valid_cnt += 1;
}
}
/* check valid dump */
if (dump_valid_cnt < (PHY_CHN_VALID_TONE_NUM >> 1)) {
#if PHY_DEBUG_EN
iot_printf("[BB_AI] find pkt, valid cnt:%u\n", dump_valid_cnt);
#endif
return ERR_FAIL;
}
/* spur check: scan band 0-511 with special point */
for (j = PHY_CHN_EST_AI_SIDELOBE_NUM + 1;
j < (IOT_PHY_CSI_BUF_LEN >> 2) - PHY_CHN_EST_AI_SIDELOBE_NUM; j++) {
/* zero pwr */
center_pwr = 0;
sidelobe_pwr = 0;
ext_pwr = 0;
/* spur find loop */
for (tone_idx = j - PHY_CHN_EST_AI_SIDELOBE_NUM;
tone_idx <= j + PHY_CHN_EST_AI_SIDELOBE_NUM; tone_idx++) {
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
/* check full */
if ((csi_i > PHY_CHN_EST_AI_FULL_PWR ||
csi_i < -PHY_CHN_EST_AI_FULL_PWR) &&
(csi_q > PHY_CHN_EST_AI_FULL_PWR ||
csi_q < -PHY_CHN_EST_AI_FULL_PWR)) {
/* if current gain is not least gain,
* decrease gain and discard this data.
* else use this data.
*/
if (*current_gain != -PHY_AGC_GAIN_ENTRY_OFFSET) {
full_flag = true;
break;
}
} else {
if (tone_idx >= (j - PHY_CHN_EST_AI_W_SIZE_4) &&
tone_idx <= (j + PHY_CHN_EST_AI_W_SIZE_4)) {
center_pwr += csi_i * csi_i + csi_q * csi_q;
} else {
sidelobe_pwr += csi_i * csi_i + csi_q * csi_q;
}
if (tone_idx == j - PHY_CHN_EST_AI_W_SIZE_6 ||
tone_idx == j + PHY_CHN_EST_AI_W_SIZE_6 ) {
ext_pwr += csi_i * csi_i + csi_q * csi_q;
}
}
}
if (full_flag) {
/* reint full flag */
full_flag = false;
uint8_t gain_step = ((bbai_nf > PHY_CHN_EST_AI_SPUR_NF_THD) ?
(PHY_CHN_EST_AI_GAIN_STEP << 1) : (PHY_CHN_EST_AI_GAIN_STEP));
/* decrease gain */
if ((*current_gain - gain_step + PHY_AGC_GAIN_ENTRY_OFFSET) > 0) {
*current_gain -= (int8_t)gain_step;
} else {
*current_gain = -PHY_AGC_GAIN_ENTRY_OFFSET;
}
iot_printf("[BB_AI] pwr full, decrease gain to:%d\n", *current_gain);
return ERR_FAIL;
} else {
is_w_size_6 = false;
windows:
/* check sidelobe_pwr */
if (!sidelobe_pwr) {
continue;
}
/* cal pwr ratio*/
pwr_ratio = center_pwr/sidelobe_pwr;
bool_t judge_spur_flag;
if ((center_pwr > PHY_CHN_EST_AI_SUPR_PWR_THD) &&
(bbai_nf > PHY_CHN_EST_AI_SPUR_NF_THD)) {
/* power > 24000000 and nf > 100 */
judge_spur_flag = true;
} else {
judge_spur_flag = (pwr_ratio > PHY_CHN_EST_AI_SPUR_THD);
}
if (judge_spur_flag) {
#if PHY_DEBUG_EN
iot_printf("[BB_AI] tone:%u, center_pwr:%u, ext_pwr:%u\n",
j + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2),
center_pwr, sidelobe_pwr);
#endif
/* notch filter thd check */
bool_t judge_notch_flag;
if ((center_pwr > PHY_CHN_EST_AI_SUPR_PWR_THD) &&
(bbai_nf > PHY_CHN_EST_AI_SPUR_NF_THD)) {
/* power > 24000000 and nf > 100 */
judge_notch_flag = true;
} else {
judge_notch_flag =
(pwr_ratio > PHY_CHN_EST_AI_SPUR_NOTCH_THD);
}
if (judge_notch_flag) {
/* append to spur array with notch filter */
phy_spur_arry_append(spur_buf,
PHY_CHN_EST_AI_SPUR_LEN,
j + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2),
center_pwr >> 5, true);
} else {
/* append to spur array without notch filter */
phy_spur_arry_append(spur_buf,
PHY_CHN_EST_AI_SPUR_LEN,
j + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2),
center_pwr >> 5, false);
}
} else {
/* if find spur fail, adjust main windows form 4 to 6 */
if (is_w_size_6 == false) {
is_w_size_6 = true;
center_pwr += ext_pwr;
sidelobe_pwr -= ext_pwr;
goto windows;
}
}
}
}
#else
(void)csi_buf;
(void)spur_buf;
(void)current_gain;
(void)pkt_idx;
#endif
return ret;
}
static void phy_chn_est_sidelobe_process(uint32_t *csi_buf,
iot_phy_spur_t *spur_buf, int8_t *current_gain, uint8_t pkt_idx)
{
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t j = 0;
int16_t csi_i = 0, csi_q = 0;
uint32_t center_pwr = 0;
uint32_t sidelobe_pwr = 0;
uint32_t tone_idx = 0;
bool_t full_flag = false;
#if PHY_DEBUG_EN
for (tone_idx = 0; tone_idx <= (PHY_CHN_EST_AI_SIDELOBE_NUM << 2);
tone_idx++) {
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
iot_printf("tone:%u, csi_i:%d, csi_q:%d, dB:%u\n",
tone_idx + pkt_idx * 512 - (PHY_CHN_EST_AI_SIDELOBE_NUM << 1),
csi_i, csi_q,
(uint32_t)(10 * mlog10(csi_i * csi_i + csi_q * csi_q + 1)));
}
#endif
/* spur check: scan band 0-24 with special point */
for (j = PHY_CHN_EST_AI_SIDELOBE_NUM;
j <= (PHY_CHN_EST_AI_SIDELOBE_NUM << 2) - PHY_CHN_EST_AI_SIDELOBE_NUM;
j++) {
/* zero pwr */
center_pwr = 0;
sidelobe_pwr = 0;
/* spur find loop */
for (tone_idx = j - PHY_CHN_EST_AI_SIDELOBE_NUM;
tone_idx <= j + PHY_CHN_EST_AI_SIDELOBE_NUM; tone_idx++) {
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
/* check full */
if((csi_i == PHY_CHN_EST_AI_FULL_PWR ||
csi_i == -PHY_CHN_EST_AI_FULL_PWR) &&
(csi_q == PHY_CHN_EST_AI_FULL_PWR ||
csi_q == -PHY_CHN_EST_AI_FULL_PWR)) {
full_flag = true;
break;
} else {
if(tone_idx >= (j - 2) && tone_idx <= (j + 2)) {
center_pwr += csi_i * csi_i + csi_q * csi_q;
} else {
sidelobe_pwr += csi_i * csi_i + csi_q * csi_q;
}
}
}
if(full_flag) {
/* reint full flag */
full_flag = false;
/* decrease gain */
*current_gain -= (int8_t)PHY_CHN_EST_AI_GAIN_STEP;
iot_printf("[BB_AI] pwr full, decrease gain to:%d\n", *current_gain);
break;
} else {
/* check sidelobe_pwr */
if(!sidelobe_pwr) {
continue;
}
if(center_pwr/sidelobe_pwr > PHY_CHN_EST_AI_SPUR_THD) {
#if PHY_DEBUG_EN
iot_printf("[BB_AI] tone:%u, center_pwr:%u, ext_pwr:%u\n",
j + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2) -
(PHY_CHN_EST_AI_SIDELOBE_NUM << 1),
center_pwr, sidelobe_pwr);
#endif
/* notch filter thd check */
if(center_pwr/sidelobe_pwr > PHY_CHN_EST_AI_SPUR_NOTCH_THD) {
/* append to spur array with notch filter */
phy_spur_arry_append(spur_buf,
PHY_CHN_EST_AI_SPUR_LEN,
j + pkt_idx * ((IOT_PHY_CSI_BUF_LEN >> 2) -
(PHY_CHN_EST_AI_SIDELOBE_NUM << 1)),
10 * mlog10(center_pwr/sidelobe_pwr), true);
} else {
/* append to spur array without notch filter */
phy_spur_arry_append(spur_buf,
PHY_CHN_EST_AI_SPUR_LEN,
j + pkt_idx * ((IOT_PHY_CSI_BUF_LEN >> 2) -
(PHY_CHN_EST_AI_SIDELOBE_NUM << 1)),
10 * mlog10(center_pwr/sidelobe_pwr), false);
}
}
}
}
#else
(void)csi_buf;
(void)spur_buf;
(void)current_gain;
(void)pkt_idx;
#endif
}
uint32_t phy_chn_est_ai(int8_t current_gain, uint32_t est_rty_cnt,
uint32_t timeout_ms)
{
uint32_t success_cnt = 0;
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t i = 0;
uint32_t ret = ERR_OK;
uint32_t start_time = 0, end_time = 0;
int64_t time_span = 0;
iot_pkt_t *pkt_buf = NULL;
iot_pkt_t *hash_buf = NULL;
uint32_t *csi_buf = NULL;
iot_phy_spur_t *spur_buf = NULL;
uint32_t *sidelobe_buf = NULL;
uint8_t pkt_idx = 0;
/* check dump busy flag */
if (phy_busy_get(&g_phy_ctxt, PHY_BUSY_DUMP)) {
iot_printf("phy dump busy!\n");
return ERR_BUSY;
} else {
phy_dump_busy_set(true);
}
/* get start time */
start_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
/* get mem from iot_pkt to save csi data */
IOT_PKT_GET(pkt_buf, IOT_PHY_CSI_BUF_LEN, 0, PLC_PHY_COMMON_MID);
if(!pkt_buf){
iot_printf("phy chn est fatal error, iot_pkt_get fail\n");
phy_dump_busy_set(false);
return success_cnt;
}
csi_buf = (uint32_t *)iot_pkt_put(pkt_buf, IOT_PHY_CSI_BUF_LEN);
/* get mem from iot_pkt to save spur data and sidelobe */
IOT_PKT_GET(hash_buf,
PHY_CHN_EST_AI_SPUR_LEN + (PHY_CHN_EST_AI_SIDELOBE_NUM << 4) + 4,
0,
PLC_PHY_COMMON_MID);
if(!hash_buf){
iot_printf("phy chn est spur fatal error, iot_pkt_get fail\n");
/* free iot pkt */
iot_pkt_free(pkt_buf);
phy_dump_busy_set(false);
return success_cnt;
}
spur_buf = (iot_phy_spur_t *)iot_pkt_put(hash_buf, PHY_CHN_EST_AI_SPUR_LEN);
sidelobe_buf = (uint32_t *)spur_buf + (PHY_CHN_EST_AI_SPUR_LEN >> 2);
#if PHY_HW_SPIKE_OPTIMIZATION
/* NOTE: KL2/3 can not use max gain, need get average gain */
current_gain = phy_gain_get_from_agc();
if (current_gain > PHY_BBAI_GAIN_MAX) {
current_gain = PHY_BBAI_GAIN_MAX;
}
#endif
/* check csi buf pointer valid and flag */
if(csi_buf != NULL)
{
/* rst to trig enable */
phy_reset(PHY_RST_REASON_WARM);
/* get valid fft dump */
for(i = 0; i < est_rty_cnt; i++)
{
for(pkt_idx = 0; pkt_idx < FFT_DUMP_PKT_MAX; pkt_idx++) {
/* trig fft to dump */
ret = phy_rx_fft_dump(csi_buf, current_gain, pkt_idx, FFT_DUMP_PKT_MAX);
if (ret != ERR_OK) {
/* clr dump and close current dump */
phy_rx_fft_dump(csi_buf, current_gain,
FFT_DUMP_PKT_MAX - 1, FFT_DUMP_PKT_MAX);
break;
}
/* data process */
ret = phy_chn_est_data_process(
csi_buf, spur_buf, &current_gain, pkt_idx);
if(ret != ERR_OK) {
/* clr dump and close current dump */
phy_rx_fft_dump(csi_buf, current_gain,
FFT_DUMP_PKT_MAX - 1, FFT_DUMP_PKT_MAX);
break;
}
/* sidelobe data like 512-6~512+6 */
if(pkt_idx > 0) {
/* copy current pkt sidelobe */
os_mem_cpy(sidelobe_buf + (PHY_CHN_EST_AI_SIDELOBE_NUM << 1),
csi_buf,
(PHY_CHN_EST_AI_SIDELOBE_NUM << 3) + 4);
/* sidelobe data process */
phy_chn_est_sidelobe_process(
sidelobe_buf, spur_buf, &current_gain, pkt_idx);
}
/* save last pkt sidelobe */
os_mem_cpy(sidelobe_buf,
csi_buf + (IOT_PHY_CSI_BUF_LEN >> 2)
- (PHY_CHN_EST_AI_SIDELOBE_NUM << 1),
PHY_CHN_EST_AI_SIDELOBE_NUM << 3);
}
/* record successful dump cnt */
if (ret == ERR_OK) {
success_cnt++;
}
/* check timeout */
end_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
/* cal span time */
time_span = end_time - start_time;
if (time_span < 0) { // wrap around
time_span = (0x100000000LL) - start_time + end_time;
}
/* break if timeout */
if (time_span >= timeout_ms * NTB_TICKS_PER_MS) {
break;
}
}
#if PHY_DEBUG_EN
uint32_t spur_buf_size1 = PHY_CHN_EST_AI_SPUR_LEN/sizeof(iot_phy_spur_t);
for (i = 0; i < spur_buf_size1; i++) {
iot_printf("B tone:%d, spur_cnt:%d, ratio:%d, notch_cnt:%d\n",
spur_buf[i].tone_id, spur_buf[i].spur_cnt,
spur_buf[i].spur_ratio, spur_buf[i].notch_filter_en_cnt);
}
#endif
/* get peak point */
phy_spur_arry_peak_handler(spur_buf, PHY_CHN_EST_AI_SPUR_LEN, est_rty_cnt);
}
else{
iot_printf("csi buf pointer get fail from iot_pkt!\n");
}
/* free iot pkt */
iot_pkt_free(pkt_buf);
iot_pkt_free(hash_buf);
/* get end time */
end_time = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
/* cal span time */
time_span = end_time - start_time;
if (time_span < 0) { // wrap around
time_span = (0x100000000LL) - start_time + end_time;
}
/* clear dump flag */
phy_dump_busy_set(false);
/* for kl3 */
phy_increase_tgt_pwr(g_phy_cpu_share_ctxt.spur_exist);
iot_printf("start_time:%u, end time:%u, bbai success cnt:%d\n",
start_time, end_time, success_cnt);
#else
(void)est_rty_cnt;
(void)timeout_ms;
#endif
return success_cnt;
}
#endif /* PHY_BBAI_ALGORITHM == PHY_BBAI_FIX_WINDOWS */