801 lines
28 KiB
C
801 lines
28 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_SLIDE_WINDOWS
|
||
|
|
||
|
#define PHY_CHN_EST_AI_SPUR_LEN (684)
|
||
|
|
||
|
/* 0: not care;
|
||
|
* 1: closer to the left;
|
||
|
* 2: closer to the right;
|
||
|
*/
|
||
|
typedef enum{
|
||
|
POSITION_NOT_CARE = 0,
|
||
|
POSITION_CLOSER_LEFT = 1,
|
||
|
POSITION_CLOSER_RIGHT = 2,
|
||
|
}POSITION_INFO;
|
||
|
|
||
|
/* 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;
|
||
|
uint8_t position_left_cnt;
|
||
|
uint8_t position_right_cnt;
|
||
|
} iot_phy_spur_t;
|
||
|
|
||
|
static uint32_t phy_spur_arry_peak_handler(
|
||
|
iot_phy_spur_t *spur_buf, uint32_t buf_len, uint32_t est_rty_cnt)
|
||
|
{
|
||
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
||
|
#define MAX_PLUSE_LEN 400
|
||
|
uint32_t spur_total_len = 0;
|
||
|
uint32_t max_ratio = 0, sec_ratio = 0;
|
||
|
uint16_t max_spur_id = 0, notch_alpha = 0, sec_spur_id = 0;
|
||
|
/* max spur left or right. secend spur left right */
|
||
|
uint8_t max_spur_lr = POSITION_NOT_CARE, sec_spur_lr = POSITION_NOT_CARE;
|
||
|
uint16_t max_spur_lr_id = 0, sec_spur_lr_id = 0;
|
||
|
uint16_t inband_tone_mask_curr = 0, inband_tone_mask_total = 0;
|
||
|
uint32_t cmp_thd_cnt = est_rty_cnt >> 1;
|
||
|
uint32_t band_id = phy_band_id_get();
|
||
|
uint32_t pluse_idx = 0, pluse_max_idx = 0, pluse_max_vle = 0;
|
||
|
uint32_t spur_vld_cnt = 0, last_tone = 0;
|
||
|
iot_pkt_t *pluse_pkt = NULL;
|
||
|
uint16_t *pluse_buf = NULL;
|
||
|
|
||
|
if (g_phy_cpu_share_ctxt.pt_mode_entry == 1) {
|
||
|
return ERR_NOSUPP;
|
||
|
}
|
||
|
|
||
|
/* get mem from iot_pkt to save pluse data */
|
||
|
IOT_PKT_GET(pluse_pkt, MAX_PLUSE_LEN, 0, PLC_PHY_COMMON_MID);
|
||
|
if (!pluse_pkt) {
|
||
|
iot_printf("phy peak hdl, get pluse pkt fail\n");
|
||
|
return ERR_FAIL;
|
||
|
}
|
||
|
pluse_buf = (uint16_t *)iot_pkt_put(pluse_pkt, MAX_PLUSE_LEN);
|
||
|
|
||
|
/* 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 */
|
||
|
/* multiband special config */
|
||
|
if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
|
||
|
inband_tone_mask_total = 5;
|
||
|
} else {
|
||
|
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, ismax:%d, lcnt:%d, rcnt:%d\n",
|
||
|
spur_buf[i].tone_id, spur_buf[i].spur_cnt, spur_buf[i].color,
|
||
|
spur_buf[i].position_left_cnt,
|
||
|
spur_buf[i].position_right_cnt);
|
||
|
|
||
|
/* check spike */
|
||
|
if (spur_buf[i].spur_cnt > cmp_thd_cnt) {
|
||
|
/* just check max */
|
||
|
if (spur_buf[i].color == 1) {
|
||
|
spur_vld_cnt++;
|
||
|
if (spur_vld_cnt == 1) {
|
||
|
last_tone = spur_buf[i].tone_id;
|
||
|
} else {
|
||
|
if (spur_buf[i].tone_id > last_tone) {
|
||
|
pluse_idx = spur_buf[i].tone_id - last_tone;
|
||
|
} else {
|
||
|
pluse_idx = last_tone - spur_buf[i].tone_id;
|
||
|
}
|
||
|
last_tone = spur_buf[i].tone_id;
|
||
|
|
||
|
/* only care about the peak length of MAX_PLUSE_LEN */
|
||
|
if (pluse_idx < (MAX_PLUSE_LEN >> 1)) {
|
||
|
pluse_buf[pluse_idx]++;
|
||
|
if (spur_vld_cnt == 2) {
|
||
|
pluse_max_idx = pluse_idx;
|
||
|
pluse_max_vle = pluse_buf[pluse_idx];
|
||
|
} else {
|
||
|
if (pluse_buf[pluse_idx] > pluse_max_vle) {
|
||
|
pluse_max_vle = pluse_buf[pluse_idx];
|
||
|
pluse_max_idx = pluse_idx;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* 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;
|
||
|
if (spur_buf[i].position_left_cnt >
|
||
|
spur_buf[i].position_right_cnt) {
|
||
|
max_spur_lr = POSITION_CLOSER_LEFT;
|
||
|
} else if (spur_buf[i].position_right_cnt >
|
||
|
spur_buf[i].position_left_cnt) {
|
||
|
max_spur_lr = POSITION_CLOSER_RIGHT;
|
||
|
}
|
||
|
sec_ratio = 0;
|
||
|
sec_spur_id = 0;
|
||
|
} else if (max_ratio < spur_buf[i].spur_ratio &&
|
||
|
spur_buf[i].tone_id < 512 &&
|
||
|
spur_buf[i].color) {
|
||
|
/* record second largest */
|
||
|
if (sec_spur_id != max_spur_id &&
|
||
|
spur_buf[i].color) {
|
||
|
sec_ratio = max_ratio;
|
||
|
sec_spur_id = max_spur_id;
|
||
|
sec_spur_lr = max_spur_lr;
|
||
|
}
|
||
|
/* record max */
|
||
|
max_ratio = spur_buf[i].spur_ratio;
|
||
|
max_spur_id = spur_buf[i].tone_id;
|
||
|
if (spur_buf[i].position_left_cnt >
|
||
|
spur_buf[i].position_right_cnt) {
|
||
|
max_spur_lr = POSITION_CLOSER_LEFT;
|
||
|
} else if (spur_buf[i].position_right_cnt >
|
||
|
spur_buf[i].position_left_cnt) {
|
||
|
max_spur_lr = POSITION_CLOSER_RIGHT;
|
||
|
}
|
||
|
} else if (sec_ratio < spur_buf[i].spur_ratio &&
|
||
|
spur_buf[i].tone_id < 512 && spur_buf[i].color) {
|
||
|
/* record second largest */
|
||
|
if (sec_spur_id != spur_buf[i].tone_id &&
|
||
|
spur_buf[i].color) {
|
||
|
sec_ratio = spur_buf[i].spur_ratio;
|
||
|
sec_spur_id = spur_buf[i].tone_id;
|
||
|
if (spur_buf[i].position_left_cnt >
|
||
|
spur_buf[i].position_right_cnt) {
|
||
|
sec_spur_lr = POSITION_CLOSER_LEFT;
|
||
|
} else if (spur_buf[i].position_right_cnt >
|
||
|
spur_buf[i].position_left_cnt) {
|
||
|
sec_spur_lr = POSITION_CLOSER_RIGHT;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* multiband special config */
|
||
|
if (band_id == IOT_SUPPORT_TONE_MULTI_BAND021) {
|
||
|
if ((max_spur_id >= all_mask_band_table_r0_full.start_tone &&
|
||
|
max_spur_id <= all_mask_band_table_r0_full.end_tone) ||
|
||
|
(sec_spur_id >= all_mask_band_table_r0_full.start_tone &&
|
||
|
sec_spur_id <= all_mask_band_table_r0_full.end_tone)) {
|
||
|
|
||
|
iot_printf("clear inband tonemask on multiband\n");
|
||
|
|
||
|
/* clear to avoid mask over for time-varying spur */
|
||
|
phy_tone_mask_amp_phase_tab_load(&all_mask_amp_phase_table,
|
||
|
phy_mask_id_get(), PHY_PROTO_TYPE_GET());
|
||
|
|
||
|
if (max_spur_id >= all_mask_band_table_r0_full.start_tone &&
|
||
|
max_spur_id <= all_mask_band_table_r0_full.end_tone) {
|
||
|
phy_spur_mask_set(max_spur_id, 2);
|
||
|
iot_printf("[BB_AI] spur tone: %u mask done!\n",
|
||
|
max_spur_id);
|
||
|
} else {
|
||
|
phy_spur_mask_set(sec_spur_id, 2);
|
||
|
iot_printf("[BB_AI] spur tone: %u mask done!\n",
|
||
|
sec_spur_id);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* sw calcualte pluse */
|
||
|
if (spur_vld_cnt > 10) {
|
||
|
uint32_t pluse_cnt = pluse_buf[pluse_max_idx] +
|
||
|
pluse_buf[pluse_max_idx - 1] + pluse_buf[pluse_max_idx + 1];
|
||
|
/* more than 1/2 the pulse is considered present */
|
||
|
if (pluse_cnt > spur_vld_cnt * 0.5) {
|
||
|
g_phy_cpu_share_ctxt.spike_exist = 1;
|
||
|
g_phy_cpu_share_ctxt.spike_value = pluse_max_idx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
iot_printf("pluse exist:%d, pluse tone %d, vldcnt:%lu cnt-1:%lu, "
|
||
|
"cnt:%lu, cnt+1:%lu, maxspur:%d, lr:%d, secspur:%d, lr:%d\n",
|
||
|
g_phy_cpu_share_ctxt.spike_exist, pluse_max_idx, spur_vld_cnt,
|
||
|
pluse_buf[pluse_max_idx - 1], pluse_buf[pluse_max_idx],
|
||
|
pluse_buf[pluse_max_idx + 1], max_spur_id, max_spur_lr,
|
||
|
sec_spur_id, sec_spur_lr);
|
||
|
|
||
|
/* notch filter config */
|
||
|
if (max_ratio) {
|
||
|
g_phy_cpu_share_ctxt.spur_exist = 1;
|
||
|
|
||
|
notch_alpha = phy_alpha_cal(max_spur_id);
|
||
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 1, notch_alpha);
|
||
|
if (max_spur_lr == POSITION_CLOSER_LEFT) {
|
||
|
if (max_spur_id) {
|
||
|
max_spur_lr_id = max_spur_id - 1;
|
||
|
}
|
||
|
notch_alpha = phy_alpha_cal(max_spur_lr_id);
|
||
|
} else if (max_spur_lr == POSITION_CLOSER_RIGHT) {
|
||
|
max_spur_lr_id = max_spur_id + 1;
|
||
|
notch_alpha = phy_alpha_cal(max_spur_lr_id);
|
||
|
}
|
||
|
phy_fnf_option_set(PHY_FNF_MODE_FIX, 1, notch_alpha);
|
||
|
|
||
|
notch_alpha = phy_alpha_cal(sec_spur_id);
|
||
|
phy_anf_option_set(PHY_ANF_MODE_FIX, 1, 2, notch_alpha);
|
||
|
if (sec_spur_lr == POSITION_CLOSER_LEFT) {
|
||
|
if (sec_spur_id) {
|
||
|
sec_spur_lr_id = sec_spur_id - 1;
|
||
|
}
|
||
|
notch_alpha = phy_alpha_cal(sec_spur_lr_id);
|
||
|
} else if (sec_spur_lr == POSITION_CLOSER_RIGHT) {
|
||
|
sec_spur_lr_id = sec_spur_id + 1;
|
||
|
notch_alpha = phy_alpha_cal(sec_spur_lr_id);
|
||
|
}
|
||
|
phy_fnf_option_set(PHY_FNF_MODE_FIX, 2, notch_alpha);
|
||
|
|
||
|
/* for jilin spur cert test */
|
||
|
extern void mac_cert_test_tt_special(uint32_t tone_id);
|
||
|
mac_cert_test_tt_special(max_spur_id);
|
||
|
phy_check_spur_cert_handle(notch_alpha);
|
||
|
iot_printf("[BB_AI] notch filter max:%d - %d, sec: %d - %d enable!\n",
|
||
|
max_spur_id, max_spur_lr_id, sec_spur_id, sec_spur_lr_id);
|
||
|
}
|
||
|
|
||
|
iot_pkt_free(pluse_pkt);
|
||
|
#else
|
||
|
(void *)spur_buf;
|
||
|
(void)buf_len;
|
||
|
(void)est_rty_cnt;
|
||
|
#endif
|
||
|
|
||
|
return ERR_OK;
|
||
|
}
|
||
|
|
||
|
static uint32_t phy_spur_arry_append(iot_phy_spur_t *spur_buf,
|
||
|
uint32_t buf_len, uint16_t tone_id, uint8_t pwr_ratio,
|
||
|
bool_t notch_en, uint32_t is_max, uint8_t left_right)
|
||
|
{
|
||
|
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;
|
||
|
spur_buf[i].color = is_max;
|
||
|
if (left_right == POSITION_CLOSER_LEFT) {
|
||
|
spur_buf[i].position_left_cnt++;
|
||
|
} else if (left_right == POSITION_CLOSER_RIGHT) {
|
||
|
spur_buf[i].position_right_cnt++;
|
||
|
}
|
||
|
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;
|
||
|
spur_buf[min_spur_idx].color = is_max;
|
||
|
|
||
|
if (left_right == POSITION_CLOSER_LEFT) {
|
||
|
spur_buf[min_spur_idx].position_left_cnt = 1;
|
||
|
spur_buf[min_spur_idx].position_right_cnt = 0;
|
||
|
} else if (left_right == POSITION_CLOSER_RIGHT) {
|
||
|
spur_buf[min_spur_idx].position_left_cnt = 0;
|
||
|
spur_buf[min_spur_idx].position_right_cnt = 1;
|
||
|
} else {
|
||
|
spur_buf[min_spur_idx].position_left_cnt = 0;
|
||
|
spur_buf[min_spur_idx].position_right_cnt = 0;
|
||
|
}
|
||
|
}
|
||
|
} 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;
|
||
|
spur_buf[i].color = is_max;
|
||
|
|
||
|
if (left_right == POSITION_CLOSER_LEFT) {
|
||
|
spur_buf[i].position_left_cnt++;
|
||
|
} else if (left_right == POSITION_CLOSER_RIGHT) {
|
||
|
spur_buf[i].position_right_cnt++;
|
||
|
}
|
||
|
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;
|
||
|
spur_buf[i].color = is_max;
|
||
|
|
||
|
if (left_right == POSITION_CLOSER_LEFT) {
|
||
|
spur_buf[i].position_left_cnt++;
|
||
|
} else if (left_right == POSITION_CLOSER_RIGHT) {
|
||
|
spur_buf[i].position_right_cnt++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
(void *)spur_buf;
|
||
|
(void)buf_len;
|
||
|
(void)tone_id;
|
||
|
(void)pwr_ratio;
|
||
|
(void)notch_en;
|
||
|
#endif
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static uint32_t phy_chn_est_dmpd_process(uint8_t *pwr_buf, uint32_t *csi_buf,
|
||
|
uint16_t *detect_buf, iot_phy_spur_t *spur_buf, int8_t *current_gain,
|
||
|
uint8_t pkt_idx)
|
||
|
{
|
||
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
||
|
uint32_t i = 0, j = 0, zone;
|
||
|
int16_t csi_i = 0, csi_q = 0;
|
||
|
uint32_t dump_valid_cnt = 0;
|
||
|
uint64_t inband_pwr = 0;
|
||
|
uint64_t outband_pwr = 0;
|
||
|
uint32_t tone_idx = 0;
|
||
|
uint32_t max_idx = 0;
|
||
|
int32_t max_value = 0;
|
||
|
int32_t row_sum = 0;
|
||
|
uint32_t window_length;
|
||
|
bool_t full_flag = false;
|
||
|
uint32_t pwr_value = 0;
|
||
|
uint32_t bbai_nf = phy_get_nf_of_bbai();
|
||
|
uint8_t left_right = POSITION_NOT_CARE;
|
||
|
|
||
|
/* range of calculation */
|
||
|
zone = IOT_PHY_CSI_BUF_LEN >> 2;
|
||
|
|
||
|
/* cal csi for every tone for debug*/
|
||
|
for (tone_idx = 0; tone_idx < zone; tone_idx++) {
|
||
|
/* tone 0 is abnormal, set to 20 */
|
||
|
if (pkt_idx == 0 && tone_idx == 0) {
|
||
|
*(pwr_buf + tone_idx) = 20;
|
||
|
continue;
|
||
|
}
|
||
|
csi_i = (int16_t)(*(csi_buf + tone_idx) & 0xFFFF);
|
||
|
csi_q = (int16_t)(*(csi_buf + tone_idx) >> 16);
|
||
|
pwr_value =
|
||
|
(uint32_t)(10 * mlog10(csi_i * csi_i + csi_q * csi_q + 1));
|
||
|
#if PHY_DEBUG_EN
|
||
|
iot_printf("tone:%u, csi_i:%d, csi_q:%d, dB:%u\n",
|
||
|
tone_idx + pkt_idx * 512, csi_i, csi_q, pwr_value);
|
||
|
#endif
|
||
|
/* 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) ||
|
||
|
pwr_value > PHY_CHN_EST_PWR_LIMIT) {
|
||
|
/* 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;
|
||
|
}
|
||
|
}
|
||
|
*(pwr_buf + tone_idx) = (uint8_t)pwr_value;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
if (pkt_idx == 0) {
|
||
|
/* cal outband total pwr */
|
||
|
outband_pwr = 0;
|
||
|
for (j = 1; j < PHY_CHN_VALID_TONE_NUM + 1; j++) {
|
||
|
outband_pwr += *(pwr_buf +
|
||
|
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone - j);
|
||
|
}
|
||
|
/* 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++) {
|
||
|
inband_pwr = *(pwr_buf +
|
||
|
g_plc_band_tbl_r0[HW_FULL_BAND]->start_tone + j);
|
||
|
/* pkt feature: inband > outband 10dB */
|
||
|
if (inband_pwr <= outband_pwr ||
|
||
|
((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)) {
|
||
|
iot_printf("[BB_AI] find pkt, valid cnt:%u\n", dump_valid_cnt);
|
||
|
return ERR_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* the maximum value is found at a certain interval */
|
||
|
for (j = 1; j < ((zone >> 1) + 1); j++) {
|
||
|
row_sum = 0;
|
||
|
for (i = j; i < zone - j; i++) {
|
||
|
if (*(pwr_buf + i) >= *(pwr_buf + i - j) &&
|
||
|
*(pwr_buf + i) >= *(pwr_buf + i + j)) {
|
||
|
row_sum++;
|
||
|
}
|
||
|
/* row_sum can't exceed the max_value, we can stop early */
|
||
|
if ((max_value - row_sum) > (int32_t)(zone - j - i)) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
/* find max row */
|
||
|
if (row_sum > max_value) {
|
||
|
max_idx = j;
|
||
|
max_value = row_sum;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
window_length = max_idx;
|
||
|
|
||
|
for (j = 1; j < (window_length + 1); j++) {
|
||
|
for (i = j; i < zone - j; i++) {
|
||
|
if (*(pwr_buf + i) > *(pwr_buf + i - j) &&
|
||
|
*(pwr_buf + i) > *(pwr_buf + i + j)) {
|
||
|
detect_buf[i]++;
|
||
|
} else if (j == 1 && i + 2 < zone &&
|
||
|
*(pwr_buf + i) == *(pwr_buf + i + j)) {
|
||
|
if (*(pwr_buf + i) > *(pwr_buf + i - j) &&
|
||
|
*(pwr_buf + i) > *(pwr_buf + i + j + 1)) {
|
||
|
detect_buf[i]++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float window_thd = window_length * 0.75;
|
||
|
if (window_length > 2 && window_length * 0.15 < 1) {
|
||
|
window_thd = window_length - 2;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < zone; i++) {
|
||
|
if (detect_buf[i] > (uint32_t)window_thd) {
|
||
|
if (pwr_buf[i] > 45) {
|
||
|
if (i && (i < zone -1) && detect_buf[i] == window_length) {
|
||
|
if (pwr_buf[i + 1] > pwr_buf[i - 1]) {
|
||
|
left_right = POSITION_CLOSER_RIGHT;
|
||
|
} else {
|
||
|
left_right = POSITION_CLOSER_LEFT;
|
||
|
}
|
||
|
}
|
||
|
phy_spur_arry_append(spur_buf, PHY_CHN_EST_AI_SPUR_LEN,
|
||
|
i + pkt_idx * (IOT_PHY_CSI_BUF_LEN >> 2), pwr_buf[i], true,
|
||
|
(detect_buf[i] == window_length), left_right);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
(void)csi_buf;
|
||
|
(void)spur_buf;
|
||
|
(void)current_gain;
|
||
|
(void)pkt_idx;
|
||
|
#endif
|
||
|
|
||
|
return ERR_OK;
|
||
|
}
|
||
|
|
||
|
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 *csi_pkt = NULL;
|
||
|
uint32_t *csi_buf = NULL;
|
||
|
iot_pkt_t *pwr_pkt = NULL;
|
||
|
uint8_t *pwr_buf = NULL;
|
||
|
iot_pkt_t *detect_pkt = NULL;
|
||
|
uint16_t *detect_buf = NULL;
|
||
|
iot_pkt_t *spur_pkt = NULL;
|
||
|
iot_phy_spur_t *spur_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");
|
||
|
goto err1;
|
||
|
} 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(csi_pkt, IOT_PHY_CSI_BUF_LEN, 0, PLC_PHY_COMMON_MID);
|
||
|
if (!csi_pkt) {
|
||
|
iot_printf("phy chn est error, get csi pkt fail\n");
|
||
|
goto err2;
|
||
|
}
|
||
|
csi_buf = (uint32_t *)iot_pkt_put(csi_pkt, IOT_PHY_CSI_BUF_LEN);
|
||
|
|
||
|
/* get mem from iot_pkt to save power data */
|
||
|
IOT_PKT_GET(pwr_pkt, IOT_PHY_PWR_BUF_LEN, 0, PLC_PHY_COMMON_MID);
|
||
|
if (!pwr_pkt) {
|
||
|
iot_printf("phy chn est error, get power pkt fail\n");
|
||
|
goto err3;
|
||
|
}
|
||
|
pwr_buf = (uint8_t *)iot_pkt_put(pwr_pkt, IOT_PHY_PWR_BUF_LEN);
|
||
|
|
||
|
/* get mem from iot_pkt to save detect data */
|
||
|
IOT_PKT_GET(detect_pkt, IOT_PHY_DETECT_BUF_LEN, 0, PLC_PHY_COMMON_MID);
|
||
|
if (!detect_pkt) {
|
||
|
iot_printf("phy chn est error, get detect pkt fail\n");
|
||
|
goto err4;
|
||
|
}
|
||
|
detect_buf = (uint16_t *)iot_pkt_put(detect_pkt, IOT_PHY_DETECT_BUF_LEN);
|
||
|
|
||
|
/* get mem from iot_pkt to save spur data */
|
||
|
IOT_PKT_GET(spur_pkt, PHY_CHN_EST_AI_SPUR_LEN, 0, PLC_PHY_COMMON_MID);
|
||
|
if (!spur_pkt) {
|
||
|
iot_printf("phy chn est error, get spur pkt fail\n");
|
||
|
goto err5;
|
||
|
}
|
||
|
spur_buf = (iot_phy_spur_t *)iot_pkt_put(spur_pkt, PHY_CHN_EST_AI_SPUR_LEN);
|
||
|
|
||
|
/* get average gain */
|
||
|
current_gain = phy_gain_get_from_agc();
|
||
|
if (current_gain > PHY_BBAI_GAIN_MAX) {
|
||
|
current_gain = PHY_BBAI_GAIN_MAX;
|
||
|
}
|
||
|
|
||
|
/* 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++) {
|
||
|
os_mem_set(detect_buf, 0, IOT_PHY_DETECT_BUF_LEN);
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/* don't care more than 25M */
|
||
|
if (FFT_DUMP_PKT_MAX - 1 == pkt_idx) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ret = phy_chn_est_dmpd_process(pwr_buf,
|
||
|
csi_buf, detect_buf, spur_buf, ¤t_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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* 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, "
|
||
|
"is_max:%d\n", spur_buf[i].tone_id, spur_buf[i].spur_cnt,
|
||
|
spur_buf[i].spur_ratio, spur_buf[i].notch_filter_en_cnt,
|
||
|
spur_buf[i].color);
|
||
|
}
|
||
|
#endif
|
||
|
/* get peak point */
|
||
|
phy_spur_arry_peak_handler(spur_buf, PHY_CHN_EST_AI_SPUR_LEN, success_cnt);
|
||
|
} else {
|
||
|
iot_printf("csi buf pointer get fail from iot_pkt!\n");
|
||
|
}
|
||
|
/* 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;
|
||
|
}
|
||
|
|
||
|
/* 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);
|
||
|
|
||
|
/* free spur pkt */
|
||
|
iot_pkt_free(spur_pkt);
|
||
|
|
||
|
err5:
|
||
|
/* free detect pkt */
|
||
|
iot_pkt_free(detect_pkt);
|
||
|
|
||
|
err4:
|
||
|
/* free pwr pkt */
|
||
|
iot_pkt_free(pwr_pkt);
|
||
|
|
||
|
err3:
|
||
|
/* free csi pkt */
|
||
|
iot_pkt_free(csi_pkt);
|
||
|
|
||
|
err2:
|
||
|
phy_dump_busy_set(false);
|
||
|
|
||
|
err1:
|
||
|
|
||
|
#else
|
||
|
(void)est_rty_cnt;
|
||
|
(void)timeout_ms;
|
||
|
#endif
|
||
|
|
||
|
return success_cnt;
|
||
|
}
|
||
|
|
||
|
#endif /* PHY_BBAI_ALGORITHM == PHY_BBAI_SLIDE_WINDOWS */
|