/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2017-2021. All rights reserved. * Description: Unicable IAPI interface * Author: Hisilicon * Create: 2017/06/30 */ #include "iapi_unicable.h" #include #include "soc_log.h" #include "soc_errno.h" #include "securec.h" #include "mpi_frontend_ext.h" #include "iapi_frontend.h" #include "iapi_diseqc.h" static unicable_info g_unicable_info; static td_u32 g_unicable_stop = 0; static scr_tone g_scr_array[SCR_D_SCAN_FREQ_END - SCR_D_SCAN_FREQ_START]; static scr_tone g_min_agc[SCR_USER_BAND_NUMBERS]; static scr_tone g_max_agc_differ[SCR_USER_BAND_NUMBERS]; static td_s32 g_tone_freq[SCR_USER_BAND_NUMBERS]; td_s32 uapi_unicable_odu_power_off(td_u32 port, td_u8 scrno) { uapi_frontend_diseqc_send_msg send_msg; td_s32 ret; td_u8 chan_byte[CHAN_BYTE_SIZE] = {0}; /* 2:index */ if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (scrno >= SCR_NO_MAX) { soc_log_err("SCR NO error.\n"); return TD_FALSE; } unic_init_diseqc_send_msg(send_msg, port); chan_byte[0] = ((scrno & 7) << 5); /* 7:value;5:shift */ format_diseqc_cmd_value(send_msg.msg, 0xE0, 0x10, 0x5A, chan_byte, CHAN_BYTE_SIZE); /* 2:length */ ret = diseqc_send_recv_message(port, &send_msg, NULL); if (ret != TD_SUCCESS) { soc_log_err("Send WRITE N0 fail.\n"); return ret; } return TD_SUCCESS; } td_s32 uapi_unicable_odu_ubx_signal_on(td_u32 port) { td_s32 ret; td_u8 chan_byte[CHAN_BYTE_SIZE] = {0, 0}; /* 2:index */ const td_u8 sub_fun = 0; const td_u8 scrno = 0; uapi_frontend_diseqc_send_msg send_msg; if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } unic_init_diseqc_send_msg(send_msg, port); /* 7:value;5:shift */ chan_byte[0] = ((scrno & 7) << 5) | ((sub_fun & 0x1f) << 0); /* 0x1f:value;0:shift */ format_diseqc_cmd_value(send_msg.msg, 0xE0, /* 0xE0:FRAMING_BYTE */ 0x10, 0x5B, chan_byte, CHAN_BYTE_SIZE); ret = diseqc_send_recv_message(port, &send_msg, NULL); if (ret != TD_SUCCESS) { soc_log_err("Send SCRxSignal ON fail.\n"); return ret; } return TD_SUCCESS; } td_s32 uapi_unicable_odu_config(td_u32 port, td_u8 scrno, td_u8 app_no) { uapi_frontend_diseqc_send_msg send_msg; td_s32 ret; td_u8 chan_byte[CHAN_BYTE_SIZE] = {0, 0}; const td_u8 sub_fun = 1; if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (scrno >= SCR_NO_MAX) { soc_log_err("SCR NO error.\n"); return TD_FALSE; } unic_init_diseqc_send_msg(send_msg, port); /* 7:value;5:shift */ chan_byte[0] = ((scrno & 7) << 5) | ((sub_fun & 0x1f) << 0); /* 0x1f:value;0:shift */ chan_byte[1] = app_no; format_diseqc_cmd_value(send_msg.msg, 0xE0, 0x10, 0x5B, chan_byte, CHAN_BYTE_SIZE); ret = diseqc_send_recv_message(port, &send_msg, NULL); if (ret != TD_SUCCESS) { soc_log_err("Send unicable config fail.\n"); return ret; } return TD_SUCCESS; } td_s32 uapi_unicable_odu_lo_freq(td_u32 port, td_u8 scrno, td_u8 lo_freq_no) { uapi_frontend_diseqc_send_msg send_msg; td_s32 ret; td_u8 chan_byte[CHAN_BYTE_SIZE] = {0, 0}; const td_u8 sub_fun = 2; if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (scrno >= SCR_NO_MAX) { soc_log_err("SCR NO error.\n"); return TD_FALSE; } unic_init_diseqc_send_msg(send_msg, port); /* 7:value;5:shift */ chan_byte[0] = ((scrno & 7) << 5) | ((sub_fun & 0x1f) << 0); /* 0x1f:value;0:shift */ chan_byte[1] = lo_freq_no; format_diseqc_cmd_value(send_msg.msg, 0xE0, 0x10, 0x5B, chan_byte, CHAN_BYTE_SIZE); ret = diseqc_send_recv_message(port, &send_msg, NULL); if (ret != TD_SUCCESS) { soc_log_err("Send unicable local oscillator number fail.\n"); return ret; } return TD_SUCCESS; } td_s32 uapi_unicable_odu_channel_change(td_u32 port, const uapi_unicable_channel_para *para) { td_s32 ret; uapi_frontend_diseqc_send_msg send_msg; td_u8 chan_byte[CHAN_BYTE_SIZE] = {0, 0}; if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (para == TD_NULL) { soc_log_err("Input parameter(para) invalid.\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } unic_init_diseqc_send_msg(send_msg, port); /* 7:value;5:shift */ chan_byte[0] = ((para->ub_num & 0x7) << 5) | ((para->bank & 0x7) << 2); /* 0x7:value;5 2:shift */ chan_byte[0] |= ((para->t_val >> 0x8) & 0x3); /* 0x8:shift 0x3:mask */ chan_byte[1] = para->t_val & 0xff; /* 0xE0 0x10 0x5A:diseqc command */ format_diseqc_cmd_value(send_msg.msg, 0xE0, 0x10, 0x5A, chan_byte, CHAN_BYTE_SIZE); ret = diseqc_send_recv_message(port, &send_msg, NULL); if (ret != TD_SUCCESS) { soc_log_err("Send WRITE N0 fail.\n"); return ret; } /* If support level 2.x, handle received message here. */ return TD_SUCCESS; } static td_s32 scr_get_agc(td_u32 port, td_s32 center_freq, td_s32 *agc) { td_s32 ret; fe_ioctrl_data_buf fe_data_buf = {0}; fe_data_buf.port = port; fe_data_buf.data_buf[0] = (td_u32)center_freq; ret = ext_mpi_frontend_get_agc(&fe_data_buf); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_get_agc, ret); return ret; } *agc = (td_s32)fe_data_buf.data_buf[1]; return TD_SUCCESS; } static td_s32 scr_enable_tone(td_u32 port) { td_s32 ret; td_u8 chan_byte[CHAN_BYTE_SIZE] = {0x0}; /* 2:index */ uapi_frontend_diseqc_send_msg send_msg; if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } unic_init_diseqc_send_msg(send_msg, port); format_diseqc_cmd_value(send_msg.msg, 0xE0, 0x10, 0x5B, chan_byte, CHAN_BYTE_SIZE); ret = diseqc_send_recv_message(port, &send_msg, NULL); if (ret != TD_SUCCESS) { soc_log_err("Send scr msg fail.\n"); return ret; } return TD_SUCCESS; } static td_s32 scr_off_tones(td_u32 port, td_u32 scrbpf) { uapi_frontend_diseqc_send_msg send_msg; td_s32 ret; td_u8 chan_byte[CHAN_BYTE_SIZE] = {0}; if (scrbpf >= 8) { // scrbpf 8 return TD_FAILURE; } unic_init_diseqc_send_msg(send_msg, port); chan_byte[0] |= (td_u8)(scrbpf << 5); // 5:bit offset format_diseqc_cmd_value(send_msg.msg, 0xE0, 0x10, 0x5A, chan_byte, CHAN_BYTE_SIZE); ret = diseqc_send_recv_message(port, &send_msg, NULL); if (ret != TD_SUCCESS) { soc_log_err("Send scr msg fail.\n"); return ret; } fe_usleep(2 * 1000); // 2* 1000:2ms return TD_SUCCESS; } /* Sort Array by the AGC value in ascending order. */ static td_s32 scr_sort_ub_by_agc(scr_tone us_list[], td_u32 ub_list_len) { td_u32 i; td_u32 j; scr_tone tmp_ub = {0}; if (ub_list_len == 0) { soc_log_err("para is invalid!\n"); return TD_FAILURE; } if (ub_list_len <= 1) { return TD_FAILURE; } for (i = 0; i < ub_list_len - 1; i++) { for (j = i + 1; j < ub_list_len; j++) { if (us_list[j].agc < us_list[i].agc) { tmp_ub = us_list[i]; us_list[i] = us_list[j]; us_list[j] = tmp_ub; } } } return TD_SUCCESS; } /* Sort Array by the Freq in ascending order. */ static td_s32 scr_sort_ub_by_freq(scr_tone us_list[], td_u32 ub_list_len, td_s32 count) { td_s32 i, j; scr_tone tmp_ub = {0}; if (ub_list_len == 0) { soc_log_err("para is invalid!\n"); return TD_FAILURE; } if (count <= 1) { return TD_FAILURE; } for (i = 0; i < count - 1; i++) { for (j = i + 1; j < count; j++) { if (us_list[j].freq < us_list[i].freq) { tmp_ub = us_list[i]; us_list[i] = us_list[j]; us_list[j] = tmp_ub; } } } soc_log_info("SortUbByFreq start:\n"); for (i = 0; i < count; i++) { soc_log_info("i:%d, freq:%u MHz, agc:%#x\n", i, us_list[i].freq, us_list[i].agc); } soc_log_info("SortUbByFreq end.\n"); return TD_SUCCESS; } static td_void scr_blindscan_set_status(td_u32 port, const unicable_scan_para *para, td_u16 progress) { uapi_unicable_scan_user_band_notify notify; uapi_unicable_scan_status unic_status; td_u16 notify_progress; notify_progress = progress; notify.progress_percent = ¬ify_progress; if (para->unic_scan_para.evt_notify != NULL) { para->unic_scan_para.evt_notify(port, UAPI_UNICABLE_SCAN_EVT_PROGRESS, ¬ify); if (progress == 100) { /* 100:percent */ unic_status = UAPI_UNICABLE_SCAN_STATUS_FINISH; notify.status = &unic_status; para->unic_scan_para.evt_notify(port, UAPI_UNICABLE_SCAN_EVT_STATUS, ¬ify); } } return; } static td_s32 scr_blindscan_tone_get_agc_value(td_u32 port, const unicable_scan_para *para) { td_s32 ret; td_s32 i; td_s32 count = 0; td_u16 progress; td_u16 pre_progress = 0; td_double tmp_percent; uapi_unicable_scan_status unic_status; uapi_unicable_scan_user_band_notify notify; /* enable all tones */ ret = scr_enable_tone(port); if (ret != TD_SUCCESS) { soc_log_err("scr_enable_tone fail.\n"); return TD_FAILURE; } fe_usleep(100); /* 100:us */ /* get the agc value of every freq */ for (i = 0; i < SCR_D_SCAN_FREQ_END - SCR_D_SCAN_FREQ_START; i++) { g_scr_array[i].freq = i + SCR_D_SCAN_FREQ_START; ret = scr_get_agc(port, g_scr_array[i].freq, &(g_scr_array[i].agc)); if (ret != TD_SUCCESS) { soc_log_err("scr_get_agc fail.\n"); return TD_FAILURE; } count++; if (g_unicable_stop != 0) { unic_status = UAPI_UNICABLE_SCAN_STATUS_QUIT; notify.status = &unic_status; para->unic_scan_para.evt_notify(port, UAPI_UNICABLE_SCAN_EVT_STATUS, ¬ify); return TD_SUCCESS; } if (count % 5 == 0) { /* 5:value */ tmp_percent = (td_double)(count) / 1200 * 98; /* 1200:division,98:multi */ progress = (td_u16)tmp_percent; if (progress > pre_progress) { pre_progress = progress; scr_blindscan_set_status(port, para, progress); } } } return TD_SUCCESS; } static td_void get_min_agc_array(td_void) { td_s32 ret; td_u32 i, j; td_u32 ub_count; /* the value of agc is more smaller,the strength of signal is more stronger. */ ret = scr_sort_ub_by_agc(g_scr_array, sizeof(g_scr_array) / sizeof(scr_tone)); if (ret != TD_SUCCESS) { soc_log_err("scr_sort_ub_by_agc error!\n"); } /* pick up the most eight strongest UB which has 80MHz bandwidth between each other. */ g_min_agc[0] = g_scr_array[0]; ub_count = 1; for (i = 1; i < sizeof(g_scr_array) / sizeof(scr_tone); i++) { for (j = 0; j < SCR_USER_BAND_NUMBERS && j < ub_count; j++) { if (abs(g_scr_array[i].freq - g_min_agc[j].freq) <= MIN_DISTANCE_BETWEEN_UB_MHZ) { break; } } if ((j < SCR_USER_BAND_NUMBERS) && (j >= ub_count)) { g_min_agc[ub_count] = g_scr_array[i]; ub_count++; if (ub_count >= SCR_USER_BAND_NUMBERS) { break; } } } soc_log_info("min_agc start:\n"); for (i = 0; i < SCR_USER_BAND_NUMBERS; i++) { soc_log_info("i:%d, freq:%u MHz, agc:%#x\n", i, g_min_agc[i].freq, g_min_agc[i].agc); } soc_log_info("g_min_agc end.\n"); ret = scr_sort_ub_by_freq(g_scr_array, sizeof(g_scr_array) / sizeof(scr_tone), sizeof(g_scr_array) / sizeof(scr_tone)); if (ret != TD_SUCCESS) { soc_log_err("scr_sort_ub_by_freq error!\n"); } return; } static td_void check_tone_off(td_u32 port, td_u32 real_ub_number, td_s32 *count) { td_s32 ret; td_u32 ub_count; td_u32 i; td_s32 tmp_count; td_s32 agc_value = 0; tmp_count = 0; for (ub_count = 0; ub_count < real_ub_number; ub_count++) { for (i = 0; i < 10; i++) { /* 10:max */ ret = scr_get_agc(port, g_min_agc[ub_count].freq, &agc_value); if (ret != TD_SUCCESS) { soc_log_err("scr_get_agc fail.\n"); continue; } if (agc_value != 0x77777777) { /* agc not lock,try get agc again */ break; } } if (abs(agc_value - g_min_agc[ub_count].agc) >= MIN_AGC_CHANGED_BETWEEN_ON_AND_OFF) { if (tmp_count < SCR_USER_BAND_NUMBERS) { g_max_agc_differ[tmp_count].agc = agc_value; g_max_agc_differ[tmp_count].freq = g_min_agc[ub_count].freq; tmp_count++; } } else { soc_log_info("agc_value:%#x\n", agc_value); soc_log_info("min_agc[%u].freq:%u\n", ub_count, g_min_agc[ub_count].freq); soc_log_info("min_agc[%u].agc:%#x\n", ub_count, g_min_agc[ub_count].agc); for (i = ub_count; i < real_ub_number && (i < SCR_USER_BAND_NUMBERS - 1); i++) { g_min_agc[i] = g_min_agc[i + 1]; } real_ub_number--; if (ub_count > 0) { ub_count = ub_count - 1; } else { ub_count = 0; } } } *count = tmp_count; return; } static td_void check_tone_up(td_u32 port, td_u32 real_ub_number, td_s32 *count) { td_s32 ret; td_u32 ub_count; td_u32 ub_count_sub1 = 0; td_u32 i; td_s32 tmp_count; td_s32 agc_value = 0; tmp_count = 0; for (ub_count = 0; ub_count < real_ub_number; ub_count++) { if (ub_count_sub1 != 0) { ub_count -= 1; // before ub_count 0; ub_count_sub1 = 0; } for (i = 0; i < 10; i++) { /* 10:max */ ret = scr_get_agc(port, g_min_agc[ub_count].freq, &agc_value); if (ret != TD_SUCCESS) { soc_log_err("scr_get_agc fail.\n"); continue; } if (agc_value != 0x77777777) { /* agc not lock,try get agc again */ break; } } if (abs(agc_value - g_max_agc_differ[ub_count].agc) >= MIN_AGC_CHANGED_BETWEEN_ON_AND_OFF) { tmp_count++; continue; } soc_log_info("agc_value:%#x\n", agc_value); soc_log_info("g_max_agc_differ[%u].freq:%u\n", ub_count, g_max_agc_differ[ub_count].freq); soc_log_info("g_max_agc_differ[%u].agc:%#x\n", ub_count, g_max_agc_differ[ub_count].agc); for (i = ub_count; i < real_ub_number; i++) { if (i < (SCR_USER_BAND_NUMBERS - 1)) { g_min_agc[i] = g_min_agc[i + 1]; } } real_ub_number--; if (ub_count > 0) { ub_count = ub_count - 1; } else { ub_count_sub1 = 1; } } *count = tmp_count; return; } static td_s32 scr_blindscan_tone_by_sort(td_u32 port, td_s32 *threshold, td_u32 *real_ub_number, td_s32 *count, const unicable_scan_para *para) { td_s32 ret; td_s32 i; td_s32 boundary_agc; td_u16 progress; get_min_agc_array(); if (((g_min_agc[3].freq - 15 - SCR_D_SCAN_FREQ_START) < 0) || /* 3:index,15:sub */ ((g_min_agc[3].freq - 15 - SCR_D_SCAN_FREQ_START) >= /* 3:index,15:sub */ (SCR_D_SCAN_FREQ_END - SCR_D_SCAN_FREQ_START))) { soc_log_err("g_min_agc[3].freq is out of bound\n"); return TD_FAILURE; } /* * tuner lowpass filter bandwidth = 30MHz.the strength of signal is most * weakest at tone 15MHz */ boundary_agc = g_scr_array[g_min_agc[3].freq - 15 - SCR_D_SCAN_FREQ_START].agc; /* 3:index,15:sub */ /* agc threshold equal one half of max agc subing min agc */ *threshold = g_min_agc[3].agc + abs(boundary_agc - g_min_agc[3].agc) / 4; /* 3:index;3:index;4:div */ for (i = 0; i < SCR_USER_BAND_NUMBERS; i++) { if (g_min_agc[i].agc <= *threshold) { (*real_ub_number)++; } else { break; } } ret = scr_sort_ub_by_freq(g_min_agc, sizeof(g_min_agc) / sizeof(scr_tone), (td_s32)(*real_ub_number)); if (ret != TD_SUCCESS) { soc_log_err("scr_sort_ub_by_freq failed.\n"); return TD_FAILURE; } /* send ODU_PowerOFF command, check tone signal is true or not */ for (i = 0; i < SCR_USER_BAND_NUMBERS; i++) { ret = scr_off_tones(port, (td_u32)i); fe_usleep(5 * 1000); /* 5:sleep;1000:us */ } /* if there are -20dbm,Unicable device is exist. */ check_tone_off(port, *real_ub_number, count); *real_ub_number = (td_u32)*count; progress = 99; /* 99:percent */ scr_blindscan_set_status(port, para, progress); return TD_SUCCESS; } static td_s32 scr_blindscan_tone_first_check(td_u32 port, td_s32 *threshold, td_u32 *real_ub_number, td_s32 *count, const unicable_scan_para *para) { td_s32 ret; td_u16 progress; ret = scr_blindscan_tone_get_agc_value(port, para); if (ret != TD_SUCCESS) { soc_log_err("scr_blindscan_tone_get_agc_value fail.\n"); return TD_FAILURE; } ret = scr_blindscan_tone_by_sort(port, threshold, real_ub_number, count, para); if (ret != TD_SUCCESS) { soc_log_err("scr_blindscan_tone_get_agc_value fail.\n"); progress = 100; /* 100:percent */ scr_blindscan_set_status(port, para, progress); return TD_FAILURE; } if (*count == 0) { soc_log_err("There is no tone,please check the unicable!\n"); g_unicable_info.total_ub_number = 0; progress = 100; /* 100:percent */ scr_blindscan_set_status(port, para, progress); return TD_FAILURE; } return TD_SUCCESS; } static td_s32 scr_blindscan_tone_second_check(td_u32 port, td_u32 real_ub_number, td_s32 *count, const unicable_scan_para *para) { td_s32 ret; td_u16 progress; /* maybe cable disconnect,check again */ ret = scr_enable_tone(port); if (ret != TD_SUCCESS) { soc_log_err("scr_enable_tone fail.\n"); return TD_FAILURE; } fe_usleep(100); /* 100:sleep */ /* if there are -20dbm,cable is always plugged on. */ if (real_ub_number > SCR_USER_BAND_NUMBERS) { soc_log_err("real_ub_number:%u is out of bound:%u\n", real_ub_number, SCR_USER_BAND_NUMBERS); return TD_FAILURE; } if (real_ub_number < SCR_USER_BAND_NUMBERS) { check_tone_up(port, real_ub_number, count); real_ub_number = (td_u32)*count; } else { soc_log_err("Out of bound!\n"); } if (*count == 0) { soc_log_err("There is no tone,please check the unicable!\n"); g_unicable_info.total_ub_number = 0; progress = 100; /* 100:percent */ scr_blindscan_set_status(port, para, progress); return TD_FAILURE; } return TD_SUCCESS; } static td_void adjust_tone_freq_prepare(td_s32 i, td_s32 threshold, td_s32 *tone_frequency) { td_s32 j; td_s32 index; td_u32 agc_start_bound_index; td_u32 agc_stop_bound_index; td_double threshold_start; td_double threshold_stop; /* according to the threstold, recongnize the start freq and stop freq of tone. */ index = g_min_agc[i].freq - SCR_D_SCAN_FREQ_START; for (j = index; j > index - 30; j--) { /* 30:step */ if (g_scr_array[j].agc < threshold) { continue; } if (g_scr_array[j - 1].agc >= threshold) { break; } } soc_log_info("index:%d, scr_array[%d].agc:%#x\n", index, j, g_scr_array[j].agc); agc_start_bound_index = (td_u32)j + 1; threshold_start = (td_double)g_scr_array[agc_start_bound_index].freq; for (j = index; j < index + 30; j++) { /* 30:step */ if (g_scr_array[j].agc < threshold) { continue; } if (g_scr_array[j + 1].agc >= threshold) { break; } } soc_log_info("index:%d, scr_array[%d].agc:%#x\n", index, j, g_scr_array[j].agc); agc_stop_bound_index = (td_u32)j - 1; threshold_stop = (td_double)g_scr_array[agc_stop_bound_index].freq; *tone_frequency = (td_s32)((threshold_start + threshold_stop) / 2.0 + 0.5); /* 2.0:division;0.5:plus */ soc_log_info("tone_freucncy:%d\n", *tone_frequency); soc_log_info("threshold_start(%lf):%f\n", agc_start_bound_index, threshold_start); soc_log_info("threshold_stop(%lf):%f\n", agc_stop_bound_index, threshold_stop); return; } static td_void adjust_tone_freq_set_tone_freq(td_u32 real_ub_number, td_s32 threshold, td_s32 *tone_frequency, td_s32 index) { td_s32 j; soc_log_info("real_ub_number:%u, threshold:%#x\n", real_ub_number, threshold); if (real_ub_number > SCR_USER_BAND_NUMBERS) { soc_log_err("real_ub_number:%u is out of bound:%u\n", real_ub_number, SCR_USER_BAND_NUMBERS); return; } for (j = 1; j < 30; j++) { /* 30:max */ if (((index + j + 1) >= (SCR_D_SCAN_FREQ_END - SCR_D_SCAN_FREQ_START)) || ((index - j - 1) < 0)) { soc_log_err("index:%d is invalid!\n", index); break; } soc_log_info("scr_array[%d].agc:%#x\n", index + j, g_scr_array[index + j].agc); soc_log_info("scr_array[%d].agc:%#x\n", index - j, g_scr_array[index - j].agc); soc_log_info("scr_array[%d].agc:%#x\n", index + j + 1, g_scr_array[index + j + 1].agc); soc_log_info("scr_array[%d].agc:%#x\n", index - j - 1, g_scr_array[index - j - 1].agc); if (g_scr_array[index + j].agc < g_scr_array[index - j].agc) { if (g_scr_array[index + j + 1].agc <= g_scr_array[index - j - 1].agc) { *tone_frequency += 1; break; } } else if (g_scr_array[index + j].agc > g_scr_array[index - j].agc) { if (g_scr_array[index + j + 1].agc >= g_scr_array[index - j - 1].agc) { *tone_frequency -= 1; break; } } else { continue; } } } static td_s32 adjust_tone_freq(td_u32 real_ub_number, td_s32 threshold) { td_u32 real_ub_index; td_s32 index; td_s32 tone_frequency = 0; soc_log_info("real_ub_number:%u, threshold:%#x\n", real_ub_number, threshold); if (real_ub_number > SCR_USER_BAND_NUMBERS) { soc_log_err("real_ub_number:%u is out of bound:%u\n", real_ub_number, SCR_USER_BAND_NUMBERS); return TD_FAILURE; } for (real_ub_index = 0; real_ub_index < real_ub_number; real_ub_index++) { adjust_tone_freq_prepare((td_s32)real_ub_index, threshold, &tone_frequency); /* the next step should base on the lastest tone,not the tone which is sorted by agc. */ index = tone_frequency - SCR_D_SCAN_FREQ_START; /* the center of tone should be even number. */ if ((tone_frequency % 2) != 0) { /* 2:even number */ adjust_tone_freq_set_tone_freq(real_ub_number, threshold, &tone_frequency, index); } g_tone_freq[real_ub_index] = tone_frequency; } return TD_SUCCESS; } static td_s32 scr_blindscan_tone_adjust_freq(td_u32 port, td_s32 threshold, td_u32 real_ub_number, const unicable_scan_para *para) { td_u32 i; td_s32 ret; td_u16 progress; uapi_unicable_scan_user_band_notify notify; uapi_unicable_scan_status unic_status; ret = adjust_tone_freq(real_ub_number, threshold); if (ret != TD_SUCCESS) { soc_log_err("adjust_tone_freq fail.\n"); real_ub_number = SCR_USER_BAND_NUMBERS; } if (real_ub_number > SCR_USER_BAND_NUMBERS) { soc_log_err("real_ub_number:%u is out of bound:%u\n", real_ub_number, SCR_USER_BAND_NUMBERS); return TD_FAILURE; } else { for (i = 0; i < real_ub_number; i++) { if (i < SCR_USER_BAND_NUMBERS) { soc_print("i:%u, u32ToneFreq:%d\n", i, g_tone_freq[i]); } else { soc_log_err("i:%d is out of bound:%u\n", i, SCR_USER_BAND_NUMBERS); return TD_FAILURE; } } } /* Result Storing... */ g_unicable_info.total_ub_number = real_ub_number; if (real_ub_number > SCR_USER_BAND_NUMBERS) { soc_log_warn("real_ub_number:%u is out of bound:%u\n", real_ub_number, SCR_USER_BAND_NUMBERS); real_ub_number = SCR_USER_BAND_NUMBERS; } for (i = 0; i < real_ub_number; i++) { g_unicable_info.ub_info[i].scr_no = i; g_unicable_info.ub_info[i].center_freq = g_tone_freq[i]; } g_unicable_info.ub_index = 0; progress = 100; /* 100:percent */ scr_blindscan_set_status(port, para, progress); unic_status = UAPI_UNICABLE_SCAN_STATUS_FINISH; notify.status = &unic_status; para->unic_scan_para.evt_notify(port, UAPI_UNICABLE_SCAN_EVT_STATUS, ¬ify); return TD_SUCCESS; } static td_s32 scr_blindscan_tone(const td_void *scan_para) { td_s32 ret; td_s32 count = 0; td_s32 threshold; td_u32 port; td_u32 real_ub_number = 0; unicable_scan_para para; if (scan_para == TD_NULL) { soc_log_err("Input parameter(scan_para)invalid.\n"); return SOC_ERR_FRONTEND_INVALID_PARA; } para = *(unicable_scan_para *)scan_para; port = para.port; ret = memset_s(g_scr_array, sizeof(g_scr_array), 0x77, sizeof(g_scr_array)); if (ret != EOK) { soc_log_err("call memset_s func error. sec_ret:%d\n", ret); return TD_FAILURE; } ret = scr_blindscan_tone_first_check(port, &threshold, &real_ub_number, &count, ¶); if (ret != TD_SUCCESS) { soc_log_err("scr_blindscan_tone_first_check failed.\n"); return TD_FAILURE; } ret = scr_blindscan_tone_second_check(port, real_ub_number, &count, ¶); if (ret != TD_SUCCESS) { soc_log_err("scr_blindscan_tone_second_check failed.\n"); return TD_FAILURE; } ret = scr_blindscan_tone_adjust_freq(port, threshold, real_ub_number, ¶); if (ret != TD_SUCCESS) { soc_log_err("scr_blindscan_tone_adjust_freq failed.\n"); return TD_FAILURE; } return TD_SUCCESS; } td_s32 uapi_unicable_user_band_scan_start(td_u32 port, uapi_unicable_scan_para scan_para) { static unicable_scan_para local_scan_para = {0}; td_s32 result; pthread_t unicable_scan_thread; if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (scan_para.evt_notify == TD_NULL) { soc_log_err("Input parameter(evt_notify) invalid\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } local_scan_para.port = port; local_scan_para.unic_scan_para = scan_para; result = scr_enable_tone(port); if (result != TD_SUCCESS) { soc_log_err("scr_enable_tone fail.\n"); return TD_FAILURE; } fe_usleep(2 * 1000); // 2 1000 : us g_unicable_stop = 0; result = pthread_create(&unicable_scan_thread, 0, (td_void *)scr_blindscan_tone, &local_scan_para); if (result != TD_SUCCESS) { soc_log_err("Create pthread fail.\n"); return TD_FAILURE; } pthread_detach(unicable_scan_thread); return TD_SUCCESS; } td_s32 uapi_unicable_user_band_scan_stop(td_u32 port) { if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } g_unicable_stop = 1; return TD_SUCCESS; } td_s32 uapi_unicable_get_user_bands_num(td_u32 port, td_u32 *ub_num) { if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (ub_num == TD_NULL) { soc_log_err("data is null ptr.\n"); return TD_FAILURE; } *ub_num = g_unicable_info.total_ub_number; return TD_SUCCESS; } td_s32 uapi_unicable_get_user_band_info(td_u32 port, uapi_unicable_scr_ub *ub_info, td_u32 ub_info_num, td_u32 *num) { td_s32 ret; if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%d) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (ub_info == TD_NULL) { soc_log_err("data is null ptr.\n"); return TD_FAILURE; } if (num == TD_NULL) { soc_log_err("data is null ptr.\n"); return TD_FAILURE; } if (ub_info_num == 0) { soc_log_err("ub_info_num is 0.\n"); return TD_FAILURE; } *num = (g_unicable_info.total_ub_number > ub_info_num) ? ub_info_num : g_unicable_info.total_ub_number; ret = memcpy_s(ub_info, ub_info_num * sizeof(uapi_unicable_scr_ub), g_unicable_info.ub_info, *num * sizeof(uapi_unicable_scr_ub)); if (ret != EOK) { return SOC_ERR_FRONTEND_SECURE_CHECK; } return TD_SUCCESS; }