/*
* 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)
int FMR_get_cfgs(int idx)
{
int ret = -1;
FMR_cust_hdler(idx) = NULL;
FMR_get_cfg(idx) = NULL;
FMR_cust_hdler(idx) = dlopen(CUST_LIB_NAME, RTLD_NOW);
if (FMR_cust_hdler(idx) == NULL) {
LOGE("%s failed, %s\n", __FUNCTION__, dlerror());
//FMR_seterr(ERR_LD_LIB);
} else {
*(void **) (&FMR_get_cfg(idx)) = dlsym(FMR_cust_hdler(idx), "CUST_get_cfg");
if (FMR_get_cfg(idx) == NULL) {
LOGE("%s failed, %s\n", __FUNCTION__, dlerror());
//FMR_seterr(ERR_FIND_CUST_FNUC);
} else {
LOGI("Go to run cust function\n");
(*FMR_get_cfg(idx))(&(pfmr_data[idx]->cfg_data));
LOGI("OK\n");
ret = 0;
}
//dlclose(FMR_cust_hdler(idx));
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?
return 0;
}
static void sig_alarm(int sig)
{
LOGI("+++Receive sig %d\n", sig);
return;
}
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;
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, Chip config error. 0x%x\n", __func__, 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;
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;
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;
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;
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_ps(int idx, uint8_t **ps, int *ps_len)
{
int ret = 0;
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;
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_tune(int idx, int freq)
{
int ret = 0;
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;
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, j = 0;
struct fm_fake_channel_t *chan_info = fmr_data.cfg_data.fake_chan;
ChannelNo /= 10;
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 (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;
cur_freq.freq = validfreq->freq;
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 (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 (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 (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 (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 (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, i, j;
fm_softmute_tune_t cur_freq;
fm_s32 band_channel_no = 0;
fm_u8 seek_space = 10;
fm_u16 min_freq, max_freq;
int rssi;
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;
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_rdsrx_support(int idx, int *supt)
{
int ret = 0;
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)
{
//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)
{
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};
fm_u8 NF_Idx = 0;
#endif
memset(SortData, 0, CQI_CH_NUM_MAX*sizeof(struct fm_cqi));
LOGI("band_channel_no=[%d], seek_space=%d, start freq=%d\n", band_channel_no,seek_space,Start_Freq);
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;
}
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=NF_Idx; 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;
}
}
NF_Idx = j;
LOGI("FM Noise FLoor NF_Idx[%d] \n", NF_Idx);
}
#endif
}
LOGI("get channel no.[%d] \n", Num);
if (Num == 0)/*get nothing*/ {
*max_cnt = 0;
FMR_Restore_Search(idx);
return -1;
}
for (i=0; i<Num; i++)/*debug*/ {
LOGI("[%d]:%d \n", i,SortData[i].ch);
}
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) {
SortData[i].ch /= 10;
scan_tbl[ChannelNo]=SortData[i].ch;
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;
//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)
{
fmr_data.scan_stop = fm_true;
return 0;
}
int FMR_turn_on_off_rds(int idx, int onoff)
{
int ret = 0;
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;
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);
/*if (ret) {
LOGE("%s, get no event\n", __func__);
}*/
LOGD("%s, [status=%d] [ret=%d]\n", __func__, *rds_status, ret);
return ret;
}
int FMR_active_af(int idx, uint16_t *ret_freq)
{
int ret = 0;
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.band,
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);
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FMR_ana_switch(int idx, int antenna)
{
int ret = 0;
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;
}