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 
COM_open_dev(const char * pname,int * fd)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 
COM_close_dev(int fd)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 
COM_pwr_up(int fd,int band,int freq)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 
COM_pwr_down(int fd,int type)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)*/
COM_change_string(uint8_t * str,int len)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 
COM_get_ps(int fd,RDSData_Struct * rds,uint8_t ** ps,int * ps_len)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 
COM_get_rt(int fd,RDSData_Struct * rds,uint8_t ** rt,int * rt_len)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 
COM_get_pi(int fd,RDSData_Struct * rds,uint16_t * pi)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 
COM_tune(int fd,int freq,int band)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 
COM_seek(int fd,int * freq,int band,int dir,int lev)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 
COM_set_mute(int fd,int mute)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 
COM_is_fm_pwrup(int fd,int * pwrup)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  ******************************************/
COM_is_rdsrx_support(int fd,int * supt)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 
COM_pre_search(int fd)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 
COM_restore_search(int fd)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*/
COM_Soft_Mute_Tune(int fd,fm_softmute_tune_t * para)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 
COM_get_cqi(int fd,int num,char * buf,int buf_len)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 
COM_turn_on_off_rds(int fd,int onoff)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 
COM_get_chip_id(int fd,int * chipid)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 
COM_read_rds_data(int fd,RDSData_Struct * rds,uint16_t * rds_status)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 
COM_active_af(int fd,RDSData_Struct * rds,int band,uint16_t cur_freq,uint16_t * ret_freq)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 
COM_ana_switch(int fd,int antenna)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   */
COM_is_dese_chan(int fd,int freq)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   */
COM_desense_check(int fd,int freq,int rssi)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 
FM_interface_init(struct fm_cbk_tbl * cbk_tbl)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