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