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
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 = ¬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;
|
|
}
|
|
|