C++程序  |  844行  |  25.37 KB

/*
 * 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;
}