You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

972 lines
29 KiB

/*
* 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 <pthread.h>
#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 = &notify_progress;
if (para->unic_scan_para.evt_notify != NULL) {
para->unic_scan_para.evt_notify(port, UAPI_UNICABLE_SCAN_EVT_PROGRESS, &notify);
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, &notify);
}
}
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, &notify);
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, &notify);
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, &para);
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, &para);
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, &para);
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;
}