device_brax_brax3/libfmjni/fmr_core.cpp
Vincent Vidal 8710a52d67 init
2025-08-07 16:07:57 +02:00

1264 lines
35 KiB
C++
Executable file

/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*******************************************************************
* FM JNI core
* return -1 if error occured. else return needed value.
* if return type is char *, return NULL if error occured.
* Do NOT return value access paramater.
*
* FM JNI core should be independent from lower layer, that means
* there should be no low layer dependent data struct in FM JNI core
*
* Naming rule: FMR_n(paramter Micro), FMR_v(functions), fmr_n(global param)
* pfmr_n(global paramter pointer)
*
*******************************************************************/
#include "fmr.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "FMLIB_CORE"
#define FMR_MAX_IDX 1
struct fmr_ds fmr_data;
struct fmr_ds *pfmr_data[FMR_MAX_IDX] = {0};
#define FMR_fd(idx) ((pfmr_data[idx])->fd)
#define FMR_err(idx) ((pfmr_data[idx])->err)
#define FMR_chip(idx) ((pfmr_data[idx])->cfg_data.chip)
#define FMR_low_band(idx) ((pfmr_data[idx])->cfg_data.low_band)
#define FMR_high_band(idx) ((pfmr_data[idx])->cfg_data.high_band)
#define FMR_seek_space(idx) ((pfmr_data[idx])->cfg_data.seek_space)
#define FMR_max_scan_num(idx) ((pfmr_data[idx])->cfg_data.max_scan_num)
#define FMR_cbk_tbl(idx) ((pfmr_data[idx])->tbl)
#define FMR_cust_hdler(idx) ((pfmr_data[idx])->custom_handler)
#define FMR_get_cfg(idx) ((pfmr_data[idx])->get_cfg)
#define UNUSED(x) (void)(x)
int FMR_get_cfgs(int idx)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -ERR_INVALID_PARA;
}
CUST_get_cfg(&(pfmr_data[idx]->cfg_data));
LOGI("OK\n");
FMR_cust_hdler(idx) = NULL;
FMR_get_cfg(idx) = NULL;
LOGI("%s successfully. chip: 0x%x, lband: %d, hband: %d, seek_space: %d, max_scan_num: %d\n", __FUNCTION__, FMR_chip(idx), FMR_low_band(idx), FMR_high_band(idx), FMR_seek_space(idx), FMR_max_scan_num(idx));
return ret;
}
int FMR_chk_cfg_data(int idx)
{
//TODO Need check? how to check?
UNUSED(idx);
return 0;
}
int FMR_init()
{
int idx;
int ret = 0;
//signal(4, sig_alarm);
for (idx=0; idx<FMR_MAX_IDX; idx++) {
if (pfmr_data[idx] == NULL) {
break;
}
}
LOGI("FMR idx = %d\n", idx);
if (idx == FMR_MAX_IDX) {
//FMR_seterr(ERR_NO_MORE_IDX);
return -1;
}
/*The best way here is to call malloc to alloc mem for each idx,but
I do not know where to release it, so use static global param instead*/
pfmr_data[idx] = &fmr_data;
memset(pfmr_data[idx], 0, sizeof(struct fmr_ds));
if (FMR_get_cfgs(idx) < 0) {
LOGI("FMR_get_cfgs failed\n");
goto fail;
}
if (FMR_chk_cfg_data(idx) < 0) {
LOGI("FMR_chk_cfg_data failed\n");
goto fail;
}
pfmr_data[idx]->init_func = FM_interface_init;
if (pfmr_data[idx]->init_func == NULL) {
LOGE("%s init_func error, %s\n", __func__, dlerror());
goto fail;
} else {
LOGI("Go to run init function\n");
(*pfmr_data[idx]->init_func)(&(pfmr_data[idx]->tbl));
LOGI("OK\n");
ret = 0;
}
return idx;
fail:
pfmr_data[idx] = NULL;
return -1;
}
int FMR_open_dev(int idx)
{
int ret = 0;
int real_chip = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).open_dev);
ret = FMR_cbk_tbl(idx).open_dev(FM_DEV_NAME, &FMR_fd(idx));
if (ret || FMR_fd(idx) < 0) {
LOGE("%s failed, [fd=%d]\n", __func__, FMR_fd(idx));
return ret;
}
//Check if customer's cfg matchs driver.
ret = FMR_get_chip_id(idx, &real_chip);
if (FMR_chip(idx) != real_chip) {
LOGE("%s, 0x%x != 0x%x, reinit cfg.\n", __func__, FMR_chip(idx), real_chip);
CUST_update_cfg(&(pfmr_data[idx]->cfg_data), real_chip);
}
if (FMR_chip(idx) != real_chip) {
LOGE("%s, Chip config error. 0x%x != 0x%x\n", __func__,
FMR_chip(idx), real_chip);
ret = FMR_cbk_tbl(idx).close_dev(FMR_fd(idx));
return ret;
}
LOGD("%s, [fd=%d] [chipid=0x%x] [ret=%d]\n", __func__, FMR_fd(idx), real_chip, ret);
return ret;
}
int FMR_close_dev(int idx)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).close_dev);
ret = FMR_cbk_tbl(idx).close_dev(FMR_fd(idx));
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, FMR_fd(idx), ret);
return ret;
}
int FMR_pwr_up(int idx, int freq)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).pwr_up);
LOGI("%s,[freq=%d]\n", __func__, freq);
if (freq < fmr_data.cfg_data.low_band || freq > fmr_data.cfg_data.high_band) {
LOGE("%s error freq: %d\n", __func__, freq);
ret = -ERR_INVALID_PARA;
return ret;
}
ret = FMR_cbk_tbl(idx).pwr_up(FMR_fd(idx), fmr_data.cfg_data.band, freq);
if (ret) {
LOGE("%s failed, [ret=%d]\n", __func__, ret);
}
fmr_data.cur_freq = freq;
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_pwr_down(int idx, int type)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).pwr_down);
ret = FMR_cbk_tbl(idx).pwr_down(FMR_fd(idx), type);
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_get_chip_id(int idx, int *chipid)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_chip_id);
FMR_ASSERT(chipid);
ret = FMR_cbk_tbl(idx).get_chip_id(FMR_fd(idx), chipid);
if (ret) {
LOGE("%s failed, %s\n", __func__, FMR_strerr());
*chipid = -1;
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_get_rssi(int idx, int *rssi)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_rssi);
FMR_ASSERT(rssi);
ret = FMR_cbk_tbl(idx).get_rssi(FMR_fd(idx), rssi);
if (ret){
LOGE("%s failed, [ret=%d]\n", __func__, ret);
*rssi = -1;
}
LOGD("%s, [rssi=%d] [ret=%d]\n", __func__, *rssi, ret);
return ret;
}
int FMR_get_ps(int idx, uint8_t **ps, int *ps_len)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_ps);
FMR_ASSERT(ps);
FMR_ASSERT(ps_len);
ret = FMR_cbk_tbl(idx).get_ps(FMR_fd(idx), &fmr_data.rds, ps, ps_len);
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_get_rt(int idx, uint8_t **rt, int *rt_len)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_rt);
FMR_ASSERT(rt);
FMR_ASSERT(rt_len);
ret = FMR_cbk_tbl(idx).get_rt(FMR_fd(idx), &fmr_data.rds, rt, rt_len);
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_get_pi(int idx, uint16_t *pi)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_pi);
ret = FMR_cbk_tbl(idx).get_pi(FMR_fd(idx), &fmr_data.rds, pi);
if (ret){
LOGE("%s failed, %s\n", __func__, FMR_strerr());
*pi = 0;
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_get_ecc(int idx, uint8_t *ecc)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_ecc);
ret = FMR_cbk_tbl(idx).get_ecc(FMR_fd(idx), &fmr_data.rds, ecc);
if (ret){
LOGE("%s failed\n", __func__);
*ecc = -1;
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_get_pty(int idx, uint8_t *pty)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_pty);
ret = FMR_cbk_tbl(idx).get_pty(FMR_fd(idx), &fmr_data.rds, pty);
if (ret){
*pty = -1;
LOGI("%s failed, %s\n", __func__, FMR_strerr());
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_tune(int idx, int freq)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).tune);
ret = FMR_cbk_tbl(idx).tune(FMR_fd(idx), freq, fmr_data.cfg_data.band);
if (ret) {
LOGE("%s failed, [ret=%d]\n", __func__, ret);
}
fmr_data.cur_freq = freq;
LOGD("%s, [freq=%d] [ret=%d]\n", __func__, freq, ret);
return ret;
}
/*return: fm_true: desense, fm_false: not desene channel*/
fm_bool FMR_DensenseDetect(fm_s32 idx, fm_u16 ChannelNo, fm_s32 RSSI)
{
fm_u8 bDesenseCh = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return fm_false;
}
bDesenseCh = FMR_cbk_tbl(idx).desense_check(FMR_fd(idx), ChannelNo, RSSI);
if (bDesenseCh == 1) {
return fm_true;
}
return fm_false;
}
fm_bool FMR_SevereDensense(fm_u16 ChannelNo, fm_s32 RSSI)
{
fm_s32 i = 0;
struct fm_fake_channel_t *chan_info = fmr_data.cfg_data.fake_chan;
for (i=0; i<chan_info->size; i++) {
if (ChannelNo == chan_info->chan[i].freq) {
//if (RSSI < FM_SEVERE_RSSI_TH)
if (RSSI < chan_info->chan[i].rssi_th) {
LOGI(" SevereDensense[%d] RSSI[%d]\n", ChannelNo,RSSI);
return fm_true;
} else {
break;
}
}
}
return fm_false;
}
#if (FMR_NOISE_FLOORT_DETECT==1)
/*return TRUE:get noise floor freq*/
fm_bool FMR_NoiseFloorDetect(fm_bool *rF, fm_s32 rssi, fm_s32 *F_rssi)
{
if (rF[0] == fm_true) {
if (rF[1] == fm_true) {
F_rssi[2] = rssi;
rF[2] = fm_true;
return fm_true;
} else {
F_rssi[1] = rssi;
rF[1] = fm_true;
}
} else {
F_rssi[0] = rssi;
rF[0] = fm_true;
}
return fm_false;
}
#endif
/*check the cur_freq->freq is valid or not
return fm_true : need check cur_freq->valid
fm_false: check faild, should stop seek
*/
static fm_bool FMR_Seek_TuneCheck(int idx, fm_softmute_tune_t *cur_freq)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return fm_false;
}
if (fmr_data.scan_stop == fm_true) {
ret = FMR_tune(idx,fmr_data.cur_freq);
LOGI("seek stop!!! tune ret=%d",ret);
return fm_false;
}
ret = FMR_cbk_tbl(idx).soft_mute_tune(FMR_fd(idx), cur_freq);
if (ret) {
LOGE("soft mute tune, failed:[%d]\n",ret);
cur_freq->valid = fm_false;
return fm_true;
}
if (cur_freq->valid == fm_true)/*get valid channel*/ {
if (FMR_DensenseDetect(idx, cur_freq->freq, cur_freq->rssi) == fm_true) {
LOGI("desense channel detected:[%d] \n", cur_freq->freq);
cur_freq->valid = fm_false;
return fm_true;
}
if (FMR_SevereDensense(cur_freq->freq, cur_freq->rssi) == fm_true) {
LOGI("sever desense channel detected:[%d] \n", cur_freq->freq);
cur_freq->valid = fm_false;
return fm_true;
}
LOGI("seek result freq:[%d] \n", cur_freq->freq);
}
return fm_true;
}
/*
check more 2 freq, curfreq: current freq, seek_dir: 1,forward. 0,backword
*/
static int FMR_Seek_More(int idx, fm_softmute_tune_t *validfreq, fm_u8 seek_dir, fm_u8 step, fm_u16 min_freq, fm_u16 max_freq)
{
fm_s32 i;
fm_softmute_tune_t cur_freq;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
cur_freq.freq = validfreq->freq;
cur_freq.rssi = 0;
for (i=0; i<2; i++) {
if (seek_dir)/*forward*/ {
if (cur_freq.freq + step > max_freq) {
return 0;
}
cur_freq.freq += step;
} else/*backward*/ {
if (cur_freq.freq - step < min_freq) {
return 0;
}
cur_freq.freq -= step;
}
if (FMR_Seek_TuneCheck(idx, &cur_freq) == fm_true) {
if (cur_freq.valid == fm_true) {
if (cur_freq.rssi > validfreq->rssi) {
validfreq->freq = cur_freq.freq;
validfreq->rssi = cur_freq.rssi;
LOGI("seek cover last by freq=%d",cur_freq.freq);
}
}
} else {
return -1;
}
}
return 0;
}
/*check the a valid channel
return -1 : seek fail
0: seek success
*/
int FMR_seek_Channel(int idx, int start_freq, int min_freq, int max_freq, int band_channel_no, int seek_space, int dir, int *ret_freq, int *rssi_tmp)
{
fm_s32 i, ret = 0;
fm_softmute_tune_t cur_freq;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
memset(&cur_freq, 0, sizeof(struct fm_softmute_tune_t));
if (dir == 1)/*forward*/ {
for (i=((start_freq-min_freq)/seek_space+1); i<band_channel_no; i++) {
cur_freq.freq = min_freq + seek_space*i;
LOGI("i=%d, freq=%d-----1",i,cur_freq.freq);
ret = FMR_Seek_TuneCheck(idx, &cur_freq);
if (ret == fm_false) {
return -1;
} else {
if (cur_freq.valid == fm_false) {
continue;
} else {
if ((seek_space == 5) && (start_freq == cur_freq.freq - seek_space)) {
continue; // filter the same channel
}
if (FMR_Seek_More(idx, &cur_freq, dir, seek_space, min_freq, max_freq) == 0) {
*ret_freq = cur_freq.freq;
*rssi_tmp = cur_freq.rssi;
return 0;
} else {
return -1;
}
}
}
}
for (i=0; i<((start_freq-min_freq)/seek_space); i++) {
cur_freq.freq = min_freq + seek_space*i;
LOGI("i=%d, freq=%d-----2",i,cur_freq.freq);
ret = FMR_Seek_TuneCheck(idx, &cur_freq);
if (ret == fm_false) {
return -1;
} else {
if (cur_freq.valid == fm_false) {
continue;
} else {
if ((seek_space == 5) && (start_freq == cur_freq.freq - seek_space)) {
continue; // filter the same channel
}
if (FMR_Seek_More(idx, &cur_freq, dir, seek_space, min_freq, max_freq) == 0) {
*ret_freq = cur_freq.freq;
*rssi_tmp = cur_freq.rssi;
return 0;
} else {
return -1;
}
}
}
}
} else/*backward*/ {
for (i=((start_freq-min_freq)/seek_space-1); i>=0; i--) {
cur_freq.freq = min_freq + seek_space*i;
LOGI("i=%d, freq=%d-----3",i,cur_freq.freq);
ret = FMR_Seek_TuneCheck(idx, &cur_freq);
if (ret == fm_false) {
return -1;
} else {
if (cur_freq.valid == fm_false) {
continue;
} else {
if ((seek_space == 5) && (start_freq == cur_freq.freq + seek_space)) {
continue; // filter the same channel
}
if (FMR_Seek_More(idx, &cur_freq, dir, seek_space, min_freq, max_freq) == 0) {
*ret_freq = cur_freq.freq;
*rssi_tmp = cur_freq.rssi;
return 0;
} else {
return -1;
}
}
}
}
for (i=(band_channel_no-1); i>((start_freq-min_freq)/seek_space); i--) {
cur_freq.freq = min_freq + seek_space*i;
LOGI("i=%d, freq=%d-----4",i,cur_freq.freq);
ret = FMR_Seek_TuneCheck(idx, &cur_freq);
if (ret == fm_false) {
return -1;
} else {
if (cur_freq.valid == fm_false) {
continue;
} else {
if ((seek_space == 5) && (start_freq == cur_freq.freq + seek_space)) {
continue; // filter the same channel
}
if (FMR_Seek_More(idx, &cur_freq, dir,seek_space, min_freq, max_freq) == 0) {
*ret_freq = cur_freq.freq;
*rssi_tmp = cur_freq.rssi;
return 0;
} else {
return -1;
}
}
}
}
}
*ret_freq = start_freq;
return 0;
}
int FMR_seek(int idx, int start_freq, int dir, int *ret_freq)
{
fm_s32 ret = 0;
fm_s32 band_channel_no = 0;
fm_u8 seek_space = 10;
fm_u16 min_freq, max_freq;
int rssi;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
if ((start_freq < 7600) || (start_freq > 10800)) /*need replace by macro*/ {
LOGE("%s error start_freq: %d\n", __func__, start_freq);
return -ERR_INVALID_PARA;
}
//FM radio seek space,5:50KHZ; 1:100KHZ; 2:200KHZ
if (fmr_data.cfg_data.seek_space == 5) {
seek_space = 5;
} else if (fmr_data.cfg_data.seek_space == 2) {
seek_space = 20;
} else {
seek_space = 10;
}
if (fmr_data.cfg_data.band == FM_BAND_JAPAN)/* Japan band 76MHz ~ 90MHz */ {
band_channel_no = (9600-7600)/seek_space + 1;
min_freq = 7600;
max_freq = 9600;
} else if (fmr_data.cfg_data.band == FM_BAND_JAPANW)/* Japan wideband 76MHz ~ 108MHz */ {
band_channel_no = (10800-7600)/seek_space + 1;
min_freq = 7600;
max_freq = 10800;
} else/* US/Europe band 87.5MHz ~ 108MHz (DEFAULT) */ {
band_channel_no = (10800-8750)/seek_space + 1;
min_freq = 8750;
max_freq = 10800;
}
fmr_data.scan_stop = fm_false;
LOGD("seek start freq %d band_channel_no=[%d], seek_space=%d band[%d - %d] dir=%d\n", start_freq, band_channel_no,seek_space,min_freq,max_freq,dir);
ret = FMR_seek_Channel(idx, start_freq, min_freq, max_freq, band_channel_no, seek_space, dir, ret_freq, &rssi);
return ret;
}
int FMR_set_mute(int idx, int mute)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).set_mute)
if ((mute < 0) || (mute > 1)) {
LOGE("%s error param mute: %d\n", __func__, mute);
}
ret = FMR_cbk_tbl(idx).set_mute(FMR_fd(idx), mute);
if (ret) {
LOGE("%s failed, %s\n", __func__, FMR_strerr());
}
LOGD("%s, [mute=%d] [ret=%d]\n", __func__, mute, ret);
return ret;
}
int FMR_is_fm_pwrup(int idx, int *pwrup)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).is_fm_pwrup);
FMR_ASSERT(pwrup);
ret = FMR_cbk_tbl(idx).is_fm_pwrup(FMR_fd(idx), pwrup);
if (ret){
*pwrup = 0;
LOGE("%s failed, %s\n", __func__, FMR_strerr());
}
LOGD("%s, [pwrup=%d] [ret=%d]\n", __func__, *pwrup, ret);
return ret;
}
int FMR_is_rdsrx_support(int idx, int *supt)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).is_rdsrx_support);
FMR_ASSERT(supt);
ret = FMR_cbk_tbl(idx).is_rdsrx_support(FMR_fd(idx), supt);
if (ret) {
*supt = 0;
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [supt=%d] [ret=%d]\n", __func__, *supt, ret);
return ret;
}
int FMR_Pre_Search(int idx)
{
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
//avoid scan stop flag clear if stop cmd send before pre-search finish
fmr_data.scan_stop = fm_false;
FMR_ASSERT(FMR_cbk_tbl(idx).pre_search);
FMR_cbk_tbl(idx).pre_search(FMR_fd(idx));
return 0;
}
int FMR_Restore_Search(int idx)
{
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).restore_search);
FMR_cbk_tbl(idx).restore_search(FMR_fd(idx));
return 0;
}
int FMR_scan_Channels(int idx, uint16_t *scan_tbl, int *max_cnt, fm_s32 band_channel_no, fm_u16 Start_Freq, fm_u8 seek_space, fm_u8 NF_Space)
{
fm_s32 ret = 0, Num = 0, i, j;
fm_u32 ChannelNo = 0;
fm_softmute_tune_t cur_freq;
static struct fm_cqi SortData[CQI_CH_NUM_MAX];
fm_bool LastExist = fm_false;
struct fm_cqi swap;
#if (FMR_NOISE_FLOORT_DETECT==1)
fm_s32 Pacc = 0, Nacc = 0;
fm_s32 NF = 0;
fm_bool F[3] = {fm_false, fm_false, fm_false};
fm_s32 F_Rssi[3] = {0};
#endif
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
memset(SortData, 0, CQI_CH_NUM_MAX*sizeof(struct fm_cqi));
LOGI("band_channel_no=[%d], seek_space=%d, start freq=%d, NF_Space=%d\n", band_channel_no,seek_space,Start_Freq, NF_Space);
for (i=0; i<band_channel_no; i++) {
if (fmr_data.scan_stop == fm_true) {
FMR_Restore_Search(idx);
ret = FMR_tune(idx, fmr_data.cur_freq);
LOGI("scan stop!!! tune ret=%d",ret);
return -1;
}
cur_freq.freq = Start_Freq + seek_space*i;
ret = FMR_cbk_tbl(idx).soft_mute_tune(FMR_fd(idx), &cur_freq);
if (ret) {
LOGE("soft mute tune, failed:[%d]\n",ret);
LastExist = fm_false;
continue;
}
if (cur_freq.valid == fm_true)/*get valid channel*/ {
#if (FMR_NOISE_FLOORT_DETECT==1)
memset(F, fm_false, sizeof(F));
#endif
if (FMR_DensenseDetect(idx, cur_freq.freq, cur_freq.rssi) == fm_true) {
LOGI("desense channel detected:[%d] \n", cur_freq.freq);
LastExist = fm_false;
continue;
}
if ((LastExist == fm_true) && (Num > 0)) /*neighbor channel*/ {
if (cur_freq.rssi>SortData[Num-1].rssi)/*save current freq and cover last channel*/ {
if (FMR_SevereDensense(cur_freq.freq, cur_freq.rssi) == fm_true) {
LastExist = fm_false;
continue;
}
SortData[Num-1].ch=cur_freq.freq;
SortData[Num-1].rssi=cur_freq.rssi;
SortData[Num-1].reserve = 1;
LOGI("cover last channel \n");
} else/*ignore current freq*/ {
LastExist = fm_false;
continue;
}
} else/*save current*/ {
if (FMR_SevereDensense(cur_freq.freq, cur_freq.rssi) == fm_true) {
LastExist = fm_false;
continue;
}
if (Num < 0 || Num >= CQI_CH_NUM_MAX) {
continue;
}
SortData[Num].ch = cur_freq.freq;
SortData[Num].rssi = cur_freq.rssi;
SortData[Num].reserve = 1;
Num++;
LastExist = fm_true;
LOGI("Num++:[%d] \n", Num);
}
} else {
#if (FMR_NOISE_FLOORT_DETECT==1)
if (FMR_DensenseDetect(idx, cur_freq.freq, cur_freq.rssi) == fm_false) {
if (FMR_NoiseFloorDetect(F, cur_freq.rssi, F_Rssi) == fm_true) {
Pacc += F_Rssi[1];
Nacc++;
/*check next freq*/
F[0] = F[1];
F_Rssi[0] = F_Rssi[1];
F[1] = F[2];
F_Rssi[1] = F_Rssi[2];
F[2] = fm_false;
F_Rssi[2] = 0;
LOGI("FM Noise FLoor:Pacc=[%d] Nacc=[%d] \n", Pacc,Nacc);
}
} else {
memset(F, fm_false, sizeof(F));
}
#endif
LastExist = fm_false;
}
#if (FMR_NOISE_FLOORT_DETECT==1)
if (((i%NF_Space) == 0) && (i != 0)) {
if (Nacc > 0) {
NF = Pacc/Nacc;
} else {
NF = RSSI_TH-FM_NOISE_FLOOR_OFFSET;
}
Pacc = 0;
Nacc = 0;
for (j = 0; j < Num; j++) {
if (SortData[j].rssi < (NF + FM_NOISE_FLOOR_OFFSET)) {
LOGI("FM Noise FLoor Detected:freq=[%d] NF=[%d] \n", SortData[j].ch, NF);
SortData[j].reserve = 0;
}
}
LOGI("FM Noise FLoor NF_Idx[%d] \n", j);
}
#endif
}
LOGI("get channel no.[%d] \n", Num);
if (Num == 0)/*get nothing*/ {
*max_cnt = 0;
FMR_Restore_Search(idx);
return -1;
}
switch (fmr_data.cfg_data.scan_sort)
{
case FM_SCAN_SORT_UP:
case FM_SCAN_SORT_DOWN:
{
LOGI("Start sort \n");
//do sort: insert sort algorithm
for (i = 1; i < Num; i++) {
for (j = i; (j > 0) && ((FM_SCAN_SORT_DOWN == fmr_data.cfg_data.scan_sort) ? (SortData[j-1].rssi \
< SortData[j].rssi) : (SortData[j-1].rssi > SortData[j].rssi)); j--) {
memcpy(&swap, &SortData[j], sizeof(struct fm_cqi));
memcpy(&SortData[j], &SortData[j-1], sizeof(struct fm_cqi));
memcpy(&SortData[j-1], &swap, sizeof(struct fm_cqi));
}
}
LOGI("End sort \n");
break;
}
default:
break;
}
ChannelNo = 0;
for (i=0; i<Num; i++) {
if (SortData[i].reserve == 1) {
if (10 == seek_space)
SortData[i].ch /= 10;
scan_tbl[ChannelNo] = SortData[i].ch;
LOGI("scan_tbl[%d]:%d\n", i, scan_tbl[ChannelNo]);
ChannelNo++;
}
}
*max_cnt=ChannelNo;
LOGI("return channel no.[%d] \n", ChannelNo);
return 0;
}
int FMR_scan(int idx, uint16_t *scan_tbl, int *max_cnt)
{
fm_s32 ret = 0;
fm_s32 band_channel_no = 0;
fm_u8 seek_space = 10;
fm_u16 Start_Freq = 8750;
fm_u8 NF_Space = 41;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
//FM radio seek space,5:50KHZ; 1:100KHZ; 2:200KHZ
if (fmr_data.cfg_data.seek_space == 5) {
seek_space = 5;
} else if (fmr_data.cfg_data.seek_space == 2) {
seek_space = 20;
} else {
seek_space = 10;
}
if (fmr_data.cfg_data.band == FM_BAND_JAPAN)/* Japan band 76MHz ~ 90MHz */ {
band_channel_no = (9600-7600)/seek_space + 1;
Start_Freq = 7600;
NF_Space = 400/seek_space;
} else if (fmr_data.cfg_data.band == FM_BAND_JAPANW)/* Japan wideband 76MHZ ~ 108MHz */ {
band_channel_no = (10800-7600)/seek_space + 1;
Start_Freq = 7600;
NF_Space = 640/seek_space;
} else/* US/Europe band 87.5MHz ~ 108MHz (DEFAULT) */ {
band_channel_no = (10800-8750)/seek_space + 1;
Start_Freq = 8750;
NF_Space = 410/seek_space;
}
ret = FMR_scan_Channels(idx, scan_tbl, max_cnt, band_channel_no, Start_Freq, seek_space, NF_Space);
return ret;
}
int FMR_stop_scan(int idx)
{
UNUSED(idx);
fmr_data.scan_stop = fm_true;
return 0;
}
int FMR_turn_on_off_rds(int idx, int onoff)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).turn_on_off_rds)
ret = FMR_cbk_tbl(idx).turn_on_off_rds(FMR_fd(idx), onoff);
if (ret) {
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [onoff=%d] [ret=%d]\n", __func__, onoff, ret);
return ret;
}
int FMR_read_rds_data(int idx, uint16_t *rds_status)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).read_rds_data);
FMR_ASSERT(rds_status);
ret = FMR_cbk_tbl(idx).read_rds_data(FMR_fd(idx), &fmr_data.rds, rds_status);
LOGD("%s, [status=0x%04x] , [ret=%d]\n", __func__, *rds_status, ret);
return ret;
}
int FMR_active_af(int idx, uint16_t orig_pi, uint16_t *ret_freq)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).active_af);
FMR_ASSERT(ret_freq);
ret = FMR_cbk_tbl(idx).active_af(FMR_fd(idx),
&fmr_data.rds,
&fmr_data.cfg_data,
orig_pi,
fmr_data.cur_freq,
ret_freq);
if ((ret == 0) && (*ret_freq != fmr_data.cur_freq)) {
fmr_data.cur_freq = *ret_freq;
LOGI("active AF OK, new channel[freq=%d]\n", fmr_data.cur_freq);
}
if(fmr_data.cfg_data.seek_space != 5) {
*ret_freq = *ret_freq/10;
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_active_ta(int idx, uint16_t *ret_freq)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).active_ta);
FMR_ASSERT(ret_freq);
ret = FMR_cbk_tbl(idx).active_ta(FMR_fd(idx),
&fmr_data.rds,
fmr_data.cfg_data.band,
fmr_data.cur_freq,
&fmr_data.backup_freq,
ret_freq);
if((ret == 0) && (*ret_freq != fmr_data.cur_freq)){
fmr_data.cur_freq = *ret_freq;
LOGI("active TA OK, new channel[freq=%d]\n", fmr_data.cur_freq);
}
if(fmr_data.cfg_data.seek_space != 5) {
*ret_freq = *ret_freq/10;
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_deactive_ta(int idx, uint16_t *ret_freq)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).deactive_ta);
FMR_ASSERT(ret_freq);
ret = FMR_cbk_tbl(idx).deactive_ta(FMR_fd(idx),
&fmr_data.rds,
fmr_data.cfg_data.band,
fmr_data.cur_freq,
&fmr_data.backup_freq,
ret_freq);
if((ret == 0) && (*ret_freq != fmr_data.cur_freq)){
fmr_data.cur_freq = *ret_freq;
LOGI("deactive TA OK, new channel[freq=%d]\n", fmr_data.cur_freq);
}
if(fmr_data.cfg_data.seek_space != 5) {
*ret_freq = *ret_freq/10;
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_ana_switch(int idx, int antenna)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).ana_switch);
if (fmr_data.cfg_data.short_ana_sup == true) {
ret = FMR_cbk_tbl(idx).ana_switch(FMR_fd(idx), antenna);
if (ret) {
LOGE("%s failed, [ret=%d]\n", __func__, ret);
}
} else {
LOGW("FM antenna switch not support!\n");
ret = -ERR_UNSUPT_SHORTANA;
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_get_badratio(int idx, int *badratio)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_badratio);
FMR_ASSERT(badratio);
ret = FMR_cbk_tbl(idx).get_badratio(FMR_fd(idx), badratio);
if (ret){
*badratio = 0;
LOGE("%s failed, %s\n", __func__, FMR_strerr());
}
LOGD("%s, [badratio=%d] [ret=%d]\n", __func__, *badratio, ret);
return ret;
}
int FMR_get_stereomono(int idx, int *stemono)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_stereomono);
FMR_ASSERT(stemono);
ret = FMR_cbk_tbl(idx).get_stereomono(FMR_fd(idx), stemono);
if (ret){
*stemono = 0;
LOGE("%s failed, %s\n", __func__, FMR_strerr());
}
LOGD("%s, [stemono=%d] [ret=%d]\n", __func__, *stemono, ret);
return ret;
}
int FMR_set_stereomono(int idx, int stemono)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).set_stereomono);
ret = FMR_cbk_tbl(idx).set_stereomono(FMR_fd(idx), stemono);
if (ret){
LOGE("%s failed, %s\n", __func__, FMR_strerr());
}
LOGD("%s, [stemono=%d] [ret=%d]\n", __func__, stemono, ret);
return ret;
}
int FMR_get_caparray(int idx, int *caparray)
{
int ret = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_caparray);
FMR_ASSERT(caparray);
ret = FMR_cbk_tbl(idx).get_caparray(FMR_fd(idx), caparray);
if (ret){
*caparray = 0;
LOGE("%s failed, %s\n", __func__, FMR_strerr());
}
LOGD("%s, [caparray=%d] [ret=%d]\n", __func__, *caparray, ret);
return ret;
}
int FMR_get_hw_info(int idx, int **info, int *info_len)
{
int ret = 0;
static int inited = 0;
static int info_array[10] = {0};
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).get_hw_info);
FMR_ASSERT(info);
FMR_ASSERT(info_len);
if(!inited){
ret = FMR_cbk_tbl(idx).get_hw_info(FMR_fd(idx), &fmr_data.hw_info);
if(ret >= 0){
inited = 1; //get hw info success
}
}
info_array[0] = fmr_data.hw_info.chip_id;
info_array[1] = fmr_data.hw_info.eco_ver;
info_array[2] = fmr_data.hw_info.rom_ver;
info_array[3] = fmr_data.hw_info.patch_ver;
*info = info_array;
*info_len = sizeof(struct fm_hw_info)/sizeof(int);
LOGD("chip:0x%08x, eco:0x%08x, rom:0x%08x, patch: 0x%08x\n", info_array[0], info_array[1], info_array[2], info_array[3]);
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
/*
th_idx:
threshold type: 0, RSSI. 1,desense RSSI. 2,SMG.
th_val: threshold value*/
int FMR_EMSetTH(int idx, int th_idx, int th_val)
{
int ret = -1;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).set_search_threshold);
ret=FMR_cbk_tbl(idx).set_search_threshold(FMR_fd(idx),th_idx,th_val);
return ret;
}
int FMR_EM_CQI_logger(int idx,uint16_t cycle)
{
int ret = -1;
fm_full_cqi_log_t log_setting;
uint i = 0;
if (idx < 0 || idx >= FMR_MAX_IDX) {
return -1;
}
FMR_ASSERT(FMR_cbk_tbl(idx).full_cqi_logger);
//log_setting.cycle = cycle;
if(fmr_data.cfg_data.seek_space == 5) {
log_setting.lower = FM_FREQ_MIN * 10;
log_setting.upper = FM_FREQ_MAX * 10;
} else {
log_setting.lower = FM_FREQ_MIN;
log_setting.upper = FM_FREQ_MAX;
}
log_setting.space = 0x2;
for(i = 0;i < cycle; i++)
{
log_setting.cycle = i;
ret = FMR_cbk_tbl(idx).full_cqi_logger(FMR_fd(idx),&log_setting);
LOGD("%s, [%d]\n", __func__, i);
}
//ret = FMR_cbk_tbl(idx).full_cqi_logger(FMR_fd(idx),&log_setting);
return ret;
}