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