Home | History | Annotate | Download | only in fmr
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "fmr.h"
     18 
     19 #ifdef LOG_TAG
     20 #undef LOG_TAG
     21 #endif
     22 #define LOG_TAG "FMLIB_COM"
     23 
     24 static int g_stopscan = 0;
     25 
     26 int COM_open_dev(const char *pname, int *fd)
     27 {
     28     int ret = 0;
     29     int tmp = -1;
     30 
     31     FMR_ASSERT(pname);
     32     FMR_ASSERT(fd);
     33 
     34     LOGI("COM_open_dev start\n");
     35     tmp = open(pname, O_RDWR);
     36     if (tmp < 0) {
     37         LOGE("Open %s failed, %s\n", pname, strerror(errno));
     38         ret = -ERR_INVALID_FD;
     39     }
     40     *fd = tmp;
     41     LOGI("%s, [fd=%d] [ret=%d]\n", __func__, *fd, ret);
     42     return ret;
     43 }
     44 
     45 int COM_close_dev(int fd)
     46 {
     47     int ret = 0;
     48 
     49     LOGI("COM_close_dev start\n");
     50     ret = close(fd);
     51     if (ret) {
     52         LOGE("%s, failed\n", __func__);
     53     }
     54     LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
     55     return ret;
     56 }
     57 
     58 int COM_pwr_up(int fd, int band, int freq)
     59 {
     60     int ret = 0;
     61     struct fm_tune_parm parm;
     62 
     63     LOGI("%s, [freq=%d]\n", __func__, freq);
     64     bzero(&parm, sizeof(struct fm_tune_parm));
     65 
     66     parm.band = band;
     67     parm.freq = freq;
     68     parm.hilo = FM_AUTO_HILO_OFF;
     69     parm.space = FM_SEEK_SPACE;
     70 
     71     ret = ioctl(fd, FM_IOCTL_POWERUP, &parm);
     72     if (ret) {
     73         LOGE("%s, failed\n", __func__);
     74     }
     75     LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
     76     return ret;
     77 }
     78 
     79 int COM_pwr_down(int fd, int type)
     80 {
     81     int ret = 0;
     82     LOGI("%s, [type=%d]\n", __func__, type);
     83     ret = ioctl(fd, FM_IOCTL_POWERDOWN, &type);
     84     if (ret) {
     85         LOGE("%s, failed\n", __func__);
     86     }
     87     LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
     88     return ret;
     89 }
     90 
     91 /*0x20: space, 0x7E:~*/
     92 #define ISVALID(c)((c)>=0x20 && (c)<=0x7E)
     93 /*change any char which out of [0x20,0x7E]to space(0x20)*/
     94 void COM_change_string(uint8_t *str, int len)
     95 {
     96     int i = 0;
     97     for (i=0; i<len; i++) {
     98         if (false == ISVALID(str[i])) {
     99             str[i]= 0x20;
    100         }
    101     }
    102 }
    103 
    104 int COM_get_ps(int fd, RDSData_Struct *rds, uint8_t **ps, int *ps_len)
    105 {
    106     int ret = 0;
    107     char tmp_ps[9] = {0};
    108 
    109     FMR_ASSERT(rds);
    110     FMR_ASSERT(ps);
    111     FMR_ASSERT(ps_len);
    112 
    113     if (rds->event_status&RDS_EVENT_PROGRAMNAME) {
    114         LOGD("%s, Success,[event_status=%d]\n", __func__, rds->event_status);
    115         *ps = &rds->PS_Data.PS[3][0];
    116         *ps_len = sizeof(rds->PS_Data.PS[3]);
    117 
    118         COM_change_string(*ps, *ps_len);
    119         memcpy(tmp_ps, *ps, 8);
    120         LOGI("PS=%s\n", tmp_ps);
    121     } else {
    122         LOGE("%s, Failed,[event_status=%d]\n", __func__, rds->event_status);
    123         *ps = NULL;
    124         *ps_len = 0;
    125         ret = -ERR_RDS_NO_DATA;
    126     }
    127 
    128     return ret;
    129 }
    130 
    131 int COM_get_rt(int fd, RDSData_Struct *rds, uint8_t **rt, int *rt_len)
    132 {
    133     int ret = 0;
    134     char tmp_rt[65] = { 0 };
    135 
    136     FMR_ASSERT(rds);
    137     FMR_ASSERT(rt);
    138     FMR_ASSERT(rt_len);
    139 
    140     if (rds->event_status&RDS_EVENT_LAST_RADIOTEXT) {
    141         LOGD("%s, Success,[event_status=%d]\n", __func__, rds->event_status);
    142         *rt = &rds->RT_Data.TextData[3][0];
    143         *rt_len = rds->RT_Data.TextLength;
    144 
    145         COM_change_string(*rt, *rt_len);
    146         memcpy(tmp_rt, *rt, 64);
    147         LOGI("RT=%s\n", tmp_rt);
    148     } else {
    149         LOGE("%s, Failed,[event_status=%d]\n", __func__, rds->event_status);
    150         *rt = NULL;
    151         *rt_len = 0;
    152         ret = -ERR_RDS_NO_DATA;
    153     }
    154     return ret;
    155 }
    156 
    157 int COM_get_pi(int fd, RDSData_Struct *rds, uint16_t *pi)
    158 {
    159     int ret = 0;
    160 
    161     FMR_ASSERT(rds);
    162     FMR_ASSERT(pi);
    163 
    164     if (rds->event_status&RDS_EVENT_PI_CODE) {
    165         LOGD("%s, Success,[event_status=%d] [PI=%d]\n", __func__, rds->event_status, rds->PI);
    166         *pi = rds->PI;
    167     } else {
    168         LOGI("%s, Failed, there's no pi,[event_status=%d]\n", __func__, rds->event_status);
    169         *pi = -1;
    170         ret = -ERR_RDS_NO_DATA;
    171     }
    172 
    173     return ret;
    174 }
    175 
    176 int COM_tune(int fd, int freq, int band)
    177 {
    178     int ret = 0;
    179 
    180     struct fm_tune_parm parm;
    181 
    182     bzero(&parm, sizeof(struct fm_tune_parm));
    183 
    184     parm.band = band;
    185     parm.freq = freq;
    186     parm.hilo = FM_AUTO_HILO_OFF;
    187     parm.space = FM_SEEK_SPACE;
    188 
    189     ret = ioctl(fd, FM_IOCTL_TUNE, &parm);
    190     if (ret) {
    191         LOGE("%s, failed\n", __func__);
    192     }
    193     LOGD("%s, [fd=%d] [freq=%d] [ret=%d]\n", __func__, fd, freq, ret);
    194     return ret;
    195 }
    196 
    197 int COM_seek(int fd, int *freq, int band, int dir, int lev)
    198 {
    199     int ret = 0;
    200     struct fm_seek_parm parm;
    201 
    202     bzero(&parm, sizeof(struct fm_tune_parm));
    203 
    204     parm.band = band;
    205     parm.freq = *freq;
    206     parm.hilo = FM_AUTO_HILO_OFF;
    207     parm.space = FM_SEEK_SPACE;
    208     if (dir == 1) {
    209         parm.seekdir = FM_SEEK_UP;
    210     } else if (dir == 0) {
    211         parm.seekdir = FM_SEEK_DOWN;
    212     }
    213     parm.seekth = lev;
    214 
    215     ret = ioctl(fd, FM_IOCTL_SEEK, &parm);
    216     if (ret == 0) {
    217         *freq = parm.freq;
    218     }
    219     LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
    220     return ret;
    221 }
    222 
    223 int COM_set_mute(int fd, int mute)
    224 {
    225     int ret = 0;
    226     int tmp = mute;
    227 
    228     LOGD("%s, start \n", __func__);
    229     ret = ioctl(fd, FM_IOCTL_MUTE, &tmp);
    230     if (ret) {
    231         LOGE("%s, failed\n", __func__);
    232     }
    233     LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
    234     return ret;
    235 }
    236 
    237 int COM_is_fm_pwrup(int fd, int *pwrup)
    238 {
    239     int ret = 0;
    240 
    241     ret = ioctl(fd, FM_IOCTL_IS_FM_POWERED_UP, pwrup);
    242     if (ret) {
    243         LOGE("%s, failed\n", __func__);
    244     }
    245     LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
    246     return ret;
    247 }
    248 
    249 /******************************************
    250  * Inquiry if RDS is support in driver.
    251  * Parameter:
    252  *      None
    253  *supt Value:
    254  *      1: support
    255  *      0: NOT support
    256  *      -1: error
    257  ******************************************/
    258 int COM_is_rdsrx_support(int fd, int *supt)
    259 {
    260     int ret = 0;
    261     int support = -1;
    262 
    263     if (fd < 0) {
    264         LOGE("FM isRDSsupport fail, g_fm_fd = %d\n", fd);
    265         *supt = -1;
    266         ret = -ERR_INVALID_FD;
    267         return ret;
    268     }
    269 
    270     ret = ioctl(fd, FM_IOCTL_RDS_SUPPORT, &support);
    271     if (ret) {
    272         LOGE("FM FM_IOCTL_RDS_SUPPORT fail, errno = %d\n", errno);
    273         //don't support
    274         *supt = 0;
    275         return ret;
    276     }
    277     LOGI("isRDSsupport Success,[support=%d]\n", support);
    278     *supt = support;
    279     return ret;
    280 }
    281 
    282 int COM_pre_search(int fd)
    283 {
    284     fm_s32 ret = 0;
    285     ret = ioctl(fd, FM_IOCTL_PRE_SEARCH, 0);
    286     LOGD("COM_pre_search:%d\n",ret);
    287     return ret;
    288 }
    289 
    290 int COM_restore_search(int fd)
    291 {
    292     fm_s32 ret = 0;
    293     ret = ioctl(fd, FM_IOCTL_RESTORE_SEARCH, 0);
    294     LOGD("COM_restore_search:%d\n",ret);
    295     return ret;
    296 }
    297 
    298 /*soft mute tune function, usually for sw scan implement or CQI log tool*/
    299 int COM_Soft_Mute_Tune(int fd, fm_softmute_tune_t *para)
    300 {
    301     fm_s32 ret = 0;
    302     //fm_s32 RSSI = 0, PAMD = 0,MR = 0, ATDC = 0;
    303     //fm_u32 PRX = 0;
    304     //fm_u16 softmuteGainLvl = 0;
    305     fm_softmute_tune_t value;
    306 
    307     value.freq = para->freq;
    308     ret = ioctl(fd, FM_IOCTL_SOFT_MUTE_TUNE, &value);
    309     if (ret) {
    310         LOGE("FM soft mute tune faild:%d\n",ret);
    311         return ret;
    312     }
    313 #if 0
    314     LOGD("Raw data of soft mute tune[%d]: RSSI:[%x]PAMD:[%x]MR:[%x]ATDC:[%x]PRX:[%x]SMG:[%x]",para->freq,value.RSSI,value.PAMD,value.MR,value.ATDC,value.PRX,value.SMG);
    315     RSSI = ((value.RSSI & 0x03FF) >= 512) ? ((value.RSSI & 0x03FF) - 1024) : (value.RSSI & 0x03FF);
    316     PAMD = ((value.PAMD & 0xFF) >= 128) ? ((value.PAMD & 0x00FF) - 256) : (value.PAMD & 0x00FF);
    317     MR = ((value.MR & 0x01FF) >= 256) ? ((value.MR & 0x01FF) - 512) : (value.MR & 0x01FF);
    318     ATDC =((value.ATDC & 0x0FFF) >= 2048) ? ((value.ATDC & 0x0FFF) - 4096) : (value.ATDC & 0x0FFF);
    319     if (ATDC < 0) {
    320         ATDC = (~(ATDC)) - 1;//Get abs value of ATDC
    321     }
    322     PRX = (value.PRX & 0x00FF);
    323     softmuteGainLvl = value.SMG;
    324     //check if the channel is valid according to each CQIs
    325     if ((RSSI >= RSSI_TH)
    326      && (PAMD <= PAMD_TH)
    327      && (ATDC <= ATDC_TH)
    328      && (MR >= MR_TH)
    329      && (PRX >= PRX_TH)
    330      && (softmuteGainLvl <= softMuteGainTH)) {
    331         para->valid = fm_true;
    332     } else {
    333         para->valid = fm_false;
    334     }
    335 #endif
    336     para->valid = value.valid;
    337     para->rssi = value.rssi;
    338     //LOGI("soft mute tune[%d] valid[%d]: RSSI:[%d]PAMD:[%d]MR:[%d]ATDC:[%d]PRX:[%d]SMG:[%d]",para->freq,para->valid,RSSI,PAMD,MR,ATDC,PRX,softmuteGainLvl);
    339     return 0;
    340 }
    341 
    342 int COM_get_cqi(int fd, int num, char *buf, int buf_len)
    343 {
    344     int ret;
    345     struct fm_cqi_req cqi_req;
    346 
    347     //check buf
    348     num = (num > CQI_CH_NUM_MAX) ? CQI_CH_NUM_MAX : num;
    349     num = (num < CQI_CH_NUM_MIN) ? CQI_CH_NUM_MIN : num;
    350     cqi_req.ch_num = (uint16_t)num;
    351     cqi_req.buf_size = cqi_req.ch_num * sizeof(struct fm_cqi);
    352     if (!buf || (buf_len < cqi_req.buf_size)) {
    353         LOGE("get cqi, invalid buf\n");
    354         return -1;
    355     }
    356     cqi_req.cqi_buf = buf;
    357 
    358     //get cqi from driver
    359     ret = ioctl(fd, FM_IOCTL_CQI_GET, &cqi_req);
    360     if (ret < 0) {
    361         LOGE("get cqi, failed %d\n", ret);
    362         return -1;
    363     }
    364 
    365     return 0;
    366 }
    367 
    368 int COM_turn_on_off_rds(int fd, int onoff)
    369 {
    370     int ret = 0;
    371     uint16_t rds_on = -1;
    372 
    373     LOGD("Rdsset start\n");
    374     if (onoff == FMR_RDS_ON) {
    375         rds_on = 1;
    376         ret = ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
    377         if (ret) {
    378             LOGE("FM_IOCTL_RDS_ON failed\n");
    379             return ret;
    380         }
    381         LOGD("Rdsset Success,[rds_on=%d]\n", rds_on);
    382     } else {
    383         rds_on = 0;
    384         ret = ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
    385         if (ret) {
    386             LOGE("FM_IOCTL_RDS_OFF failed\n");
    387             return ret;
    388         }
    389         LOGD("Rdsset Success,[rds_on=%d]\n", rds_on);
    390     }
    391     return ret;
    392 }
    393 
    394 int COM_get_chip_id(int fd, int *chipid)
    395 {
    396     int ret = 0;
    397     uint16_t tmp = 0;
    398 
    399     FMR_ASSERT(chipid);
    400 
    401     ret = ioctl(fd, FM_IOCTL_GETCHIPID, &tmp);
    402     *chipid = (int)tmp;
    403     if (ret) {
    404         LOGE("%s, failed\n", __func__);
    405     }
    406     LOGD("%s, [fd=%d] [chipid=%x] [ret=%d]\n", __func__, fd, *chipid, ret);
    407     return ret;
    408 }
    409 
    410 int COM_read_rds_data(int fd, RDSData_Struct *rds, uint16_t *rds_status)
    411 {
    412     int ret = 0;
    413     uint16_t event_status;
    414     //char tmp_ps[9] = {0};
    415     //char tmp_rt[65] = { 0 };
    416 
    417     FMR_ASSERT(rds);
    418     FMR_ASSERT(rds_status);
    419 
    420     if (read(fd, rds, sizeof(RDSData_Struct)) == sizeof(RDSData_Struct)) {
    421         event_status = rds->event_status;
    422         //memcpy(tmp_ps, &rds->PS_Data.PS[3][0], 8);
    423         //memcpy(tmp_rt, &rds->RT_Data.TextData[3][0], 64);
    424         LOGI("event_status = 0x%x\n", event_status);
    425         //memset(tmp_ps, 0, 9);
    426         //memset(tmp_rt, 0, 65);
    427         *rds_status = event_status;
    428         return ret;
    429     } else {
    430         //LOGE("readrds get no event\n");
    431         ret = -ERR_RDS_NO_DATA;
    432     }
    433     return ret;
    434 }
    435 
    436 int COM_active_af(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *ret_freq)
    437 {
    438     int ret = 0;
    439     int i = 0;
    440     struct fm_tune_parm parm;
    441     uint16_t rds_on = 0;
    442     uint16_t set_freq, sw_freq, org_freq, PAMD_Value, AF_PAMD_LBound, AF_PAMD_HBound;
    443     uint16_t PAMD_Level[25];
    444     uint16_t PAMD_DB_TBL[5] = {// 5dB, 10dB, 15dB, 20dB, 25dB,
    445                                //  13, 17, 21, 25, 29};
    446                                 8, 12, 15, 18, 20};
    447     FMR_ASSERT(rds);
    448     FMR_ASSERT(ret_freq);
    449 
    450     sw_freq = cur_freq; //current freq
    451     org_freq = cur_freq;
    452     parm.band = band;
    453     parm.freq = sw_freq;
    454     parm.hilo = FM_AUTO_HILO_OFF;
    455     parm.space = FM_SPACE_DEFAULT;
    456 
    457     if (!(rds->event_status&RDS_EVENT_AF)) {
    458         LOGE("activeAF failed\n");
    459         *ret_freq = 0;
    460         ret = -ERR_RDS_NO_DATA;
    461         return ret;
    462     }
    463 
    464     AF_PAMD_LBound = PAMD_DB_TBL[0]; //5dB
    465     AF_PAMD_HBound = PAMD_DB_TBL[1]; //15dB
    466     ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Value);
    467     LOGI("current_freq=%d,PAMD_Value=%d\n", cur_freq, PAMD_Value);
    468 
    469     if (PAMD_Value < AF_PAMD_LBound) {
    470         rds_on = 0;
    471         ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
    472         //make sure rds->AF_Data.AF_Num is valid
    473         rds->AF_Data.AF_Num = (rds->AF_Data.AF_Num > 25)? 25 : rds->AF_Data.AF_Num;
    474         for (i=0; i<rds->AF_Data.AF_Num; i++) {
    475             set_freq = rds->AF_Data.AF[1][i];  //method A or B
    476             if (set_freq != org_freq) {
    477                 parm.freq = set_freq;
    478                 ioctl(fd, FM_IOCTL_TUNE, &parm);
    479                 usleep(250*1000);
    480                 ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Level[i]);
    481                 LOGI("next_freq=%d,PAMD_Level=%d\n", parm.freq, PAMD_Level[i]);
    482                 if (PAMD_Level[i] > PAMD_Value) {
    483                     PAMD_Value = PAMD_Level[i];
    484                     sw_freq = set_freq;
    485                 }
    486             }
    487         }
    488         LOGI("PAMD_Value=%d, sw_freq=%d\n", PAMD_Value, sw_freq);
    489         if ((PAMD_Value > AF_PAMD_HBound)&&(sw_freq != 0)) {
    490             parm.freq = sw_freq;
    491             ioctl(fd, FM_IOCTL_TUNE, &parm);
    492             cur_freq = parm.freq;
    493         } else {
    494             parm.freq = org_freq;
    495             ioctl(fd, FM_IOCTL_TUNE, &parm);
    496             cur_freq = parm.freq;
    497         }
    498         rds_on = 1;
    499         ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
    500     } else {
    501         LOGD("RDS_EVENT_AF old freq:%d\n", org_freq);
    502     }
    503     *ret_freq = cur_freq;
    504 
    505     return ret;
    506 }
    507 
    508 int COM_ana_switch(int fd, int antenna)
    509 {
    510     int ret = 0;
    511 
    512     ret = ioctl(fd, FM_IOCTL_ANA_SWITCH, &antenna);
    513     if (ret < 0) {
    514         LOGE("%s: fail, ret = %d\n", __func__, ret);
    515     }
    516 
    517     LOGD("%s: [ret = %d]\n", __func__, ret);
    518     return ret;
    519 }
    520 
    521 /*  COM_is_dese_chan -- check if gived channel is a de-sense channel or not
    522   *  @fd - fd of "dev/fm"
    523   *  @freq - gived channel
    524   *  return value: 0, not a dese chan; 1, a dese chan; else error NO.
    525   */
    526 int COM_is_dese_chan(int fd, int freq)
    527 {
    528     int ret = 0;
    529     int tmp = freq;
    530 
    531     ret = ioctl(fd, FM_IOCTL_IS_DESE_CHAN, &freq);
    532     if (ret < 0) {
    533         LOGE("%s, failed,ret=%d\n", __func__,ret);
    534         return ret;
    535     } else {
    536         LOGD("[fd=%d] %d --> dese=%d\n", fd, tmp, freq);
    537         return freq;
    538     }
    539 }
    540 
    541 /*  COM_desense_check -- check if gived channel is a de-sense channel or not
    542   *  @fd - fd of "dev/fm"
    543   *  @freq - gived channel
    544   *  @rssi-freq's rssi
    545   *  return value: 0, is desense channel and rssi is less than threshold; 1, not desense channel or it is but rssi is more than threshold.
    546   */
    547 int COM_desense_check(int fd, int freq, int rssi)
    548 {
    549     int ret = 0;
    550     fm_desense_check_t parm;
    551 
    552     parm.freq = freq;
    553     parm.rssi = rssi;
    554     ret = ioctl(fd, FM_IOCTL_DESENSE_CHECK, &parm);
    555     if (ret < 0) {
    556         LOGE("%s, failed,ret=%d\n", __func__,ret);
    557         return ret;
    558     } else {
    559         LOGD("[fd=%d] %d --> dese=%d\n", fd,freq,ret);
    560         return ret;
    561     }
    562 }
    563 
    564 void FM_interface_init(struct fm_cbk_tbl *cbk_tbl)
    565 {
    566     //Basic functions.
    567     cbk_tbl->open_dev = COM_open_dev;
    568     cbk_tbl->close_dev = COM_close_dev;
    569     cbk_tbl->pwr_up = COM_pwr_up;
    570     cbk_tbl->pwr_down = COM_pwr_down;
    571     cbk_tbl->tune = COM_tune;
    572     cbk_tbl->set_mute = COM_set_mute;
    573     cbk_tbl->is_rdsrx_support = COM_is_rdsrx_support;
    574     cbk_tbl->turn_on_off_rds = COM_turn_on_off_rds;
    575     cbk_tbl->get_chip_id = COM_get_chip_id;
    576     //For RDS RX.
    577     cbk_tbl->read_rds_data = COM_read_rds_data;
    578     cbk_tbl->get_ps = COM_get_ps;
    579     cbk_tbl->get_rt = COM_get_rt;
    580     cbk_tbl->active_af = COM_active_af;
    581     //FM short antenna
    582     cbk_tbl->ana_switch = COM_ana_switch;
    583     cbk_tbl->desense_check = COM_desense_check;
    584     //soft mute tune
    585     cbk_tbl->soft_mute_tune = COM_Soft_Mute_Tune;
    586     cbk_tbl->pre_search = COM_pre_search;
    587     cbk_tbl->restore_search = COM_restore_search;
    588     return;
    589 }
    590 
    591