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
24static int g_stopscan = 0;
25
26int 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
45int 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
58int 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
79int 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)*/
94void 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
104int 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
131int 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
157int 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
176int 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
197int 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
223int 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
237int 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 ******************************************/
258int 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
282int 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
290int 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*/
299int 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
342int 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
368int 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
394int 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
410int 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
436int 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
508int 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  */
526int 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  */
547int 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
564void 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