/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2017-2021. All rights reserved. * Description: TER IAPI Interface * Author: Hisilicon * Created: 2017-06-30 */ #include #include #include "soc_log.h" #include "soc_errno.h" #include "securec.h" #include "mpi_memory_ext.h" #include "mpi_frontend_ext.h" #include "iapi_frontend.h" #include "iapi_ter.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif /* __cplusplus */ /* DVB-T2 */ ter_nordig_p1 g_cn_nordig_p1_dvbt2[4][6] = { /* 4:size,6:size */ { { EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_1_2, 3.5 }, /* 3.5:define */ { EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_3_5, 4.7 }, /* 4.7:define */ { EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_2_3, 5.6 }, /* 5.6:define */ { EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_3_4, 6.6 }, /* 6.6:define */ { EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_4_5, 7.2 }, /* 7.2:define */ { EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_5_6, 7.7 } /* 7.7:define */ }, { { EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_1_2, 8.7 }, /* 8.7:define */ { EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_3_5, 10.1 }, /* 10.1:define */ { EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_2_3, 11.4 }, /* 11.4:define */ { EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_3_4, 12.5 }, /* 12.5:define */ { EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_4_5, 13.3 }, /* 13.3:define */ { EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_5_6, 13.8 } /* 13.8:define */ }, { { EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_1_2, 13.0 }, /* 13.0:define */ { EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_3_5, 14.8 }, /* 14.8:define */ { EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_2_3, 16.2 }, /* 16.2:define */ { EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_3_4, 17.7 }, /* 17.7:define */ { EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_4_5, 18.7 }, /* 18.7:define */ { EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_5_6, 19.4 } /* 19.4:define */ }, { { EXT_DRV_MOD_TYPE_QAM_256, EXT_DRV_FRONTEND_FEC_RATE_1_2, 17.0 }, /* 17.0:define */ { EXT_DRV_MOD_TYPE_QAM_256, EXT_DRV_FRONTEND_FEC_RATE_3_5, 19.4 }, /* 19.4:define */ { EXT_DRV_MOD_TYPE_QAM_256, EXT_DRV_FRONTEND_FEC_RATE_2_3, 20.8 }, /* 20.8:define */ { EXT_DRV_MOD_TYPE_QAM_256, EXT_DRV_FRONTEND_FEC_RATE_3_4, 22.9 }, /* 22.9:define */ { EXT_DRV_MOD_TYPE_QAM_256, EXT_DRV_FRONTEND_FEC_RATE_4_5, 24.3 }, /* 24.3:define */ { EXT_DRV_MOD_TYPE_QAM_256, EXT_DRV_FRONTEND_FEC_RATE_5_6, 25.1 } /* 25.1:define */ } }; /* DVB-T */ ter_nordig_p1 g_cn_nordig_p1_dvbt[3][5] = { /* 3:index;5:index */ { {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_1_2, 5.1}, /* 5.1:define */ {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_2_3, 6.9}, /* 6.9:define */ {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_3_4, 7.9}, /* 7.9:define */ {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_5_6, 8.9}, /* 8.9:define */ {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_7_8, 9.7} /* 9.7:define */ }, { {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_1_2, 10.8}, /* 10.8:define */ {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_2_3, 13.1}, /* 13.1:define */ {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_3_4, 14.6}, /* 14.6:define */ {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_5_6, 15.6}, /* 15.6:define */ {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_7_8, 16} /* 16:define */ }, { {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_1_2, 16.5}, /* 16.5:define */ {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_2_3, 18.7}, /* 18.7:define */ {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_3_4, 20.2}, /* 20.2:define */ {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_5_6, 21.6}, /* 21.6:define */ {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_7_8, 21.5} /* 21.5:define */ } }; /* ISDB-T */ ter_nordig_p1 g_cn_nordig_p1_isdbt[4][5] = { /* 4:index;5:index */ { {EXT_DRV_MOD_TYPE_DQPSK, EXT_DRV_FRONTEND_FEC_RATE_1_2, (5.1 + 3)}, /* 5.1:define,3:plus */ {EXT_DRV_MOD_TYPE_DQPSK, EXT_DRV_FRONTEND_FEC_RATE_2_3, (6.9 + 3)}, /* 6.9:define,3:plus */ {EXT_DRV_MOD_TYPE_DQPSK, EXT_DRV_FRONTEND_FEC_RATE_3_4, (7.9 + 3)}, /* 7.9:define,3:plus */ {EXT_DRV_MOD_TYPE_DQPSK, EXT_DRV_FRONTEND_FEC_RATE_5_6, (8.9 + 3)}, /* 8.9:define,3:plus */ {EXT_DRV_MOD_TYPE_DQPSK, EXT_DRV_FRONTEND_FEC_RATE_7_8, (9.7 + 3)} /* 9.7:define,3:plus */ }, { {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_1_2, 5.1}, /* 5.1:define */ {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_2_3, 6.9}, /* 6.9:define */ {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_3_4, 7.9}, /* 7.9:define */ {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_5_6, 8.9}, /* 8.9:define */ {EXT_DRV_MOD_TYPE_QPSK, EXT_DRV_FRONTEND_FEC_RATE_7_8, 9.7} /* 9.7:define */ }, { {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_1_2, 10.8}, /* 10.8:define */ {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_2_3, 13.1}, /* 13.1:define */ {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_3_4, 14.6}, /* 14.6:define */ {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_5_6, 15.6}, /* 15.6:define */ {EXT_DRV_MOD_TYPE_QAM_16, EXT_DRV_FRONTEND_FEC_RATE_7_8, 16} /* 16:define */ }, { {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_1_2, 16.5}, /* 16.5:define */ {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_2_3, 18.7}, /* 18.7:define */ {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_3_4, 20.2}, /* 20.2:define */ {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_5_6, 21.6}, /* 21.6:define */ {EXT_DRV_MOD_TYPE_QAM_64, EXT_DRV_FRONTEND_FEC_RATE_7_8, 21.5} /* 21.5:define */ } }; /* DTMB */ ter_nordig_p1_dtmb g_cn_nordig_p1_dtmb[5][3] = { /* 5:index;3:index */ { {EXT_DRV_FRONTEND_DTMB_QAM_4QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_4, 3.5}, /* 3.5:define */ {EXT_DRV_FRONTEND_DTMB_QAM_4QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_6, 4.7}, /* 4.7:define */ {EXT_DRV_FRONTEND_DTMB_QAM_4QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_8, 7.2} /* 7.2:define */ }, { {EXT_DRV_FRONTEND_DTMB_QAM_16QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_4, 8.7}, /* 8.7:define */ {EXT_DRV_FRONTEND_DTMB_QAM_16QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_6, 10.1}, /* 10.1:define */ {EXT_DRV_FRONTEND_DTMB_QAM_16QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_8, 13.3} /* 13.3:define */ }, { {EXT_DRV_FRONTEND_DTMB_QAM_32QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_4, 10.8}, /* 10.8:define */ {EXT_DRV_FRONTEND_DTMB_QAM_32QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_6, 12.5}, /* 12.5:define */ {EXT_DRV_FRONTEND_DTMB_QAM_32QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_8, 15.5} /* 15.5:define */ }, { {EXT_DRV_FRONTEND_DTMB_QAM_64QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_4, 13.0}, /* 13.0:define */ {EXT_DRV_FRONTEND_DTMB_QAM_64QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_6, 14.8}, /* 14.8:define */ {EXT_DRV_FRONTEND_DTMB_QAM_64QAM, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_8, 18.7} /* 18.7:define */ }, { {EXT_DRV_FRONTEND_DTMB_QAM_4QAM_NR, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_8, 6.5}, /* 6.5:define */ {EXT_DRV_FRONTEND_DTMB_QAM_4QAM_NR, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_8, 6.5}, /* 6.5:define */ {EXT_DRV_FRONTEND_DTMB_QAM_4QAM_NR, EXT_DRV_FRONTEND_DTMB_CODE_RATE_0_DOT_8, 6.5} /* 6.5:define */ } }; static td_void *ter_connect_detect_execute(td_void *signal) { td_s32 ret; static fe_ioctrl_signal fe_signal; if (signal == TD_NULL) { soc_log_err("Input parameter(pstSignal) invalid.\n"); return (td_void*)TD_NULL; } fe_signal = *(fe_ioctrl_signal*)signal; ret = ext_mpi_frontend_connect(&fe_signal); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_connect, ret); return (td_void*)TD_NULL; } return (td_void*)TD_NULL; } static td_s32 ter_connect_config(td_u32 port, const uapi_frontend_connect_para *connect_para, fe_ioctrl_signal *signal) { frontend_acc_qam_params tuner_para = {0}; if (connect_para->sig_type == (UAPI_FRONTEND_SIG_TYPE_DVB_T | UAPI_FRONTEND_SIG_TYPE_DVB_T2)) { signal->sig_type = EXT_DRV_FRONTEND_SIG_TYPE_DVB_T2; tuner_para.dvbt_mode = 2; /* 2:t/t2 auto */ } else if (connect_para->sig_type == UAPI_FRONTEND_SIG_TYPE_DVB_T) { signal->sig_type = EXT_DRV_FRONTEND_SIG_TYPE_DVB_T; tuner_para.dvbt_mode = 1; tuner_para.ter.dvbt = (ext_drv_frontend_dvbt_ts_priority)connect_para->connect_para.ter.dvbt_prio; } else if (connect_para->sig_type == UAPI_FRONTEND_SIG_TYPE_DVB_T2) { signal->sig_type = EXT_DRV_FRONTEND_SIG_TYPE_DVB_T2; tuner_para.dvbt_mode = 0; tuner_para.ter.dvbt2.channel_attr = (ext_drv_frontend_dvbt2_mode)connect_para->connect_para.ter.channel_mode; tuner_para.ter.dvbt2.plp_id = connect_para->connect_para.ter.plp_param.plp_id; tuner_para.ter.dvbt2.comm_plp_id = connect_para->connect_para.ter.plp_param.comm_plp_id; tuner_para.ter.dvbt2.combination = connect_para->connect_para.ter.plp_param.combination; } else { signal->sig_type = (ext_drv_frontend_sig_type)connect_para->sig_type; } tuner_para.frequency = connect_para->connect_para.ter.freq; tuner_para.srbw.band_width = connect_para->connect_para.ter.band_width; tuner_para.si = connect_para->connect_para.ter.reverse; tuner_para.sync_lock_status = EXT_DRV_FRONTEND_LOCK_STATUS_MAX; tuner_para.scramble_code = 0; signal->port = port; signal->signal = tuner_para; return TD_SUCCESS; } static td_s32 ter_connect_detect_create(td_u32 port, fe_ioctrl_signal *signal) { td_s32 ret; static pthread_t* ter_signal_detect = TD_NULL; /* terr signal detect thread */ if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%u) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } soc_log_dbg("Creat TerSignalDetect thread to run connect.\n"); if (ter_signal_detect != TD_NULL) { (td_void)pthread_join(*ter_signal_detect, TD_NULL); free(ter_signal_detect); ter_signal_detect = TD_NULL; } ter_signal_detect = (pthread_t*)malloc(sizeof(pthread_t)); if (ter_signal_detect == TD_NULL) { soc_log_err("No memory to creat TerSignalDetect thread.\n"); return SOC_ERR_FRONTEND_MEM_ALLOC_FAIL; } ret = memset_s(ter_signal_detect, sizeof(pthread_t), 0, sizeof(pthread_t)); if (ret != TD_SUCCESS) { free(ter_signal_detect); ter_signal_detect = TD_NULL; return SOC_ERR_FRONTEND_ERR_UNKNOWN; } ret = pthread_create(ter_signal_detect, 0, ter_connect_detect_execute, signal); if (ret != TD_SUCCESS) { soc_log_err("Create pthread failed.\n"); if (ter_signal_detect != TD_NULL) { free(ter_signal_detect); ter_signal_detect = TD_NULL; } return TD_FAILURE; } return TD_SUCCESS; } static td_s32 ter_connect_execute(td_u32 port, fe_ioctrl_signal *fe_signal, td_u32 time_out) { td_s32 ret; td_u32 time_span = 0; fe_ioctrl_status fe_status = {0}; ret = ext_mpi_frontend_connect(fe_signal); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_connect, ret); return ret; } /* if demod sync is not ok,do not need to get fec status */ soc_dbg_print_u32(fe_signal->signal.sync_lock_status); if (fe_signal->signal.sync_lock_status == EXT_DRV_FRONTEND_LOCK_STATUS_DROPPED) { soc_log_dbg("Sync is not ok,so tell the locked status immediately.\n"); return SOC_ERR_FRONTEND_CONNECT_FAIL; } if (time_out == 0) { return TD_SUCCESS; } fe_status.port = port; while (time_span < time_out) { ret = ext_mpi_frontend_get_status(&fe_status); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_get_status, ret); return ret; } if (fe_status.lock_status == EXT_DRV_FRONTEND_LOCK_STATUS_LOCKED) { return TD_SUCCESS; } else { fe_usleep(10 * 1000); /* 10:sleep,1000:multi */ time_span += 10; /* 10:step */ } } /* Timeout return Failed */ return SOC_ERR_FRONTEND_CONNECT_FAIL; } td_s32 ter_connect(td_u32 tuner_id, const uapi_frontend_connect_para *connect_para, td_u32 time_out) { td_s32 ret; static fe_ioctrl_signal signal; if (connect_para == TD_NULL) { soc_log_err("Input parameter(connect_para)invalid.\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } soc_log_dbg("ter_connect\n"); if ((connect_para->connect_para.ter.freq < TER_RF_MIN) || (connect_para->connect_para.ter.freq > TER_RF_MAX)) { soc_log_err("connect_para->connect_para.ter.freq invalid.\n"); soc_err_print_u32(connect_para->connect_para.ter.freq); return SOC_ERR_FRONTEND_INVALID_PARA; } if ((connect_para->connect_para.ter.band_width < TER_BW_MIN) || (connect_para->connect_para.ter.band_width > TER_BW_MAX)) { soc_log_err("connect_para->connect_para.ter.band_width invalid.\n"); soc_err_print_u32(connect_para->connect_para.ter.band_width); return SOC_ERR_FRONTEND_INVALID_PARA; } ret = ter_connect_config(tuner_id, connect_para, &signal); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_connect_config, ret); return ret; } soc_dbg_print_u32(time_out); if (time_out == 0) { ret = ter_connect_detect_create(tuner_id, &signal); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_connect_detect_create, ret); return ret; } } else { ret = ter_connect_execute(tuner_id, &signal, time_out); if ((ret != TD_SUCCESS)) { return ret; } else { return TD_SUCCESS; } } return TD_SUCCESS; } td_s32 ter_connect_t_t2_auto(td_u32 tuner_id, const uapi_frontend_connect_para *connect_para, td_u32 time_out) { td_s32 ret; static fe_ioctrl_signal signal; if (connect_para == TD_NULL) { soc_log_err("Input parameter(connect_para)invalid.\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } soc_log_dbg("ter_connect\n"); if ((connect_para->connect_para.ter.freq < TER_RF_MIN) || (connect_para->connect_para.ter.freq > TER_RF_MAX)) { soc_log_err("connect_para->connect_para.ter.freq invalid.\n"); soc_err_print_u32(connect_para->connect_para.ter.freq); return SOC_ERR_FRONTEND_INVALID_PARA; } if ((connect_para->connect_para.ter.band_width < TER_BW_MIN) || (connect_para->connect_para.ter.band_width > TER_BW_MAX)) { soc_log_err("connect_para->connect_para.ter.band_width invalid.\n"); soc_err_print_u32(connect_para->connect_para.ter.band_width); return SOC_ERR_FRONTEND_INVALID_PARA; } ret = ter_connect_config(tuner_id, connect_para, &signal); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_connect_config, ret); return ret; } soc_dbg_print_u32(time_out); ret = ter_connect_execute(tuner_id, &signal, time_out); if ((ret != TD_SUCCESS)) { return ret; } else { return TD_SUCCESS; } return TD_SUCCESS; } static td_s32 ter_get_signal_quality_dvbt_nording_ref(td_u32 port, td_double *nordig_reference) { td_s32 ret; td_u8 i, j; fe_ioctrl_signal_info fe_signal_info = {0}; ext_drv_modulation_type qam_index; ext_drv_frontend_fec_rate code_rate; fe_signal_info.port = port; ret = ext_mpi_frontend_get_signal_info(&fe_signal_info); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_get_signal_info, ret); return ret; } qam_index = fe_signal_info.info.signal_info.dvbt.mod_type; code_rate = fe_signal_info.info.signal_info.dvbt.fec_rate; for (i = 0; i < array_size(g_cn_nordig_p1_dvbt); i++) { if (qam_index != g_cn_nordig_p1_dvbt[i][0].modulation) { continue; } for (j = 0; j < array_size(g_cn_nordig_p1_dvbt[0]); j++) { if (code_rate == g_cn_nordig_p1_dvbt[i][j].fec_rate) { *nordig_reference = g_cn_nordig_p1_dvbt[i][j].nordig_p1; soc_dbg_print_u32(*nordig_reference); break; } } } return TD_SUCCESS; } static td_s32 ter_get_signal_quality_dvbt2_nording_ref(td_u32 port, td_double *nordig_reference) { td_s32 ret; td_u8 i, j; fe_ioctrl_signal_info fe_signal_info = {0}; ext_drv_modulation_type qam_index; ext_drv_frontend_fec_rate code_rate; fe_signal_info.port = port; ret = ext_mpi_frontend_get_signal_info(&fe_signal_info); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_get_signal_info, ret); return ret; } qam_index = fe_signal_info.info.signal_info.dvbt2.mod_type; code_rate = fe_signal_info.info.signal_info.dvbt2.fec_rate; for (i = 0; i < array_size(g_cn_nordig_p1_dvbt2); i++) { if (qam_index != g_cn_nordig_p1_dvbt2[i][0].modulation) { break; } for (j = 0; j < array_size(g_cn_nordig_p1_dvbt2[0]); j++) { if (code_rate == g_cn_nordig_p1_dvbt2[i][j].fec_rate) { *nordig_reference = g_cn_nordig_p1_dvbt2[i][j].nordig_p1; soc_dbg_print_u32(*nordig_reference); break; } } } return TD_SUCCESS; } static td_s32 ter_get_signal_quality_dvbt(td_u32 port, td_double snr, td_double ber, td_u32 *signal_quality) { td_s32 ret; td_double cn_relative; td_double nordig_reference = 0; td_double tmp_ber; td_double tmp_ber_sqi; ret = ter_get_signal_quality_dvbt_nording_ref(port, &nordig_reference); if (ret != TD_SUCCESS) { soc_log_err("ter_get_signal_quality_dvbt_nording_ref failed\n"); return TD_FAILURE; } cn_relative = snr - nordig_reference; soc_dbg_print_float(cn_relative); tmp_ber = ber; soc_dbg_print_float(tmp_ber); if ((tmp_ber * 1000) > 1) { /* 1000:multi */ tmp_ber_sqi = 0; } else if ((tmp_ber * 10000000) <= 1) { /* 10000000:multi */ tmp_ber_sqi = 100; /* 100:ber_sqi */ } else { tmp_ber_sqi = 20 * log10(1 / tmp_ber) - 40; /* 20:multi;40:sub */ } soc_dbg_print_float(tmp_ber_sqi); /* according to C/Nrea, calculate SQI */ if (cn_relative < -7.0) { /* 7.0:limit */ *signal_quality = 0; } else if (cn_relative > 3.0) { /* 3.0:limit */ *signal_quality = tmp_ber_sqi; } else { *signal_quality = (((cn_relative - 3) / 10) + 1) * tmp_ber_sqi; /* 3:sub,10:div */ } *signal_quality = (*signal_quality > 100) ? 100 : *signal_quality; /* 100:quality,100:qulity */ soc_dbg_print_u32(*signal_quality); return TD_SUCCESS; } static td_s32 ter_get_signal_quality_dvbt2(td_u32 port, td_double snr, td_double ber, td_u32 *signal_quality) { td_s32 ret; td_double cn_relative; td_double nordig_reference = 0; td_double tmp_ber; td_double tmp_ber_sqi; ret = ter_get_signal_quality_dvbt2_nording_ref(port, &nordig_reference); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_dvbt2_nording_ref, ret); return ret; } cn_relative = snr - nordig_reference; soc_dbg_print_float(cn_relative); tmp_ber = ber; soc_dbg_print_float(tmp_ber); if ((tmp_ber * 10000) > 1) { /* 10000:multi */ tmp_ber_sqi = 0; } else if ((tmp_ber * 10000000) <= 1) { /* 10000000:multi */ tmp_ber_sqi = ((td_double)100) / 6; /* 100:div,6:div */ } else { tmp_ber_sqi = ((td_double)100) / 15; /* 100:div,15:div */ } soc_dbg_print_float(tmp_ber_sqi); /* according to C/Nrea, calculate SQI */ if (cn_relative < -3.0) { /* 3.0:limit */ *signal_quality = 0; } else if (cn_relative > 3.0) { /* 3.0:limit */ *signal_quality = 100; /* 100:quality */ } else { *signal_quality = (cn_relative + 3) * tmp_ber_sqi; /* 3:plus */ } *signal_quality = (*signal_quality > 100) ? 100 : *signal_quality; /* 100:quality,100:qulity */ soc_dbg_print_u32(*signal_quality); return TD_SUCCESS; } static td_s32 ter_get_signal_quality_isdbt_tmcc_info_normal(td_u32 exist_flag, const ext_drv_frontend_isdbt_tmcc_info *tmcc_info, ext_drv_modulation_type *mod_type, ext_drv_frontend_fec_rate *fec_rate) { if (exist_flag == 0x7 && tmcc_info->isdbt_layers_c_info_bits.layer_seg_num != 0) { *mod_type = tmcc_info->isdbt_layers_c_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_c_info_bits.layer_fec_rate; } else if (exist_flag == 0x7 && tmcc_info->isdbt_layers_b_info_bits.layer_seg_num != 0) { *mod_type = tmcc_info->isdbt_layers_b_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_b_info_bits.layer_fec_rate; } else if (exist_flag == 0x3 && tmcc_info->isdbt_layers_b_info_bits.layer_seg_num != 0) { *mod_type = tmcc_info->isdbt_layers_b_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_b_info_bits.layer_fec_rate; } else if (exist_flag == 0x5 && tmcc_info->isdbt_layers_c_info_bits.layer_seg_num != 0) { *mod_type = tmcc_info->isdbt_layers_c_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_c_info_bits.layer_fec_rate; } else if (exist_flag == 0x7 || exist_flag == 0x3 || exist_flag == 0x1 || exist_flag == 0x5) { *mod_type = tmcc_info->isdbt_layers_a_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_a_info_bits.layer_fec_rate; } return TD_SUCCESS; } static td_s32 ter_get_signal_quality_isdbt_tmcc_info_extra(td_u32 exist_flag, const ext_drv_frontend_isdbt_tmcc_info *tmcc_info, ext_drv_modulation_type *mod_type, ext_drv_frontend_fec_rate *fec_rate) { if (exist_flag == 0x6) { if (tmcc_info->isdbt_layers_c_info_bits.layer_seg_num != 0) { *mod_type = tmcc_info->isdbt_layers_c_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_c_info_bits.layer_fec_rate; } else { *mod_type = tmcc_info->isdbt_layers_b_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_b_info_bits.layer_fec_rate; } } else if (exist_flag == 0x4) { *mod_type = tmcc_info->isdbt_layers_c_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_c_info_bits.layer_fec_rate; } else if (exist_flag == 0x2) { *mod_type = tmcc_info->isdbt_layers_b_info_bits.layer_mod_type; *fec_rate = tmcc_info->isdbt_layers_b_info_bits.layer_fec_rate; } return TD_SUCCESS; } td_s32 ter_get_signal_quality_isdbt_tmcc_info(td_u32 exist_flag, const ext_drv_frontend_isdbt_tmcc_info *tmcc_info, ext_drv_modulation_type *mod_type, ext_drv_frontend_fec_rate *fec_rate) { td_s32 ret; /* Actually, there are three modes in the general : A/AB/ABC. */ if ((exist_flag == 0x1) || (exist_flag == 0x3) || (exist_flag == 0x5) || (exist_flag == 0x7)) { ret = ter_get_signal_quality_isdbt_tmcc_info_normal(exist_flag, tmcc_info, mod_type, fec_rate); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_isdbt_tmcc_info_normal, ret); return ret; } } else if ((exist_flag == 0x2) || (exist_flag == 0x4) || (exist_flag == 0x6)) { ret = ter_get_signal_quality_isdbt_tmcc_info_extra(exist_flag, tmcc_info, mod_type, fec_rate); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_isdbt_tmcc_info_extra, ret); return ret; } } else { soc_log_err("Layer info is not correct!\n"); soc_dbg_print_h32(exist_flag); return SOC_ERR_FRONTEND_INVALID_PARA; } return TD_SUCCESS; } static td_s32 ter_get_signal_quality_isdbt_nording_ref(td_u32 port, td_double *nordig_reference) { td_s32 ret; td_u8 i, j; td_u32 exist_flag; fe_ioctrl_signal_info fe_signal_info = {0}; ext_drv_frontend_isdbt_tmcc_info *tmcc_info = NULL; ext_drv_modulation_type mod_type; ext_drv_frontend_fec_rate fec_rate; fe_signal_info.port = port; ret = ext_mpi_frontend_get_signal_info(&fe_signal_info); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_get_signal_info, ret); return ret; } exist_flag = fe_signal_info.info.signal_info.isdbt.isdbt_layers.existance_flag; tmcc_info = &fe_signal_info.info.signal_info.isdbt.isdbt_tmcc_info; ret = ter_get_signal_quality_isdbt_tmcc_info(exist_flag, tmcc_info, &mod_type, &fec_rate); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_isdbt_tmcc_info, ret); return ret; } soc_dbg_print_u32(mod_type); soc_dbg_print_u32(fec_rate); for (i = 0; i < 4; i++) { /* 4:g_cn_nordig_p1_isdbt line */ if (mod_type != g_cn_nordig_p1_isdbt[i][0].modulation) { continue; } for (j = 0; j < 5; j++) { /* 5:g_cn_nordig_p1_isdbt col */ if (g_cn_nordig_p1_isdbt[i][j].fec_rate == fec_rate) { *nordig_reference = g_cn_nordig_p1_isdbt[i][j].nordig_p1; soc_dbg_print_float(*nordig_reference); break; } } } return TD_SUCCESS; } static td_s32 ter_get_signal_quality_isdbt(td_u32 port, td_double snr, td_double ber, td_u32 *signal_quality) { td_s32 ret; td_double cn_relative; td_double nordig_reference = 0; td_double tmp_ber; td_double tmp_ber_sqi; ret = ter_get_signal_quality_isdbt_nording_ref(port, &nordig_reference); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_isdbt_nording_ref, ret); return ret; } cn_relative = snr - nordig_reference; soc_dbg_print_float(cn_relative); tmp_ber = ber; soc_dbg_print_float(tmp_ber); if ((tmp_ber * 1000) > 1) { /* 1000:multi */ tmp_ber_sqi = 0; } else if ((tmp_ber * 10000000) <= 1) { /* 10000000:multi */ tmp_ber_sqi = 100; /* 100:ber_sqi */ } else { tmp_ber_sqi = 20 * log10(1 / tmp_ber) - 40; /* 20:multi;40:sub */ } soc_dbg_print_float(tmp_ber_sqi); /* according to C/Nrea, calculate SQI */ if (cn_relative < -7.0) { /* -7.0:limit */ *signal_quality = 0; } else if (cn_relative > 3.0) { /* 3.0:limit */ *signal_quality = tmp_ber_sqi; } else { *signal_quality = (((cn_relative - 3) / 10) + 1) * tmp_ber_sqi; /* 3:sub,10:div */ } *signal_quality = (*signal_quality > 100) ? 100 : *signal_quality; /* 100:quality,100:qulity */ soc_dbg_print_u32(*signal_quality); return TD_SUCCESS; } static td_s32 ter_get_signal_quality_dtmb_nording_ref(td_u32 port, td_double *nordig_reference) { td_s32 ret; td_u8 i, j; fe_ioctrl_signal_info fe_signal_info = {0}; ext_drv_frontend_dtmb_qam qam_index; ext_drv_frontend_dtmb_code_rate code_rate; fe_signal_info.port = port; ret = ext_mpi_frontend_get_signal_info(&fe_signal_info); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_get_signal_info, ret); return ret; } qam_index = fe_signal_info.info.signal_info.dtmb.qam_index; code_rate = fe_signal_info.info.signal_info.dtmb.code_rate; for (i = 0; i < 5; i++) { /* 5:g_cn_nordig_p1_dtmb line */ if (qam_index != g_cn_nordig_p1_dtmb[i][0].modulation) { continue; } for (j = 0; j < 3; j++) { /* 3:g_cn_nordig_p1_dtmb col */ if (code_rate == g_cn_nordig_p1_dtmb[i][j].fec_rate) { *nordig_reference = g_cn_nordig_p1_dtmb[i][j].nordig_p1; soc_dbg_print_float(*nordig_reference); break; } } } return TD_SUCCESS; } static td_s32 ter_get_signal_quality_dtmb(td_u32 port, td_double snr, td_double ber, td_u32 *signal_quality) { td_s32 ret; td_double cn_relative; td_double nordig_reference = 0; td_double tmp_ber; td_double tmp_ber_sqi; ret = ter_get_signal_quality_dtmb_nording_ref(port, &nordig_reference); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_dtmb_nording_ref, ret); return ret; } cn_relative = snr - nordig_reference; soc_dbg_print_float(cn_relative); tmp_ber = ber; soc_dbg_print_float(tmp_ber); if ((tmp_ber * 1000) > 1) { /* 1000:multi */ tmp_ber_sqi = 0; } else if ((tmp_ber * 10000000) <= 1) { /* 10000000:multi */ tmp_ber_sqi = 100; /* 100:ber_sqi */ } else { tmp_ber_sqi = 20 * log10(1 / tmp_ber) - 40; /* 20:multi;40:sub */ } soc_dbg_print_float(tmp_ber_sqi); /* according to C/Nrea, calculate SQI */ if (cn_relative < -7.0) { /* -7.0:limit */ *signal_quality = 0; } else if (cn_relative > 3.0) { /* 3.0:limit */ *signal_quality = tmp_ber_sqi; } else { *signal_quality = (((cn_relative - 3) / 10) + 1) * tmp_ber_sqi; /* 3:sub,10:div */ } *signal_quality = (*signal_quality > 100) ? 100 : *signal_quality; /* 100:quality,100:qulity */ soc_dbg_print_u32(*signal_quality); return TD_SUCCESS; } static td_s32 ter_get_signal_quality_atsc(td_u32 port, td_double snr, td_double ber, td_u32 *signal_quality) { td_double cn_relative; td_double tmp_ber; td_double tmp_ber_sqi; if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(tuner_id) invalid.\n"); soc_err_print_u32(port); return SOC_ERR_FRONTEND_INVALID_PARA; } cn_relative = snr - 15.6; /* 15.6:sub */ soc_dbg_print_float(cn_relative); tmp_ber = ber; soc_dbg_print_float(tmp_ber); if ((tmp_ber * 1000) > 1) { /* 1000:multi */ tmp_ber_sqi = 0; } else if ((tmp_ber * 10000000) <= 1) { /* 10000000:multi */ tmp_ber_sqi = 100; /* 100:ber_sqi */ } else { tmp_ber_sqi = 20 * log10(1 / tmp_ber) - 40; /* 20:multi;40:sub */ } soc_dbg_print_float(tmp_ber_sqi); /* according to C/Nrea, calculate SQI */ if (cn_relative < -7.0) { /* -7.0:limit */ *signal_quality = 0; } else if (cn_relative > 3.0) { /* 3.0:limit */ *signal_quality = tmp_ber_sqi; } else { *signal_quality = (((cn_relative - 3) / 10) + 1) * tmp_ber_sqi; /* 3:sub,10:div */ } *signal_quality = (*signal_quality > 100) ? 100 : *signal_quality; /* 100:quality,100:qulity */ soc_dbg_print_u32(*signal_quality); return TD_SUCCESS; } td_s32 ter_get_signal_quality(td_u32 tuner_id, td_double snr, td_double ber, td_u32 *signal_quality) { td_s32 ret; uapi_frontend_attr tuner_attr = {0}; ret = tuner_get_attr_execute(tuner_id, &tuner_attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(tuner_get_attr_execute, ret); return ret; } if (tuner_attr.sig_type == UAPI_FRONTEND_SIG_TYPE_DVB_T) { ret = ter_get_signal_quality_dvbt(tuner_id, snr, ber, signal_quality); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_dvbt, ret); return ret; } } else if (tuner_attr.sig_type == UAPI_FRONTEND_SIG_TYPE_DVB_T2) { ret = ter_get_signal_quality_dvbt2(tuner_id, snr, ber, signal_quality); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_dvbt2, ret); return ret; } } else if (tuner_attr.sig_type == UAPI_FRONTEND_SIG_TYPE_ISDB_T) { ret = ter_get_signal_quality_isdbt(tuner_id, snr, ber, signal_quality); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_isdbt, ret); return ret; } } else if (tuner_attr.sig_type == UAPI_FRONTEND_SIG_TYPE_DTMB) { ret = ter_get_signal_quality_dtmb(tuner_id, snr, ber, signal_quality); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_dtmb, ret); return ret; } } else if (tuner_attr.sig_type == UAPI_FRONTEND_SIG_TYPE_ATSC_T) { ret = ter_get_signal_quality_atsc(tuner_id, snr, ber, signal_quality); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ter_get_signal_quality_atsc, ret); return ret; } } else { soc_log_err("do not support signal\n"); soc_dbg_print_u32(tuner_attr.sig_type); return SOC_ERR_FRONTEND_PARA_NOT_SUPPORT; } return TD_SUCCESS; } td_s32 uapi_frontend_get_plp_num(td_u32 port, td_u8 *plp_num) { td_s32 ret; fe_ioctrl_plp_num fe_plp_num = {0}; soc_notice_func_enter(); if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port) invalid.\n"); soc_err_print_u32(port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (!frontend_is_open(port)) { soc_log_err("tuner not opened.\n"); return SOC_ERR_FRONTEND_NOT_OPEN; } if (plp_num == TD_NULL) { soc_log_err("Input parameter(plp_num) invalid.\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } fe_plp_num.port = port; fe_plp_num.plp_num = 0; ret = ext_mpi_frontend_get_plp_num(&fe_plp_num); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_get_plp_num, ret); return ret; } *plp_num = (td_u8)fe_plp_num.plp_num; soc_info_print_u32(*plp_num); soc_notice_func_exit(); return TD_SUCCESS; } td_s32 uapi_frontend_set_plp_para(td_u32 port, const uapi_frontend_dvbt2_plp_para *plp_para) { td_s32 ret; fe_ioctrl_set_plp_para fe_plp_para = {0}; soc_notice_func_enter(); if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port) invalid.\n"); soc_err_print_u32(port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (!frontend_is_open(port)) { soc_log_err("tuner not opened.\n"); return SOC_ERR_FRONTEND_NOT_OPEN; } if (plp_para == TD_NULL) { soc_log_err("Input parameter(plp_para) invalid.\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } fe_plp_para.port = port; ret = memcpy_s(&(fe_plp_para.plp_para), sizeof(ext_drv_frontend_dvbt2_plp_para), plp_para, sizeof(uapi_frontend_dvbt2_plp_para)); if (ret != TD_SUCCESS) { return SOC_ERR_FRONTEND_ERR_UNKNOWN; } ret = ext_mpi_frontend_set_plp_para(fe_plp_para); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_set_plp_para, ret); return ret; } soc_notice_func_exit(); return TD_SUCCESS; } td_s32 uapi_frontend_get_plp_para(td_u32 port, uapi_frontend_dvbt2_plp_para *plp_para) { soc_notice_func_enter(); if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port:%u) invalid.\n", port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (plp_para == TD_NULL) { soc_log_err("Input parameter(plp_para) is TD_NULL.\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } soc_notice_func_exit(); return TD_SUCCESS; } td_s32 uapi_frontend_get_plp_info(td_u32 port, td_u32 plp_index, uapi_frontend_dvbt2_plp_info *plp_info) { td_s32 ret; fe_ioctrl_get_plp_info fe_get_plp_info = {0}; errno_t sec_ret; soc_notice_func_enter(); if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port) invalid.\n"); soc_err_print_u32(port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (!frontend_is_open(port)) { soc_log_err("tuner not opened.\n"); return SOC_ERR_FRONTEND_NOT_OPEN; } if (plp_info == TD_NULL) { soc_log_err("Input parameter(plp_para) invalid\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } fe_get_plp_info.port = port; fe_get_plp_info.index = plp_index; ret = ext_mpi_frontend_get_plp_info(&fe_get_plp_info); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_get_plp_info, ret); return ret; } sec_ret = memcpy_s(plp_info, sizeof(uapi_frontend_dvbt2_plp_info), &fe_get_plp_info.plp_info, sizeof(ext_drv_frontend_dvbt2_plp_info)); if (sec_ret != EOK) { return SOC_ERR_FRONTEND_ERR_UNKNOWN; } soc_notice_func_exit(); return TD_SUCCESS; } td_s32 uapi_frontend_isdbt_config_layer_receive(td_u32 port, const uapi_frontend_isdbt_receive_config *mon_layers_config) { td_s32 ret; fe_ioctrl_receive_config fe_layers_config = {0}; soc_notice_func_enter(); if (port >= IAPI_TUNER_NUM) { soc_log_err("Input parameter(port) invalid.\n"); soc_err_print_u32(port); return SOC_ERR_FRONTEND_INVALID_PARA; } if (!frontend_is_open(port)) { soc_log_err("tuner not opened.\n"); return SOC_ERR_FRONTEND_NOT_OPEN; } if (mon_layers_config == TD_NULL) { soc_log_err("Input parameter(mon_layers_config) invalid.\n"); return SOC_ERR_FRONTEND_INVALID_POINT; } fe_layers_config.port = port; fe_layers_config.receive_config.isdbt_layer = (ext_drv_frontend_isdbt_layer)mon_layers_config->isdbt_layer; soc_dbg_print_u32(mon_layers_config->isdbt_layer); ret = ext_mpi_frontend_isdbt_config_layer_receive(fe_layers_config); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ext_mpi_frontend_isdbt_config_layer_receive, ret); return ret; } soc_notice_func_exit(); return TD_SUCCESS; } #ifdef __cplusplus #if __cplusplus } #endif #endif /* __cplusplus */