/****************************************************************************** * * Copyright(c) 2007 - 2020 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: * wlanfae * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * * Larry Finger * *****************************************************************************/ #include "halbb_precomp.h" const u32 db_invert_table[12][8] = { {10, 13, 16, 20, 25, 32, 40, 50}, /* @U(32,3) */ {64, 80, 101, 128, 160, 201, 256, 318}, /* @U(32,3) */ {401, 505, 635, 800, 1007, 1268, 1596, 2010}, /* @U(32,3) */ {316, 398, 501, 631, 794, 1000, 1259, 1585}, /* @U(32,0) */ {1995, 2512, 3162, 3981, 5012, 6310, 7943, 10000}, /* @U(32,0) */ {12589, 15849, 19953, 25119, 31623, 39811, 50119, 63098}, /* @U(32,0) */ {79433, 100000, 125893, 158489, 199526, 251189, 316228, 398107}, /* @U(32,0) */ {501187, 630957, 794328, 1000000, 1258925, 1584893, 1995262, 2511886}, /* @U(32,0) */ {3162278, 3981072, 5011872, 6309573, 7943282, 1000000, 12589254, 15848932}, /* @U(32,0) */ {19952623, 25118864, 31622777, 39810717, 50118723, 63095734, 79432823, 100000000}, /* @U(32,0) */ {125892541, 158489319, 199526232, 251188643, 316227766, 398107171, 501187234, 630957345}, /* @U(32,0) */ {794328235, 1000000000, 1258925412, 1584893192, 1995262315, 2511886432U, 3162277660U, 3981071706U} }; /* @U(32,0) */ /*Y = 10*log(X)*/ s32 halbb_pwdb_conversion(s32 X, u32 total_bit, u32 decimal_bit) { s32 Y, integer = 0, decimal = 0; u32 i; if (X == 0) X = 1; /* @log2(x), x can't be 0 */ for (i = (total_bit - 1); i > 0; i--) { if (X & BIT(i)) { integer = i; if (i > 0) { /*decimal is 0.5dB*3=1.5dB~=2dB */ decimal = (X & BIT(i - 1)) ? 2 : 0; } break; } } Y = 3 * (integer - decimal_bit) + decimal; /* @10*log(x)=3*log2(x), */ return Y; } s32 halbb_sign_conversion(s32 val, u32 total_bit) { if (val & BIT(total_bit - 1)) val -= BIT(total_bit); return val; } /*threshold must form low to high*/ u8 halbb_find_intrvl(struct bb_info *bb, u16 val, u8 *threshold, u8 len) { u8 i = 0; u8 ret_val = 0; u8 max_th = threshold[len - 1]; for (i = 0; i < len; i++) { if (val < threshold[i]) { ret_val = i; break; } else if (val >= max_th) { ret_val = len; break; } } return ret_val; } void halbb_seq_sorting(struct bb_info *bb, u32 *val, u32 *idx, u32 *idx_out, u8 seq_length) { u8 i = 0, j = 0, tmp = 0; u32 tmp_a, tmp_b; u32 tmp_idx_a, tmp_idx_b; for (i = 0; i < seq_length; i++) idx[i] = i; for (i = 0; i < (seq_length - 1); i++) { tmp = seq_length - 1 - i; /*to prevent WIN WHQL warning*/ for (j = 0; j < tmp; j++) { tmp_a = val[j]; tmp_b = val[j + 1]; tmp_idx_a = idx[j]; tmp_idx_b = idx[j + 1]; if (tmp_a < tmp_b) { val[j] = tmp_b; val[j + 1] = tmp_a; idx[j] = tmp_idx_b; idx[j + 1] = tmp_idx_a; } } } for (i = 0; i < seq_length; i++) idx_out[idx[i]] = i + 1; } u32 halbb_convert_to_db(u64 val) { u8 i; u8 j; u32 dB; if (val >= db_invert_table[11][7]) return 96; /* @maximum 96 dB */ for (i = 0; i < 12; i++) { if (i <= 2 && (val << FRAC_BITS) <= db_invert_table[i][7]) break; else if (i > 2 && val <= db_invert_table[i][7]) break; } for (j = 0; j < 8; j++) { if (i <= 2 && (val << FRAC_BITS) <= db_invert_table[i][j]) break; else if (i > 2 && i < 12 && val <= db_invert_table[i][j]) break; } /*special cases*/ if (j == 0 && i == 0) goto end; if (i == 3 && j == 0) { if (db_invert_table[3][0] - val > val - (db_invert_table[2][7] >> FRAC_BITS)) { i = 2; j = 7; } goto end; } if (i < 3) val = val << FRAC_BITS; /*@elements of row 0~2 shift left*/ /*compare difference to get precise dB*/ if (j == 0) { if (db_invert_table[i][j] - val > val - db_invert_table[i - 1][7]) { i = i - 1; j = 7; } } else { if (db_invert_table[i][j] - val > val - db_invert_table[i][j - 1]) { j = j - 1; } } end: dB = (i << 3) + j + 1; return dB; } u64 halbb_db_2_linear(u32 val) { u8 i = 0; u8 j = 0; u64 linear = 0; val = val & 0xFF; /* @1dB~96dB */ if (val > 96) { val = 96; } else if (val < 1) { linear = 1; return linear; } i = (u8)((val - 1) >> 3); j = (u8)(val - 1) - (i << 3); linear = db_invert_table[i][j]; if (i > 2) linear = linear << FRAC_BITS; return linear; } u16 halbb_show_fraction_num(u32 frac_val, u8 bit_num) { u8 i = 0; u16 val = 0; u16 base = 500; /* Fix to 3 digit after the decimal point*/ for (i = bit_num; i > 0; i--) { if (frac_val & BIT(i - 1)) val += (base >> (bit_num - i)); } return val; } u32 halbb_show_fraction_num_opt(u32 frac_val, u8 bit_num, u8 decimal_place) { u8 i = 0; u32 val = 0; u32 base = 5; if (decimal_place == 0) return 0; if (decimal_place > 9) decimal_place = 9; for (i = 1; i < decimal_place; i++) base *= 10; for (i = bit_num; i > 0; i--) { if (frac_val & BIT(i - 1)) val += (base >> (bit_num - i)); } return val; } u16 halbb_ones_num_in_bitmap(u64 val, u8 size) { u8 i = 0; u8 ones_num = 0; for (i = 0; i < size; i++) { if (val & BIT(0)) ones_num++; val = val >> 1; } return ones_num; } u64 halbb_gen_mask_from_0(u8 mask_num) { u8 i = 0; u64 bitmask = 0; if (mask_num > 64 || mask_num == 0) return 0; for (i = 0; i < mask_num; i++) bitmask = (bitmask << 1) | BIT(0); return bitmask; } u64 halbb_gen_mask(u8 up_num, u8 low_num) { if (up_num < low_num) return 0; return (halbb_gen_mask_from_0(up_num - low_num + 1) << low_num); } u32 halbb_cal_bit_shift(u32 bit_mask) { u32 i; for (i = 0; i <= 31; i++) { if ((bit_mask >> i) & BIT0) break; } return i; } s32 halbb_cnvrt_2_sign(u32 val, u8 bit_num) { if (bit_num > 32) return (s32)val; if (val & BIT(bit_num - 1)) /*Sign BIT*/ val -= (1 << bit_num); /*@2's*/ return val; } s64 halbb_cnvrt_2_sign_64(u64 val, u8 bit_num) { u64 one = 1; s64 val_sign = (s64)val; if (bit_num >= 64) return (s64)val; if (val & (one << (bit_num - 1))) /*Sign BIT*/ val_sign = val - (one << bit_num); /*@2's*/ return val_sign; } void halbb_print_sign_frac_digit(struct bb_info *bb, u32 val, u8 total_bit_num, u8 frac_bit_num, char *buf, u16 buf_size) { s32 val_s32 = (s32)val; u32 val_abs = 0; u32 mask_frac = 0; u32 frac_digit = 0; val_abs = ABS_32(val_s32); mask_frac = (u32)halbb_gen_mask_from_0(frac_bit_num); frac_digit = halbb_show_fraction_num(val_abs & mask_frac, frac_bit_num); if (frac_bit_num == 1) { frac_digit = (val & 0x1) * 5; _os_snprintf(buf, buf_size, "%s%d.%d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } else if (frac_bit_num == 2) { frac_digit = (val & 0x3) * 25; _os_snprintf(buf, buf_size, "%s%d.%02d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } else if (frac_bit_num == 3) { frac_digit = halbb_show_fraction_num_opt(val_abs & mask_frac, frac_bit_num, 3); _os_snprintf(buf, buf_size, "%s%d.%03d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } else if (frac_bit_num == 4) { frac_digit = halbb_show_fraction_num_opt(val_abs & mask_frac, frac_bit_num, 4); _os_snprintf(buf, buf_size, "%s%d.%04d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } else if (frac_bit_num == 5) { frac_digit = halbb_show_fraction_num_opt(val_abs & mask_frac, frac_bit_num, 5); _os_snprintf(buf, buf_size, "%s%d.%05d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } else { frac_digit = halbb_show_fraction_num_opt(val_abs & mask_frac, frac_bit_num, 8); _os_snprintf(buf, buf_size, "%s%d.%08d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } } char *halbb_print_sign_frac_digit2(struct bb_info *bb, u32 val, u8 total_bit_num, u8 frac_bit_num) { char *buf = bb->dbg_buf; u16 buf_size = HALBB_SNPRINT_SIZE; s32 val_s32 = (s32)val; u32 val_abs = 0; u32 mask_frac = 0; u16 frac_digit = 0; val_abs = ABS_32(val_s32); mask_frac = (u32)halbb_gen_mask_from_0(frac_bit_num); if (frac_bit_num == 1) { frac_digit = (val & 0x1) * 5; _os_snprintf(buf, buf_size, "%s%d.%d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } else if (frac_bit_num == 2) { frac_digit = (val & 0x3) * 25; _os_snprintf(buf, buf_size, "%s%d.%02d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } else { frac_digit = halbb_show_fraction_num(val_abs & mask_frac, frac_bit_num); _os_snprintf(buf, buf_size, "%s%d.%03d", (val_s32 >= 0) ? "" : "-", val_abs >> frac_bit_num, frac_digit); } return buf; } void halbb_print_buff_64(struct bb_info *bb, u8 *addr, u16 length) /*unit: Byte*/ { u64 *buff_tmp = NULL; u8 print_len = length >> 3; u8 i; if (length % 8) print_len++; buff_tmp = (u64 *)addr; for (i = 0; i < print_len; i++) { BB_TRACE("[%02d]0x%016llx\n", i, buff_tmp[i]); } } void halbb_print_buff_32(struct bb_info *bb, u8 *addr, u16 length) /*unit: Byte*/ { u32 *buff_tmp = NULL; u8 print_len = length >> 2; u8 i; if (length % 4) print_len++; buff_tmp = (u32 *)addr; for (i = 0; i < print_len; i++) { BB_TRACE("0x%08x\n", buff_tmp[i]); } }