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 */
 |