This commit is contained in:
Vincent Vidal 2025-08-07 16:07:57 +02:00
commit 8710a52d67
123 changed files with 20007 additions and 0 deletions

42
libfmjni/Android.bp Normal file
View file

@ -0,0 +1,42 @@
//
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
cc_library_shared {
name: "libfmjni-mediatek",
stem: "libfmjni",
overrides: ["libfmjni"],
srcs: [
"fmr_core.cpp",
"fmr_err.cpp",
"libfm_jni.cpp",
"common.cpp",
"custom.cpp",
],
header_libs: ["jni_headers"],
shared_libs: [
"libbase",
"libcutils",
"libdl",
"liblog",
"libmedia",
"libnativehelper",
],
}

185
libfmjni/NOTICE Normal file
View file

@ -0,0 +1,185 @@
This MediaTek software package contains software with the following notices and under the following licenses:
==============================================================================================================
Copyright (C) 2014 The Android Open Source Project
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

25
libfmjni/README Normal file
View file

@ -0,0 +1,25 @@
Libraries of MTK FM feature, including FM power on/off,
seek, scan, tune...and some other basic functions.
WHAT IT DOES?
=============
Provide FM basic functions
HOW IT WAS BUILT?
==================
It needs the following libs from AOSP:
1. libcutils
2. libdl
and the following libs from MediaTek:
1. libmedia
HOW TO USE IT?
==============
Files in this directory is used to
generate libraries 'libfmjni'
These libraries are loaded when system up
All the source code of this library were written by MediaTek co..

968
libfmjni/common.cpp Executable file
View file

@ -0,0 +1,968 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cutils/properties.h>
#include "fmr.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "FMLIB_COM"
#define UNUSED(x) (void)(x)
int COM_get_seek_space()
{
// FM radio seek space, 5:50KHZ; 1:100KHZ; 2:200KHZ
if (property_get_int32("persist.vendor.connsys.fm_50khz_support", 0) == 1)
return FM_SPACE_50K;
return FM_SPACE_DEFAULT;
}
int COM_open_dev(const char *pname, int *fd)
{
int ret = 0;
int tmp = -1;
FMR_ASSERT(pname);
FMR_ASSERT(fd);
LOGI("COM_open_dev start\n");
tmp = open(pname, O_RDWR);
if (tmp < 0) {
LOGE("Open %s failed, %s\n", pname, strerror(errno));
ret = -ERR_INVALID_FD;
}
*fd = tmp;
LOGI("%s, [fd=%d] [ret=%d]\n", __func__, *fd, ret);
return ret;
}
int COM_close_dev(int fd)
{
int ret = 0;
LOGI("COM_close_dev start\n");
ret = close(fd);
if (ret) {
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_pwr_up(int fd, int band, int freq)
{
int ret = 0;
struct fm_tune_parm parm;
LOGI("%s, [freq=%d]\n", __func__, freq);
bzero(&parm, sizeof(struct fm_tune_parm));
parm.band = band;
parm.freq = freq;
parm.hilo = FM_AUTO_HILO_OFF;
parm.space = FM_SEEK_SPACE;
ret = ioctl(fd, FM_IOCTL_POWERUP, &parm);
if (ret) {
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_pwr_down(int fd, int type)
{
int ret = 0;
LOGI("%s, [type=%d]\n", __func__, type);
ret = ioctl(fd, FM_IOCTL_POWERDOWN, &type);
if (ret) {
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_get_chip_id(int fd, int *chipid)
{
int ret = 0;
uint16_t tmp = 0;
FMR_ASSERT(chipid);
ret = ioctl(fd, FM_IOCTL_GETCHIPID, &tmp);
*chipid = (int)tmp;
if (ret){
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [chipid=%x] [ret=%d]\n", __func__, fd, *chipid, ret);
return ret;
}
int COM_get_rssi(int fd, int *rssi)
{
int ret = 0;
FMR_ASSERT(rssi);
ret = ioctl(fd, FM_IOCTL_GETRSSI, rssi);
if(ret){
LOGE("%s, failed, [ret=%d]\n", __func__, ret);
}
LOGI("%s, [rssi=%d] [ret=%d]\n", __func__, *rssi, ret);
return ret;
}
/*0x20: space, 0x7E:~*/
#define ISVALID(c)((c)>=0x20 && (c)<=0x7E)
/*change any char which out of [0x20,0x7E]to space(0x20)*/
void COM_change_string(uint8_t *str, int len)
{
int i = 0;
for (i=0; i<len; i++) {
if (false == ISVALID(str[i])) {
str[i]= 0x20;
}
}
}
int COM_get_ps(int fd, RDSData_Struct *rds, uint8_t **ps, int *ps_len)
{
int ret = 0;
char tmp_ps[9] = {0};
UNUSED(fd);
FMR_ASSERT(rds);
FMR_ASSERT(ps);
FMR_ASSERT(ps_len);
if (rds->event_status&RDS_EVENT_PROGRAMNAME) {
LOGD("%s, Success,[event_status=%d]\n", __func__, rds->event_status);
*ps = &rds->PS_Data.PS[3][0];
*ps_len = sizeof(rds->PS_Data.PS[3]);
COM_change_string(*ps, *ps_len);
memcpy(tmp_ps, *ps, 8);
LOGI("PS=%s\n", tmp_ps);
} else {
LOGE("%s, Failed,[event_status=%d]\n", __func__, rds->event_status);
*ps = NULL;
*ps_len = 0;
ret = -ERR_RDS_NO_DATA;
}
return ret;
}
int COM_get_rt(int fd, RDSData_Struct *rds, uint8_t **rt, int *rt_len)
{
int ret = 0;
char tmp_rt[65] = { 0 };
UNUSED(fd);
FMR_ASSERT(rds);
FMR_ASSERT(rt);
FMR_ASSERT(rt_len);
if (rds->event_status&RDS_EVENT_LAST_RADIOTEXT) {
LOGD("%s, Success,[event_status=%d]\n", __func__, rds->event_status);
*rt = &rds->RT_Data.TextData[3][0];
*rt_len = rds->RT_Data.TextLength;
COM_change_string(*rt, *rt_len);
memcpy(tmp_rt, *rt, 64);
LOGI("RT=%s\n", tmp_rt);
} else {
LOGE("%s, Failed,[event_status=%d]\n", __func__, rds->event_status);
*rt = NULL;
*rt_len = 0;
ret = -ERR_RDS_NO_DATA;
}
return ret;
}
int COM_get_pi(int fd, RDSData_Struct *rds, uint16_t *pi)
{
int ret = 0;
UNUSED(fd);
FMR_ASSERT(rds);
FMR_ASSERT(pi);
if (rds->event_status & RDS_EVENT_PI_CODE) {
LOGD("%s, Success,[event_status=%d] [PI=%d]\n", __func__, rds->event_status, rds->PI);
*pi = rds->PI;
} else {
LOGI("%s, Failed, there's no pi,[event_status=%d]\n", __func__, rds->event_status);
*pi = -1;
ret = -ERR_RDS_NO_DATA;
}
return ret;
}
int COM_get_ecc(int fd, RDSData_Struct *rds, uint8_t *ecc)
{
int ret = 0;
UNUSED(fd);
FMR_ASSERT(rds);
FMR_ASSERT(ecc);
if (rds->event_status & RDS_EVENT_ECC_CODE) {
LOGD("%s, Success,[event_status=%d] [ECC=%d]\n", __func__,
rds->event_status, rds->Extend_Country_Code);
*ecc = rds->Extend_Country_Code;
} else {
LOGI("%s, Failed, there's no ECC,[event_status=%d]\n", __func__, rds->event_status);
*ecc = -1;
ret = -ERR_RDS_NO_DATA;
}
return ret;
}
int COM_get_pty(int fd, RDSData_Struct *rds, uint8_t *pty)
{
int ret = 0;
UNUSED(fd);
FMR_ASSERT(rds);
FMR_ASSERT(pty);
if(rds->event_status&RDS_EVENT_PTY_CODE){
LOGD("%s, Success,[event_status=%d] [PTY=%d]\n", __func__, rds->event_status, rds->PTY);
*pty = rds->PTY;
}else{
LOGI("%s, Success, there's no pty,[event_status=%d]\n", __func__, rds->event_status);
*pty = -1;
ret = -ERR_RDS_NO_DATA;
}
return ret;
}
int COM_tune(int fd, int freq, int band)
{
int ret = 0;
struct fm_tune_parm parm;
bzero(&parm, sizeof(struct fm_tune_parm));
parm.band = band;
parm.freq = freq;
parm.hilo = FM_AUTO_HILO_OFF;
parm.space = FM_SEEK_SPACE;
ret = ioctl(fd, FM_IOCTL_TUNE, &parm);
if (ret) {
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [freq=%d] [ret=%d]\n", __func__, fd, freq, ret);
return ret;
}
int COM_seek(int fd, int *freq, int band, int dir, int lev)
{
int ret = 0;
struct fm_seek_parm parm;
bzero(&parm, sizeof(struct fm_tune_parm));
parm.band = band;
parm.freq = *freq;
parm.hilo = FM_AUTO_HILO_OFF;
parm.space = FM_SEEK_SPACE;
if (dir == 1) {
parm.seekdir = FM_SEEK_UP;
} else if (dir == 0) {
parm.seekdir = FM_SEEK_DOWN;
}
parm.seekth = lev;
ret = ioctl(fd, FM_IOCTL_SEEK, &parm);
if (ret == 0) {
*freq = parm.freq;
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_set_mute(int fd, int mute)
{
int ret = 0;
int tmp = mute;
LOGD("%s, start \n", __func__);
ret = ioctl(fd, FM_IOCTL_MUTE, &tmp);
if (ret) {
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_is_fm_pwrup(int fd, int *pwrup)
{
int ret = 0;
ret = ioctl(fd, FM_IOCTL_IS_FM_POWERED_UP, pwrup);
if (ret) {
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
/******************************************
* Inquiry if RDS is support in driver.
* Parameter:
* None
*supt Value:
* 1: support
* 0: NOT support
* -1: error
******************************************/
int COM_is_rdsrx_support(int fd, int *supt)
{
int ret = 0;
int support = -1;
if (fd < 0) {
LOGE("FM isRDSsupport fail, g_fm_fd = %d\n", fd);
*supt = -1;
ret = -ERR_INVALID_FD;
return ret;
}
ret = ioctl(fd, FM_IOCTL_RDS_SUPPORT, &support);
if (ret) {
LOGE("FM FM_IOCTL_RDS_SUPPORT fail, errno = %d\n", errno);
//don't support
*supt = 0;
return ret;
}
LOGI("isRDSsupport Success,[support=%d]\n", support);
*supt = support;
return ret;
}
int COM_pre_search(int fd)
{
fm_s32 ret = 0;
ret = ioctl(fd, FM_IOCTL_PRE_SEARCH, 0);
LOGD("COM_pre_search:%d\n",ret);
return ret;
}
int COM_restore_search(int fd)
{
fm_s32 ret = 0;
ret = ioctl(fd, FM_IOCTL_RESTORE_SEARCH, 0);
LOGD("COM_restore_search:%d\n",ret);
return ret;
}
/*soft mute tune function, usually for sw scan implement or CQI log tool*/
int COM_Soft_Mute_Tune(int fd, fm_softmute_tune_t *para)
{
fm_s32 ret = 0;
//fm_s32 RSSI = 0, PAMD = 0,MR = 0, ATDC = 0;
//fm_u32 PRX = 0;
//fm_u16 softmuteGainLvl = 0;
fm_softmute_tune_t value;
value.freq = para->freq;
ret = ioctl(fd, FM_IOCTL_SOFT_MUTE_TUNE, &value);
if (ret) {
LOGE("FM soft mute tune faild:%d\n",ret);
return ret;
}
#if 0
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);
RSSI = ((value.RSSI & 0x03FF) >= 512) ? ((value.RSSI & 0x03FF) - 1024) : (value.RSSI & 0x03FF);
PAMD = ((value.PAMD & 0xFF) >= 128) ? ((value.PAMD & 0x00FF) - 256) : (value.PAMD & 0x00FF);
MR = ((value.MR & 0x01FF) >= 256) ? ((value.MR & 0x01FF) - 512) : (value.MR & 0x01FF);
ATDC =((value.ATDC & 0x0FFF) >= 2048) ? ((value.ATDC & 0x0FFF) - 4096) : (value.ATDC & 0x0FFF);
if (ATDC < 0) {
ATDC = (~(ATDC)) - 1;//Get abs value of ATDC
}
PRX = (value.PRX & 0x00FF);
softmuteGainLvl = value.SMG;
//check if the channel is valid according to each CQIs
if ((RSSI >= RSSI_TH)
&& (PAMD <= PAMD_TH)
&& (ATDC <= ATDC_TH)
&& (MR >= MR_TH)
&& (PRX >= PRX_TH)
&& (softmuteGainLvl <= softMuteGainTH)) {
para->valid = fm_true;
} else {
para->valid = fm_false;
}
#endif
para->valid = value.valid;
para->rssi = value.rssi;
//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);
return 0;
}
int COM_get_cqi(int fd, int num, char *buf, int buf_len)
{
int ret;
struct fm_cqi_req cqi_req;
//check buf
num = (num > CQI_CH_NUM_MAX) ? CQI_CH_NUM_MAX : num;
num = (num < CQI_CH_NUM_MIN) ? CQI_CH_NUM_MIN : num;
cqi_req.ch_num = (uint16_t)num;
cqi_req.buf_size = cqi_req.ch_num * sizeof(struct fm_cqi);
if (!buf || (buf_len < cqi_req.buf_size)) {
LOGE("get cqi, invalid buf\n");
return -1;
}
cqi_req.cqi_buf = buf;
//get cqi from driver
ret = ioctl(fd, FM_IOCTL_CQI_GET, &cqi_req);
if (ret < 0) {
LOGE("get cqi, failed %d\n", ret);
return -1;
}
return 0;
}
int COM_turn_on_off_rds(int fd, int onoff)
{
int ret = 0;
uint16_t rds_on = -1;
LOGD("Rdsset start\n");
if (onoff == FMR_RDS_ON) {
rds_on = 1;
ret = ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
if (ret) {
LOGE("FM_IOCTL_RDS_ON failed\n");
return ret;
}
LOGD("Rdsset Success,[rds_on=%d]\n", rds_on);
} else {
rds_on = 0;
ret = ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
if (ret) {
LOGE("FM_IOCTL_RDS_OFF failed\n");
return ret;
}
LOGD("Rdsset Success,[rds_on=%d]\n", rds_on);
}
return ret;
}
int COM_read_rds_data(int fd, RDSData_Struct *rds, uint16_t *rds_status)
{
int ret = 0;
uint16_t event_status;
//char tmp_ps[9] = {0};
//char tmp_rt[65] = { 0 };
FMR_ASSERT(rds);
FMR_ASSERT(rds_status);
if (read(fd, rds, sizeof(RDSData_Struct)) == sizeof(RDSData_Struct)) {
event_status = rds->event_status;
//memcpy(tmp_ps, &rds->PS_Data.PS[3][0], 8);
//memcpy(tmp_rt, &rds->RT_Data.TextData[3][0], 64);
LOGI("event_status = 0x%x\n", event_status);
//memset(tmp_ps, 0, 9);
//memset(tmp_rt, 0, 65);
*rds_status = event_status;
return ret;
} else {
//LOGE("readrds get no event\n");
ret = -ERR_RDS_NO_DATA;
}
return ret;
}
static int COM_get_af_pi(int fd, uint16_t *pi)
{
int ret;
struct rds_raw_data rrd;
uint16_t pi1, pi2;
FMR_ASSERT(pi);
memset(&rrd, 0, sizeof(rrd));
ret = ioctl(fd, FM_IOCTL_RDS_GET_LOG, &rrd);
if (ret) {
LOGE("COM_get_af_pi fail(%d)\n", ret);
*pi = 0;
return ret;
}
if (rrd.len == 0) {
LOGE("COM_get_af_pi fail, RDS log empty!\n");
*pi = 0;
return -1;
}
pi1 = rrd.data[4];
pi1 |= (rrd.data[5] << 8);
LOGI("data[4]=%02x,data[5]=%02x,pi1=%04x\n", rrd.data[4], rrd.data[5], pi1);
pi2 = rrd.data[16];
pi2 |= (rrd.data[17] << 8);
LOGI("data[16]=%02x,data[17]=%02x,pi2=%04x\n", rrd.data[16], rrd.data[17], pi2);
if (pi1 == pi2) {
LOGI("got af pi!!!\n");
*pi = pi1;
} else {
LOGE("af pi check fail\n");
*pi = 0;
return -1;
}
return 0;
}
int COM_active_af(int fd, RDSData_Struct *rds, CUST_cfg_ds *cfg_data, uint16_t orig_pi, uint16_t cur_freq, uint16_t *ret_freq)
{
int ret = 0;
int i = 0, j = 0;
struct fm_tune_parm parm;
struct fm_softmute_tune_t smt_parm;
uint16_t set_freq = 0, sw_freq = 0, org_freq = 0;
uint16_t PAMD_Value = 0, AF_PAMD_LBound = 0, AF_PAMD_HBound = 0;
uint16_t PAMD_Level[25];
uint16_t PI[25];
uint16_t PAMD_DB_TBL[5] = {// 5dB, 10dB, 15dB, 20dB, 25dB,
// 13, 17, 21, 25, 29};
8, 12, 15, 18, 20};
AF_Info af_list_backup;
AF_Info af_list;
FMR_ASSERT(rds);
FMR_ASSERT(cfg_data);
sw_freq = cur_freq; //current freq
org_freq = cur_freq;
parm.band = cfg_data->band;
parm.freq = sw_freq;
parm.hilo = FM_AUTO_HILO_OFF;
parm.space = FM_SPACE_DEFAULT;
if (!(rds->event_status & RDS_EVENT_AF)) {
LOGE("activeAF failed\n");
*ret_freq = 0;
ret = -ERR_RDS_NO_DATA;
return ret;
}
memset(&af_list_backup, 0, sizeof(af_list_backup));
memcpy(&af_list_backup, &rds->AF_Data, sizeof(AF_Info));
memset(&af_list, 0, sizeof(af_list));
AF_PAMD_LBound = PAMD_DB_TBL[0]; //5dB
AF_PAMD_HBound = PAMD_DB_TBL[1]; //15dB
ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Value);
for (i = 0; i < 3 && (PAMD_Value < AF_PAMD_LBound); i++) {
usleep(10 * 1000);
ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Value);
LOGI("check PAMD %d time(s), PAMD =%d", i+1, PAMD_Value);
}
LOGI("current_freq=%d, PAMD_Value=%d, orig_pi=%d\n", cur_freq, PAMD_Value, orig_pi);
/* Start to detect AF channels when orignal channel turn weak */
if (PAMD_Value < AF_PAMD_LBound) {
/* Make sure rds->AF_Data.AF_Num is valid */
af_list_backup.AF_Num = af_list_backup.AF_Num > 25 ? 25 : af_list_backup.AF_Num;
/* Precheck af list*/
for (i = 0, j = 0; i < af_list_backup.AF_Num; i++) {
set_freq = af_list_backup.AF[1][i];
if(set_freq < cfg_data->low_band || set_freq > cfg_data->high_band) {
/*band check fail*/
LOGI("AF[1][%d]:freq %d out of bandwidth[%d,%d], skip!\n",
i, af_list_backup.AF[1][i], cfg_data->low_band, cfg_data->high_band);
continue;
}
/* Using Com_Soft_Mute_Tune to query valid channel*/
memset(&smt_parm, 0, sizeof(fm_softmute_tune_t));
smt_parm.freq = set_freq;
COM_Soft_Mute_Tune(fd, &smt_parm);
LOGE("af list pre-check:freq %d, valid:%d\n", smt_parm.freq, smt_parm.valid);
if(smt_parm.valid == 1) {
/* Update valid AF channel to af_list*/
af_list.AF[1][j] = af_list_backup.AF[1][i];
j++;
af_list.AF_Num++;
}
}
/*AF switch process*/
for (i = 0; i < af_list.AF_Num; i++) {
set_freq = af_list.AF[1][i];
LOGI("set_freq[%d] = %d, org_freq = %d\n", i, set_freq, org_freq);
if (set_freq != org_freq) {
// Set mute to check every af channels
COM_set_mute(fd, 1);
parm.freq = set_freq;
ioctl(fd, FM_IOCTL_TUNE, &parm);
usleep(20 * 1000);
ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Level[i]);
/* If signal is not good enough, skip */
if (PAMD_Level[i] < AF_PAMD_HBound) {
LOGI("PAMD_Level[%d] =%d < AF_PAMD_HBound, continue", i, PAMD_Level[i]);
continue;
}
for (j = 0 ; j < 5; j++ ) {
usleep(200 * 1000);
/* Query pi to 5 times */
if (COM_get_af_pi(fd, &PI[i])) {
if (j == 4)
LOGE("get af pi fail\n");
continue;
} else
break;
}
if (orig_pi != PI[i]) {
LOGI("pi not match, current pi(%04x), orig pi(%04x)\n", PI[i], orig_pi);
continue;
}
LOGI("next_freq=%d, PAMD_Level[%d]=%d\n", parm.freq, i, PAMD_Level[i]);
/* To get largest PAMD */
/* This is a trade-off*/
/* If want to get a better quality AF channel, do as follows, it will spend longer to do AF switch*/
/* If want to mute shorter, just use one fixed PAMD_VALUE, don't need to compare */
if (PAMD_Level[i] > AF_PAMD_HBound) {
LOGI("PAMD_Level[%d] =%d > AF_PAMD_HBound, af switch", i, PAMD_Level[i]);
sw_freq = set_freq;
PAMD_Value = PAMD_Level[i];
break;
}
}
}
LOGI("AF deside tune to freq: %d, PAMD_Level: %d\n", sw_freq, PAMD_Value);
if ((PAMD_Value > AF_PAMD_HBound)&&(sw_freq != 0)) { /* Tune to AF channel */
parm.freq = sw_freq;
ioctl(fd, FM_IOCTL_TUNE, &parm);
cur_freq = parm.freq;
} else { /* Tune to orignal channel */
parm.freq = org_freq;
ioctl(fd, FM_IOCTL_TUNE, &parm);
cur_freq = parm.freq;
}
/* Unmute when finish AF switch */
COM_set_mute(fd, 0);
} else {
LOGD("RDS_EVENT_AF old freq:%d\n", org_freq);
}
*ret_freq = cur_freq;
return ret;
}
int COM_active_ta(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *backup_freq, uint16_t *ret_freq)
{
int ret = 0;
FMR_ASSERT(rds);
FMR_ASSERT(backup_freq);
FMR_ASSERT(ret_freq);
if(rds->event_status&RDS_EVENT_TAON){
uint16_t rds_on = 0;
struct fm_tune_parm parm;
uint16_t PAMD_Level[25];
uint16_t PAMD_DB_TBL[5] = {13, 17, 21, 25, 29};
uint16_t set_freq, sw_freq, org_freq, PAMD_Value, TA_PAMD_Threshold;
int i = 0;
rds_on = 0;
ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
TA_PAMD_Threshold = PAMD_DB_TBL[2]; //15dB
sw_freq = cur_freq;
org_freq = cur_freq;
*backup_freq = org_freq;
parm.band = band;
parm.freq = sw_freq;
parm.hilo = FM_AUTO_HILO_OFF;
parm.space = COM_get_seek_space();
ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Value);
//make sure rds->AF_Data.AF_Num is valid
rds->AFON_Data.AF_Num = (rds->AFON_Data.AF_Num > 25)? 25 : rds->AFON_Data.AF_Num;
for(i=0; i< rds->AFON_Data.AF_Num; i++){
set_freq = rds->AFON_Data.AF[1][i];
LOGI("set_freq=0x%02x,org_freq=0x%02x\n", set_freq, org_freq);
if(set_freq != org_freq){
parm.freq = sw_freq;
ioctl(fd, FM_IOCTL_TUNE, &parm);
ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Level[i]);
if(PAMD_Level[i] > PAMD_Value){
PAMD_Value = PAMD_Level[i];
sw_freq = set_freq;
}
}
}
if((PAMD_Value > TA_PAMD_Threshold)&&(sw_freq != 0)){
rds->Switch_TP= 1;
parm.freq = sw_freq;
ioctl(fd, FM_IOCTL_TUNE, &parm);
cur_freq = parm.freq;
}else{
parm.freq = org_freq;
ioctl(fd, FM_IOCTL_TUNE, &parm);
cur_freq = parm.freq;
}
rds_on = 1;
ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
}
*ret_freq = cur_freq;
return ret;
}
int COM_deactive_ta(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *backup_freq, uint16_t *ret_freq)
{
int ret = 0;
UNUSED(band);
FMR_ASSERT(rds);
FMR_ASSERT(backup_freq);
FMR_ASSERT(ret_freq);
if(rds->event_status&RDS_EVENT_TAON_OFF){
uint16_t rds_on = 0;
struct fm_tune_parm parm;
parm.band = FM_RAIDO_BAND;
parm.freq = *backup_freq;
parm.hilo = FM_AUTO_HILO_OFF;
parm.space = COM_get_seek_space();
ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
ioctl(fd, FM_IOCTL_TUNE, &parm);
cur_freq = parm.freq;
rds_on = 1;
ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
}
*ret_freq = cur_freq;
return ret;
}
int COM_ana_switch(int fd, int antenna)
{
int ret = 0;
ret = ioctl(fd, FM_IOCTL_ANA_SWITCH, &antenna);
if (ret < 0) {
LOGE("%s: fail, ret = %d\n", __func__, ret);
}
LOGD("%s: [ret = %d]\n", __func__, ret);
return ret;
}
int COM_get_badratio(int fd, int *badratio)
{
int ret = 0;
uint16_t tmp = 0;
ret = ioctl(fd, FM_IOCTL_GETBLERRATIO, &tmp);
*badratio = (int)tmp;
if (ret){
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_get_stereomono(int fd, int *stemono)
{
int ret = 0;
uint16_t tmp = 0;
ret = ioctl(fd, FM_IOCTL_GETMONOSTERO, &tmp);
*stemono = (int)tmp;
if (ret){
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_set_stereomono(int fd, int stemono)
{
int ret = 0;
ret = ioctl(fd, FM_IOCTL_SETMONOSTERO, &stemono);
if (ret){
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_get_caparray(int fd, int *caparray)
{
int ret = 0;
int tmp = 0;
LOGD("%s, [fd=%d]\n", __func__, fd);
ret = ioctl(fd, FM_IOCTL_GETCAPARRAY, &tmp);
if (ret){
LOGE("%s, failed\n", __func__);
}
*caparray = tmp;
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
int COM_get_hw_info(int fd, struct fm_hw_info *info)
{
int ret = 0;
ret = ioctl(fd, FM_IOCTL_GET_HW_INFO, info);
if(ret){
LOGE("%s, failed\n", __func__);
}
LOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd, ret);
return ret;
}
/* COM_is_dese_chan -- check if gived channel is a de-sense channel or not
* @fd - fd of "dev/fm"
* @freq - gived channel
* return value: 0, not a dese chan; 1, a dese chan; else error NO.
*/
int COM_is_dese_chan(int fd, int freq)
{
int ret = 0;
int tmp = freq;
ret = ioctl(fd, FM_IOCTL_IS_DESE_CHAN, &freq);
if (ret < 0) {
LOGE("%s, failed,ret=%d\n", __func__,ret);
return ret;
} else {
LOGD("[fd=%d] %d --> dese=%d\n", fd, tmp, freq);
return freq;
}
}
/* COM_desense_check -- check if gived channel is a de-sense channel or not
* @fd - fd of "dev/fm"
* @freq - gived channel
* @rssi-freq's rssi
* 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.
*/
int COM_desense_check(int fd, int freq, int rssi)
{
int ret = 0;
fm_desense_check_t parm;
parm.freq = freq;
parm.rssi = rssi;
ret = ioctl(fd, FM_IOCTL_DESENSE_CHECK, &parm);
if (ret < 0) {
LOGE("%s, failed,ret=%d\n", __func__,ret);
return ret;
} else {
LOGD("[fd=%d] %d --> dese=%d\n", fd,freq,ret);
return ret;
}
}
/*
th_idx:
threshold type: 0, RSSI. 1,desense RSSI. 2,SMG.
th_val: threshold value*/
int COM_set_search_threshold(int fd, int th_idx,int th_val)
{
int ret = 0;
fm_search_threshold_t th_parm;
th_parm.th_type = th_idx;
th_parm.th_val = th_val;
ret = ioctl(fd, FM_IOCTL_SET_SEARCH_THRESHOLD, &th_parm);
if (ret < 0)
{
LOGE("%s, failed,ret=%d\n", __func__,ret);
}
return ret;
}
int COM_full_cqi_logger(int fd, fm_full_cqi_log_t *log_parm)
{
int ret = 0;
ret = ioctl(fd, FM_IOCTL_FULL_CQI_LOG, log_parm);
if (ret < 0)
{
LOGE("%s, failed,ret=%d\n", __func__,ret);
}
return ret;
}
void FM_interface_init(struct fm_cbk_tbl *cbk_tbl)
{
//Basic functions.
cbk_tbl->open_dev = COM_open_dev;
cbk_tbl->close_dev = COM_close_dev;
cbk_tbl->pwr_up = COM_pwr_up;
cbk_tbl->pwr_down = COM_pwr_down;
cbk_tbl->tune = COM_tune;
cbk_tbl->set_mute = COM_set_mute;
cbk_tbl->is_rdsrx_support = COM_is_rdsrx_support;
cbk_tbl->turn_on_off_rds = COM_turn_on_off_rds;
cbk_tbl->get_chip_id = COM_get_chip_id;
//For RDS RX.
cbk_tbl->read_rds_data = COM_read_rds_data;
cbk_tbl->get_pi = COM_get_pi;
cbk_tbl->get_ps = COM_get_ps;
cbk_tbl->get_ecc = COM_get_ecc;
cbk_tbl->get_pty = COM_get_pty;
cbk_tbl->get_rssi = COM_get_rssi;
cbk_tbl->get_rt = COM_get_rt;
cbk_tbl->active_af = COM_active_af;
cbk_tbl->active_ta = COM_active_ta;
cbk_tbl->deactive_ta = COM_deactive_ta;
//FM short antenna
cbk_tbl->ana_switch = COM_ana_switch;
cbk_tbl->desense_check = COM_desense_check;
//RX EM mode use
cbk_tbl->get_badratio = COM_get_badratio;
cbk_tbl->get_stereomono = COM_get_stereomono;
cbk_tbl->set_stereomono = COM_set_stereomono;
cbk_tbl->get_caparray = COM_get_caparray;
cbk_tbl->get_cqi = COM_get_cqi;
cbk_tbl->is_dese_chan = COM_is_dese_chan;
cbk_tbl->desense_check = COM_desense_check;
cbk_tbl->get_hw_info = COM_get_hw_info;
//soft mute tune
cbk_tbl->soft_mute_tune = COM_Soft_Mute_Tune;
cbk_tbl->pre_search = COM_pre_search;
cbk_tbl->restore_search = COM_restore_search;
//EM
cbk_tbl->set_search_threshold = COM_set_search_threshold;
cbk_tbl->full_cqi_logger = COM_full_cqi_logger;
return;
}

263
libfmjni/custom.cpp Normal file
View file

@ -0,0 +1,263 @@
/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*
* MediaTek Inc. (C) 2010. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek
* Software") have been modified by MediaTek Inc. All revisions are subject to
* any receiver's applicable license agreements with MediaTek Inc.
*/
#define MTK_LOG_ENABLE 1
#include <sys/types.h>
#include <stdbool.h>
#include <string.h>
#include <cutils/properties.h>
#include <cutils/log.h>
#include "fmr.h"
#include "fmlib_cust.h"
#undef LOGV
#define LOGV(...) ALOGV(__VA_ARGS__)
#undef LOGD
#define LOGD(...) ALOGD(__VA_ARGS__)
#undef LOGI
#define LOGI(...) ALOGI(__VA_ARGS__)
#undef LOGW
#define LOGW(...) ALOGW(__VA_ARGS__)
#undef LOGE
#define LOGE(...) ALOGE(__VA_ARGS__)
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "FMLIB_CUST"
#define MT6620_FM_FAKE_CHANNEL \
{ \
{10400, -40, -1}, \
{9100, -40, -1}, \
{9600, -40, -1}, \
{9220, -80, -1}, \
{0, 0, 0} \
}
#define MT6628_FM_FAKE_CHANNEL \
{ \
{0, 0, 0} \
}
#define MT6627_FM_FAKE_CHANNEL \
{ \
{9600, -107, -1}, \
{10400, -107, -1}, \
{10750, -224, -1}, \
{0, 0, 0} \
}
#define MT6580_FM_FAKE_CHANNEL \
{ \
{9600, -107, -1}, \
{9570, -258, -1}, \
{9580, -258, -1}, \
{9590, -258, -1}, \
{10400, -107, -1}, \
{0, 0, 0} \
}
#define MT6630_FM_FAKE_CHANNEL \
{ \
{9600,-107,-1}, \
{10400,-107,-1}, \
{0, 0, 0} \
}
#define MT6631_FM_FAKE_CHANNEL \
{ \
{9210, -205, -1}, \
{9600, -152, -1}, \
{10400, -152, -1}, \
{10750, -205, -1}, \
{0, 0, 0} \
}
#define MT6632_FM_FAKE_CHANNEL \
{ \
{9600, -107, -1}, \
{10400, -107, -1}, \
{0, 0, 0} \
}
static struct fm_fake_channel mt6620_fake_ch[] = MT6620_FM_FAKE_CHANNEL;
static struct fm_fake_channel mt6627_fake_ch[] = MT6627_FM_FAKE_CHANNEL;
static struct fm_fake_channel mt6628_fake_ch[] = MT6628_FM_FAKE_CHANNEL;
static struct fm_fake_channel mt6580_fake_ch[] = MT6580_FM_FAKE_CHANNEL;
static struct fm_fake_channel mt6630_fake_ch[] = MT6630_FM_FAKE_CHANNEL;
static struct fm_fake_channel mt6631_fake_ch[] = MT6631_FM_FAKE_CHANNEL;
static struct fm_fake_channel mt6632_fake_ch[] = MT6632_FM_FAKE_CHANNEL;
static struct fm_fake_channel_t fake_ch_info = {0, 0};
void CUST_update_cfg(struct CUST_cfg_ds *cfg, int chipid)
{
struct fm_fake_channel *fake_ch = NULL;
LOGI("update connsys chipid=0x%x\n", chipid);
switch (chipid)
{
case FM_CHIP_MT6580:
cfg->chip = FM_CHIP_MT6580;
fake_ch = mt6580_fake_ch;
break;
case FM_CHIP_MT6620:
cfg->chip = FM_CHIP_MT6620;
fake_ch = mt6620_fake_ch;
break;
case FM_CHIP_MT6627:
cfg->chip = FM_CHIP_MT6627;
fake_ch = mt6627_fake_ch;
break;
case FM_CHIP_MT6628:
cfg->chip = FM_CHIP_MT6628;
fake_ch = mt6628_fake_ch;
break;
case FM_CHIP_MT6630:
cfg->chip = FM_CHIP_MT6630;
fake_ch = mt6630_fake_ch;
break;
case FM_CHIP_MT6631:
cfg->chip = FM_CHIP_MT6631;
fake_ch = mt6631_fake_ch;
break;
case FM_CHIP_MT6632:
cfg->chip = FM_CHIP_MT6632;
fake_ch = mt6632_fake_ch;
break;
case FM_CHIP_MT6635:
cfg->chip = FM_CHIP_MT6635;
fake_ch = mt6631_fake_ch;
break;
default:
LOGE("not support chipid=0x%x\n", chipid);
break;
}
cfg->band = FM_RAIDO_BAND; // 1, UE; 2, JAPAN; 3, JAPANW
cfg->low_band = FM_FREQ_MIN * 10;
cfg->high_band = FM_FREQ_MAX * 10;
if (property_get_int32("persist.vendor.connsys.fm_50khz_support", 0) == 1) {
cfg->seek_space = 5; // FM radio seek space, 5:50KHZ; 1:100KHZ; 2:200KHZ
} else {
cfg->seek_space = 1;
}
cfg->max_scan_num = FM_MAX_CHL_SIZE;
cfg->seek_lev = FM_SEEKTH_LEVEL_DEFAULT;
cfg->scan_sort = FM_SCAN_SORT_SELECT;
if (property_get_int32("persist.vendor.connsys.fm_short_antenna_support", 0) == 1) {
cfg->short_ana_sup = fm_false;
} else {
cfg->short_ana_sup = fm_true;
}
cfg->rssi_th_l2 = FM_CHIP_DESE_RSSI_TH;
cfg->rssi_th_l2 = (cfg->rssi_th_l2 > -72) ? -72 : cfg->rssi_th_l2;
cfg->rssi_th_l2 = (cfg->rssi_th_l2 < -102) ? -102 : cfg->rssi_th_l2;
if (fake_ch) {
fake_ch_info.chan = fake_ch;
fake_ch_info.size = 0;
while (fake_ch[fake_ch_info.size].freq > 0) {
fake_ch_info.size++;
}
}
cfg->fake_chan = &fake_ch_info;
}
int CUST_get_cfg(struct CUST_cfg_ds *cfg)
{
char val[PROPERTY_VALUE_MAX] = {0};
int chipid = FM_CHIP_UNSUPPORTED;
if (property_get("persist.vendor.connsys.fm_chipid", val, NULL)) {
if (strcmp(val, "soc") == 0) {
chipid = FM_CHIP_MT6580;
} else if (strcmp(val, "mt6620") == 0) {
chipid = FM_CHIP_MT6620;
} else if (strcmp(val, "mt6627") == 0) {
chipid = FM_CHIP_MT6627;
} else if (strcmp(val, "mt6628") == 0) {
chipid = FM_CHIP_MT6628;
} else if (strcmp(val, "mt6630") == 0) {
chipid = FM_CHIP_MT6630;
} else if (strcmp(val, "mt6631") == 0) {
chipid = FM_CHIP_MT6631;
} else if (strcmp(val, "mt6632") == 0) {
chipid = FM_CHIP_MT6632;
} else if ((strcmp(val, "mt6635") == 0)
|| (strcmp(val, "connac2x") == 0)) {
chipid = FM_CHIP_MT6635;
}
}
if (chipid == FM_CHIP_UNSUPPORTED) {
if (property_get("vendor.connsys.fm.adie.chipid", val, NULL)) {
if (strcmp(val, "0x6631") == 0) {
chipid = FM_CHIP_MT6631;
} else if ((strcmp(val, "0x6635") == 0)
|| (strcmp(val, "0x6637") == 0)) {
chipid = FM_CHIP_MT6635;
} else {
LOGE("not support chipid=%s\n", val);
}
} else if (property_get("vendor.connsys.adie.chipid", val, NULL)) {
if (strcmp(val, "0x6631") == 0) {
chipid = FM_CHIP_MT6631;
} else if ((strcmp(val, "0x6635") == 0)
|| (strcmp(val, "0x6637") == 0)) {
chipid = FM_CHIP_MT6635;
} else {
LOGE("not support chipid=%s\n", val);
}
} else {
LOGE("get vendor.connsys.fm.adie.chipid fail\n");
}
}
CUST_update_cfg(cfg, chipid);
return 0;
}

547
libfmjni/fm.h Executable file
View file

@ -0,0 +1,547 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FM_H__
#define __FM_H__
#include <linux/ioctl.h>
#include <linux/time.h>
typedef signed char fm_s8;
typedef signed short fm_s16;
typedef signed int fm_s32;
typedef signed long long fm_s64;
typedef unsigned char fm_u8;
typedef unsigned short fm_u16;
typedef unsigned int fm_u32;
typedef unsigned long long fm_u64;
typedef enum fm_bool {
fm_false = 0,
fm_true = 1
} fm_bool;
// scan sort algorithm
enum {
FM_SCAN_SORT_NON = 0,
FM_SCAN_SORT_UP,
FM_SCAN_SORT_DOWN,
FM_SCAN_SORT_MAX
};
// scan methods
enum {
FM_SCAN_SEL_HW = 0, // select hardware scan, advantage: fast
FM_SCAN_SEL_SW, // select software scan, advantage: more accurate
FM_SCAN_SEL_MAX
};
//*****************************************************************************************
//***********************************FM config for customer *******************************
//*****************************************************************************************
#define FMR_RSSI_TH_LONG 0x0301 // FM radio long antenna RSSI threshold(11.375dBuV)
#define FMR_RSSI_TH_SHORT 0x02E0 // FM radio short antenna RSSI threshold(-1dBuV)
#define FMR_CQI_TH 0x00E9 // FM radio Channel quality indicator threshold(0x0000~0x00FF)
#define FMR_SEEK_SPACE 1 // FM radio seek space,1:100KHZ; 2:200KHZ
#define FMR_SCAN_CH_SIZE 40 // FM radio scan max channel size
#define FMR_BAND 1 // FM radio band, 1:87.5MHz~108.0MHz; 2:76.0MHz~90.0MHz;
// 3:76.0MHz~108.0MHz; 4:special
#define FMR_BAND_FREQ_L 875 // FM radio special band low freq(Default 87.5MHz)
#define FMR_BAND_FREQ_H 1080 // FM radio special band high freq(Default 108.0MHz)
#define FM_SCAN_SORT_SELECT FM_SCAN_SORT_NON
#define FM_SCAN_SELECT FM_SCAN_SEL_HW
#define FM_SCAN_SOFT_MUTE_GAIN_TH 3 // soft-mute threshold when software scan, rang: 0~3,
// 0 means better audio quality but less channel
#define FM_CHIP_DESE_RSSI_TH (-102) // rang: -102 ~ -72
//*****************************************************************************************
//***********************************FM config for engineer *******************************
//*****************************************************************************************
#define FMR_MR_TH 0x01BD // FM radio MR threshold
#define ADDR_SCAN_TH 0xE0 // scan thrshold register
#define ADDR_CQI_TH 0xE1 // scan CQI register
//*****************************************************************************************
#define FM_NAME "fm"
#define FM_DEVICE_NAME "/dev/fm"
// errno
#define FM_SUCCESS 0
#define FM_FAILED 1
#define FM_EPARM 2
#define FM_BADSTATUS 3
#define FM_TUNE_FAILED 4
#define FM_SEEK_FAILED 5
#define FM_BUSY 6
#define FM_SCAN_FAILED 7
// band
#define FM_BAND_UNKNOWN 0
#define FM_BAND_UE 1 // US/Europe band 87.5MHz ~ 108MHz (DEFAULT)
#define FM_BAND_JAPAN 2 // Japan band 76MHz ~ 90MHz
#define FM_BAND_JAPANW 3 // Japan wideband 76MHZ ~ 108MHz
#define FM_BAND_SPECIAL 4 // special band between 76MHZ and 108MHz
#define FM_BAND_DEFAULT FM_BAND_UE
#define FM_UE_FREQ_MIN 875
#define FM_UE_FREQ_MAX 1080
#define FM_JP_FREQ_MIN 760
#define FM_JP_FREQ_MAX 1080
#define FM_FREQ_MIN FMR_BAND_FREQ_L
#define FM_FREQ_MAX FMR_BAND_FREQ_H
#define FM_RAIDO_BAND FM_BAND_UE
// space
#define FM_SPACE_UNKNOWN 0
#define FM_SPACE_100K 1
#define FM_SPACE_200K 2
#define FM_SPACE_50K 5
#define FM_SPACE_DEFAULT FM_SPACE_100K
#define FM_SEEK_SPACE FMR_SEEK_SPACE
// max scan channel num
#define FM_MAX_CHL_SIZE FMR_SCAN_CH_SIZE
// auto HiLo
#define FM_AUTO_HILO_OFF 0
#define FM_AUTO_HILO_ON 1
// seek direction
#define FM_SEEK_UP 0
#define FM_SEEK_DOWN 1
// seek threshold
#define FM_SEEKTH_LEVEL_DEFAULT 4
struct fm_tune_parm {
uint8_t err;
uint8_t band;
uint8_t space;
uint8_t hilo;
uint8_t deemphasis;
uint16_t freq;
};
struct fm_seek_parm {
uint8_t err;
uint8_t band;
uint8_t space;
uint8_t hilo;
uint8_t seekdir;
uint8_t seekth;
uint16_t freq;
};
struct fm_scan_parm {
uint8_t err;
uint8_t band;
uint8_t space;
uint8_t hilo;
uint16_t freq;
uint16_t ScanTBL[16];
uint16_t ScanTBLSize;
};
struct fm_ch_rssi {
uint16_t freq;
int rssi;
};
enum fm_scan_cmd_t {
FM_SCAN_CMD_INIT = 0,
FM_SCAN_CMD_START,
FM_SCAN_CMD_GET_NUM,
FM_SCAN_CMD_GET_CH,
FM_SCAN_CMD_GET_RSSI,
FM_SCAN_CMD_GET_CH_RSSI,
FM_SCAN_CMD_MAX
};
struct fm_scan_t {
enum fm_scan_cmd_t cmd;
int ret; // 0, success; else error code
uint16_t lower; // lower band, Eg, 7600 -> 76.0Mhz
uint16_t upper; // upper band, Eg, 10800 -> 108.0Mhz
int space; // 5: 50KHz, 10: 100Khz, 20: 200Khz
int num; // valid channel number
void *priv;
int sr_size; // scan result buffer size in bytes
union {
uint16_t *ch_buf; // channel buffer
int *rssi_buf; // rssi buffer
struct fm_ch_rssi *ch_rssi_buf; //channel and RSSI buffer
} sr;
};
struct fm_seek_t {
int ret; // 0, success; else error code
uint16_t freq;
uint16_t lower; // lower band, Eg, 7600 -> 76.0Mhz
uint16_t upper; // upper band, Eg, 10800 -> 108.0Mhz
int space; // 5: 50KHz, 10: 100Khz, 20: 200Khz
int dir; // 0: up; 1: down
int th; // seek threshold in dbm(Eg, -95dbm)
void *priv;
};
struct fm_tune_t {
int ret; // 0, success; else error code
uint16_t freq;
uint16_t lower; // lower band, Eg, 7600 -> 76.0Mhz
uint16_t upper; // upper band, Eg, 10800 -> 108.0Mhz
int space; // 5: 50KHz, 10: 100Khz, 20: 200Khz
void *priv;
};
struct fm_softmute_tune_t {
fm_s32 rssi; // RSSI of current channel
fm_u16 freq; // current frequency
fm_bool valid; // current channel is valid(true) or not(false)
};
struct fm_rssi_req {
uint16_t num;
uint16_t read_cnt;
struct fm_ch_rssi cr[16*16];
};
struct fm_hw_info {
int chip_id;
int eco_ver;
int rom_ver;
int patch_ver;
int reserve;
};
struct fm_search_threshold_t {
fm_s32 th_type;// 0, RSSI. 1,desense RSSI. 2,SMG.
fm_s32 th_val; //threshold value
fm_s32 reserve;
};
#define NEED_DEF_RDS 1
#if NEED_DEF_RDS
//For RDS feature
typedef struct {
uint8_t TP;
uint8_t TA;
uint8_t Music;
uint8_t Stereo;
uint8_t Artificial_Head;
uint8_t Compressed;
uint8_t Dynamic_PTY;
uint8_t Text_AB;
uint32_t flag_status;
} RDSFlag_Struct;
typedef struct {
uint16_t Month;
uint16_t Day;
uint16_t Year;
uint16_t Hour;
uint16_t Minute;
uint8_t Local_Time_offset_signbit;
uint8_t Local_Time_offset_half_hour;
} CT_Struct;
typedef struct {
int16_t AF_Num;
int16_t AF[2][25];
uint8_t Addr_Cnt;
uint8_t isMethod_A;
uint8_t isAFNum_Get;
} AF_Info;
typedef struct {
uint8_t PS[4][8];
uint8_t Addr_Cnt;
} PS_Info;
typedef struct {
uint8_t TextData[4][64];
uint8_t GetLength;
uint8_t isRTDisplay;
uint8_t TextLength;
uint8_t isTypeA;
uint8_t BufCnt;
uint16_t Addr_Cnt;
} RT_Info;
struct rds_raw_data {
int dirty; // indicate if the data changed or not
int len; // the data len form chip
uint8_t data[148];
};
struct rds_group_cnt {
unsigned int total;
unsigned int groupA[16]; // RDS groupA counter
unsigned int groupB[16]; // RDS groupB counter
};
enum rds_group_cnt_opcode {
RDS_GROUP_CNT_READ = 0,
RDS_GROUP_CNT_WRITE,
RDS_GROUP_CNT_RESET,
RDS_GROUP_CNT_MAX
};
struct rds_group_cnt_req {
int err;
enum rds_group_cnt_opcode op;
struct rds_group_cnt gc;
};
typedef struct {
CT_Struct CT;
RDSFlag_Struct RDSFlag;
uint16_t PI;
uint8_t Switch_TP;
uint8_t PTY;
AF_Info AF_Data;
AF_Info AFON_Data;
uint8_t Radio_Page_Code;
uint16_t Program_Item_Number_Code;
uint8_t Extend_Country_Code;
uint16_t Language_Code;
PS_Info PS_Data;
uint8_t PS_ON[8];
RT_Info RT_Data;
uint16_t event_status;
struct rds_group_cnt gc;
} RDSData_Struct;
//valid Rds Flag for notify
typedef enum {
RDS_FLAG_IS_TP = 0x0001, // Program is a traffic program
RDS_FLAG_IS_TA = 0x0002, // Program currently broadcasts a traffic ann.
RDS_FLAG_IS_MUSIC = 0x0004, // Program currently broadcasts music
RDS_FLAG_IS_STEREO = 0x0008, // Program is transmitted in stereo
RDS_FLAG_IS_ARTIFICIAL_HEAD = 0x0010, // Program is an artificial head recording
RDS_FLAG_IS_COMPRESSED = 0x0020, // Program content is compressed
RDS_FLAG_IS_DYNAMIC_PTY = 0x0040, // Program type can change
RDS_FLAG_TEXT_AB = 0x0080 // If this flag changes state, a new radio text string begins
} RdsFlag;
typedef enum {
RDS_EVENT_FLAGS = 0x0001, // One of the RDS flags has changed state
RDS_EVENT_PI_CODE = 0x0002, // The program identification code has changed
RDS_EVENT_PTY_CODE = 0x0004, // The program type code has changed
RDS_EVENT_PROGRAMNAME = 0x0008, // The program name has changed
RDS_EVENT_UTCDATETIME = 0x0010, // A new UTC date/time is available
RDS_EVENT_LOCDATETIME = 0x0020, // A new local date/time is available
RDS_EVENT_LAST_RADIOTEXT = 0x0040, // A radio text string was completed
RDS_EVENT_AF = 0x0080, // Current Channel RF signal strength too weak, need do AF switch
RDS_EVENT_AF_LIST = 0x0100, // An alternative frequency list is ready
RDS_EVENT_AFON_LIST = 0x0200, // An alternative frequency list is ready
RDS_EVENT_TAON = 0x0400, // Other Network traffic announcement start
RDS_EVENT_TAON_OFF = 0x0800, // Other Network traffic announcement finished.
RDS_EVENT_ECC_CODE = 0x1000, /* ECC code */
RDS_EVENT_RDS = 0x2000, // RDS Interrupt had arrived durint timer period
RDS_EVENT_NO_RDS = 0x4000, // RDS Interrupt not arrived durint timer period
RDS_EVENT_RDS_TIMER = 0x8000 // Timer for RDS Bler Check. ---- BLER block error rate
} RdsEvent;
#endif
typedef enum {
FM_I2S_ON = 0,
FM_I2S_OFF,
FM_I2S_STATE_ERR
} fm_i2s_state_e;
typedef enum {
FM_I2S_MASTER = 0,
FM_I2S_SLAVE,
FM_I2S_MODE_ERR
} fm_i2s_mode_e;
typedef enum {
FM_I2S_32K = 0,
FM_I2S_44K,
FM_I2S_48K,
FM_I2S_SR_ERR
} fm_i2s_sample_e;
struct fm_i2s_setting {
int onoff;
int mode;
int sample;
};
typedef enum {
FM_RX = 0,
FM_TX = 1
} FM_PWR_T;
typedef struct fm_i2s_info {
int status; /* 0:FM_I2S_ON, 1:FM_I2S_OFF,2:error */
int mode; /* 0:FM_I2S_MASTER, 1:FM_I2S_SLAVE,2:error */
int rate; /* 0:FM_I2S_32K:32000,1:FM_I2S_44K:44100,2:FM_I2S_48K:48000,3:error */
} fm_i2s_info_t;
typedef enum {
FM_AUD_ANALOG = 0,
FM_AUD_I2S = 1,
FM_AUD_MRGIF = 2,
FM_AUD_ERR
} fm_audio_path_e;
typedef enum {
FM_I2S_PAD_CONN = 0,
FM_I2S_PAD_IO = 1,
FM_I2S_PAD_ERR
} fm_i2s_pad_sel_e;
typedef struct fm_audio_info {
fm_audio_path_e aud_path;
fm_i2s_info_t i2s_info;
fm_i2s_pad_sel_e i2s_pad;
} fm_audio_info_t;
struct fm_cqi {
int ch;
int rssi;
int reserve;
};
struct fm_cqi_req {
uint16_t ch_num;
int buf_size;
char *cqi_buf;
};
typedef struct {
int freq;
int rssi;
} fm_desense_check_t;
typedef struct {
uint16_t lower; // lower band, Eg, 7600 -> 76.0Mhz
uint16_t upper; // upper band, Eg, 10800 -> 108.0Mhz
int space; // 0x1: 50KHz, 0x2: 100Khz, 0x4: 200Khz
int cycle; // repeat times
} fm_full_cqi_log_t;
// ********** ***********FM IOCTL define start *******************************
#define FM_IOC_MAGIC 0xf5
#define FM_IOCTL_POWERUP _IOWR(FM_IOC_MAGIC, 0, struct fm_tune_parm*)
#define FM_IOCTL_POWERDOWN _IOWR(FM_IOC_MAGIC, 1, int32_t*)
#define FM_IOCTL_TUNE _IOWR(FM_IOC_MAGIC, 2, struct fm_tune_parm*)
#define FM_IOCTL_SEEK _IOWR(FM_IOC_MAGIC, 3, struct fm_seek_parm*)
#define FM_IOCTL_SETVOL _IOWR(FM_IOC_MAGIC, 4, uint32_t*)
#define FM_IOCTL_GETVOL _IOWR(FM_IOC_MAGIC, 5, uint32_t*)
#define FM_IOCTL_MUTE _IOWR(FM_IOC_MAGIC, 6, uint32_t*)
#define FM_IOCTL_GETRSSI _IOWR(FM_IOC_MAGIC, 7, int32_t*)
#define FM_IOCTL_SCAN _IOWR(FM_IOC_MAGIC, 8, struct fm_scan_parm*)
#define FM_IOCTL_STOP_SCAN _IO(FM_IOC_MAGIC, 9)
//IOCTL and struct for test
#define FM_IOCTL_GETCHIPID _IOWR(FM_IOC_MAGIC, 10, uint16_t*)
#define FM_IOCTL_EM_TEST _IOWR(FM_IOC_MAGIC, 11, struct fm_em_parm*)
#define FM_IOCTL_RW_REG _IOWR(FM_IOC_MAGIC, 12, struct fm_ctl_parm*)
#define FM_IOCTL_GETMONOSTERO _IOWR(FM_IOC_MAGIC, 13, uint16_t*)
#define FM_IOCTL_GETCURPAMD _IOWR(FM_IOC_MAGIC, 14, uint16_t*)
#define FM_IOCTL_GETGOODBCNT _IOWR(FM_IOC_MAGIC, 15, uint16_t*)
#define FM_IOCTL_GETBADBNT _IOWR(FM_IOC_MAGIC, 16, uint16_t*)
#define FM_IOCTL_GETBLERRATIO _IOWR(FM_IOC_MAGIC, 17, uint16_t*)
//IOCTL for RDS
#define FM_IOCTL_RDS_ONOFF _IOWR(FM_IOC_MAGIC, 18, uint16_t*)
#define FM_IOCTL_RDS_SUPPORT _IOWR(FM_IOC_MAGIC, 19, int32_t*)
#define FM_IOCTL_RDS_SIM_DATA _IOWR(FM_IOC_MAGIC, 23, uint32_t*)
#define FM_IOCTL_IS_FM_POWERED_UP _IOWR(FM_IOC_MAGIC, 24, uint32_t*)
//IOCTL for FM over BT
#define FM_IOCTL_OVER_BT_ENABLE _IOWR(FM_IOC_MAGIC, 29, int32_t*)
//IOCTL for FM ANTENNA SWITCH
#define FM_IOCTL_ANA_SWITCH _IOWR(FM_IOC_MAGIC, 30, int32_t*)
#define FM_IOCTL_GETCAPARRAY _IOWR(FM_IOC_MAGIC, 31, int32_t*)
//IOCTL for FM I2S Setting
#define FM_IOCTL_I2S_SETTING _IOWR(FM_IOC_MAGIC, 33, struct fm_i2s_setting*)
#define FM_IOCTL_RDS_GROUPCNT _IOWR(FM_IOC_MAGIC, 34, struct rds_group_cnt_req*)
#define FM_IOCTL_RDS_GET_LOG _IOWR(FM_IOC_MAGIC, 35, struct rds_raw_data*)
#define FM_IOCTL_SCAN_GETRSSI _IOWR(FM_IOC_MAGIC, 36, struct fm_rssi_req*)
#define FM_IOCTL_SETMONOSTERO _IOWR(FM_IOC_MAGIC, 37, int32_t)
#define FM_IOCTL_RDS_BC_RST _IOWR(FM_IOC_MAGIC, 38, int32_t*)
#define FM_IOCTL_CQI_GET _IOWR(FM_IOC_MAGIC, 39, struct fm_cqi_req*)
#define FM_IOCTL_GET_HW_INFO _IOWR(FM_IOC_MAGIC, 40, struct fm_hw_info*)
#define FM_IOCTL_GET_I2S_INFO _IOWR(FM_IOC_MAGIC, 41, fm_i2s_info_t*)
#define FM_IOCTL_IS_DESE_CHAN _IOWR(FM_IOC_MAGIC, 42, int32_t*)
#define FM_IOCTL_TOP_RDWR _IOWR(FM_IOC_MAGIC, 43, struct fm_top_rw_parm*)
#define FM_IOCTL_HOST_RDWR _IOWR(FM_IOC_MAGIC, 44, struct fm_host_rw_parm*)
#define FM_IOCTL_PRE_SEARCH _IOWR(FM_IOC_MAGIC, 45,int32_t)
#define FM_IOCTL_RESTORE_SEARCH _IOWR(FM_IOC_MAGIC, 46,int32_t)
#define FM_IOCTL_SET_SEARCH_THRESHOLD _IOWR(FM_IOC_MAGIC, 47, fm_search_threshold_t*)
#define FM_IOCTL_GET_AUDIO_INFO _IOWR(FM_IOC_MAGIC, 48, fm_audio_info_t*)
#define FM_IOCTL_SCAN_NEW _IOWR(FM_IOC_MAGIC, 60, struct fm_scan_t*)
#define FM_IOCTL_SEEK_NEW _IOWR(FM_IOC_MAGIC, 61, struct fm_seek_t*)
#define FM_IOCTL_TUNE_NEW _IOWR(FM_IOC_MAGIC, 62, struct fm_tune_t*)
#define FM_IOCTL_SOFT_MUTE_TUNE _IOWR(FM_IOC_MAGIC, 63, struct fm_softmute_tune_t*)/*for soft mute tune*/
#define FM_IOCTL_DESENSE_CHECK _IOWR(FM_IOC_MAGIC, 64, fm_desense_check_t*)
//IOCTL for EM
#define FM_IOCTL_FULL_CQI_LOG _IOWR(FM_IOC_MAGIC, 70, fm_full_cqi_log_t *)
#define FM_IOCTL_DUMP_REG _IO(FM_IOC_MAGIC, 0xFF)
// ********** ***********FM IOCTL define end *******************************
enum group_idx {
mono = 0,
stereo,
RSSI_threshold,
HCC_Enable,
PAMD_threshold,
Softmute_Enable,
De_emphasis,
HL_Side,
Demod_BW,
Dynamic_Limiter,
Softmute_Rate,
AFC_Enable,
Softmute_Level,
Analog_Volume,
GROUP_TOTAL_NUMS
};
enum item_idx {
Sblend_OFF = 0,
Sblend_ON,
ITEM_TOTAL_NUMS
};
struct fm_ctl_parm {
uint8_t err;
uint8_t addr;
uint16_t val;
uint16_t rw_flag; // 0:write, 1:read
};
struct fm_em_parm {
uint16_t group_idx;
uint16_t item_idx;
uint32_t item_value;
};
#endif // __FM_H__

66
libfmjni/fmlib_cust.h Normal file
View file

@ -0,0 +1,66 @@
/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*
* MediaTek Inc. (C) 2010. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek
* Software") have been modified by MediaTek Inc. All revisions are subject to
* any receiver's applicable license agreements with MediaTek Inc.
*/
#ifndef __FMLIB_CUST_H__
#define __FMLIB_CUST_H__
#define FM_CHIP_MT6616 0x6616
#define FM_CHIP_MT6620 0x6620
#define FM_CHIP_MT6626 0x6626
#define FM_CHIP_MT6628 0x6628
#define FM_CHIP_MT6627 0x6627
#define FM_CHIP_MT6580 0x6580
#define FM_CHIP_MT6630 0x6630
#define FM_CHIP_MT6631 0x6631
#define FM_CHIP_MT6632 0x6632
#define FM_CHIP_MT6635 0x6635
#define FM_CHIP_UNSUPPORTED -1
#define FM_JNI_SCAN_SPACE_50K 5
#define FM_JNI_SCAN_SPACE_100K 1
#define FM_JNI_SCAN_SPACE_200K 2
/*implement fm scan by soft mute tune
change to 0 will scan by orginal way*/
#define FMR_SOFT_MUTE_TUEN_SCAN 1
#define FMR_NOISE_FLOORT_DETECT 1
#define RSSI_TH -296
#define FM_SEVERE_RSSI_TH -107 // 67dBuV
#define FM_NOISE_FLOOR_OFFSET 10
#endif // __FMLIB_CUST_H__

276
libfmjni/fmr.h Executable file
View file

@ -0,0 +1,276 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FMR_H__
#define __FMR_H__
#include <jni.h>
#include <utils/Log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include <dlfcn.h>
#include "fm.h"
#include "fmlib_cust.h"
#undef LOGV
#define LOGV(...) ALOGV(__VA_ARGS__)
#undef LOGD
#define LOGD(...) ALOGD(__VA_ARGS__)
#undef LOGI
#define LOGI(...) ALOGI(__VA_ARGS__)
#undef LOGW
#define LOGW(...) ALOGW(__VA_ARGS__)
#undef LOGE
#define LOGE(...) ALOGE(__VA_ARGS__)
#define FM_DEV_NAME "/dev/fm"
#define FM_RDS_PS_LEN 8
struct fm_fake_channel
{
int freq;
int rssi_th;
int reserve;
};
struct fm_fake_channel_t
{
int size;
struct fm_fake_channel *chan;
};
struct CUST_cfg_ds
{
int16_t chip;
int32_t band;
int32_t low_band;
int32_t high_band;
int32_t seek_space;
int32_t max_scan_num;
int32_t seek_lev;
int32_t scan_sort;
int32_t short_ana_sup;
int32_t rssi_th_l2;
struct fm_fake_channel_t *fake_chan;
};
struct fm_cbk_tbl {
//Basic functions.
int (*open_dev)(const char *pname, int *fd);
int (*close_dev)(int fd);
int (*pwr_up)(int fd, int band, int freq);
int (*pwr_down)(int fd, int type);
int (*seek)(int fd, int *freq, int band, int dir, int lev);
int (*scan)(int fd, uint16_t *tbl, int *num, int band, int sort);
int (*fastget_rssi)(int fd, struct fm_rssi_req *rssi_req);
int (*get_cqi)(int fd, int num, char *buf, int buf_len);
int (*stop_scan)(int fd);
int (*tune)(int fd, int freq, int band);
int (*set_mute)(int fd, int mute);
int (*is_fm_pwrup)(int fd, int *pwrup);
int (*is_rdsrx_support)(int fd, int *supt);
int (*turn_on_off_rds)(int fd, int onoff);
int (*get_chip_id)(int fd, int *chipid);
//FOR RDS RX.
int (*read_rds_data)(int fd, RDSData_Struct *rds, uint16_t *rds_status);
int (*get_pi)(int fd, RDSData_Struct *rds, uint16_t *pi);
int (*get_ecc)(int fd, RDSData_Struct *rds, uint8_t *ecc);
int (*get_ps)(int fd, RDSData_Struct *rds, uint8_t **ps, int *ps_len);
int (*get_pty)(int fd, RDSData_Struct *rds, uint8_t *pty);
int (*get_rssi)(int fd, int *rssi);
int (*get_rt)(int fd, RDSData_Struct *rds, uint8_t **rt, int *rt_len);
int (*active_af)(int fd, RDSData_Struct *rds, CUST_cfg_ds *cfg, uint16_t orig_pi, uint16_t cur_freq, uint16_t *ret_freq);
int (*active_ta)(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *backup_freq, uint16_t *ret_freq);
int (*deactive_ta)(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *backup_freq, uint16_t *ret_freq);
//FM long/short antenna switch
int (*ana_switch)(int fd, int antenna);
//For FM RX EM mode
int (*get_badratio)(int fd, int *badratio);
int (*get_stereomono)(int fd, int *stemono);
int (*set_stereomono)(int fd, int stemono);
int (*get_caparray)(int fd, int *caparray);
int (*get_hw_info)(int fd, struct fm_hw_info *info);
int (*is_dese_chan)(int fd, int freq);
int (*soft_mute_tune)(int fd, fm_softmute_tune_t *para);
int (*desense_check)(int fd, int freq, int rssi);
int (*set_search_threshold)(int fd, int th_idx,int th_val);
int (*full_cqi_logger)(int fd,fm_full_cqi_log_t *log_parm);
/*New search*/
int (*pre_search)(int fd);
int (*restore_search)(int fd);
};
typedef int (*CUST_func_type)(struct CUST_cfg_ds *);
typedef void (*init_func_type)(struct fm_cbk_tbl *);
struct fmr_ds {
int fd;
int err;
uint16_t cur_freq;
uint16_t backup_freq;
void *priv;
void *custom_handler;
struct CUST_cfg_ds cfg_data;
struct fm_cbk_tbl tbl;
CUST_func_type get_cfg;
void *init_handler;
init_func_type init_func;
RDSData_Struct rds;
struct fm_hw_info hw_info;
fm_bool scan_stop;
};
enum fmr_err_em {
ERR_SUCCESS = 1000, // kernel error begin at here
ERR_INVALID_BUF,
ERR_INVALID_PARA,
ERR_STP,
ERR_GET_MUTEX,
ERR_FW_NORES,
ERR_RDS_CRC,
ERR_INVALID_FD, // native error begin at here
ERR_UNSUPPORT_CHIP,
ERR_LD_LIB,
ERR_FIND_CUST_FNUC,
ERR_UNINIT,
ERR_NO_MORE_IDX,
ERR_RDS_NO_DATA,
ERR_UNSUPT_SHORTANA,
ERR_MAX
};
enum fmr_rds_onoff {
FMR_RDS_ON,
FMR_RDS_OFF,
FMR_MAX
};
typedef enum {
FM_LONG_ANA = 0,
FM_SHORT_ANA
} fm_antenna_type;
#define CQI_CH_NUM_MAX 255
#define CQI_CH_NUM_MIN 0
/****************** Function declaration ******************/
//fmr_err.cpp
char *FMR_strerr();
void FMR_seterr(int err);
//fmr_core.cpp
int FMR_init(void);
int FMR_get_cfgs(int idx);
int FMR_open_dev(int idx);
int FMR_close_dev(int idx);
int FMR_pwr_up(int idx, int freq);
int FMR_pwr_down(int idx, int type);
int FMR_seek(int idx, int start_freq, int dir, int *ret_freq);
int FMR_scan(int idx, uint16_t *tbl, int *num);
int FMR_stop_scan(int idx);
int FMR_tune(int idx, int freq);
int FMR_set_mute(int idx, int mute);
int FMR_is_fm_pwrup(int idx, int *pwrup);
int FMR_is_rdsrx_support(int idx, int *supt);
int FMR_turn_on_off_rds(int idx, int onoff);
int FMR_get_chip_id(int idx, int *chipid);
int FMR_read_rds_data(int idx, uint16_t *rds_status);
int FMR_get_pi(int idx, uint16_t *pi);
int FMR_get_ecc(int idx, uint8_t *ecc);
int FMR_get_ps(int idx, uint8_t **ps, int *ps_len);
int FMR_get_pty(int idx, uint8_t *pty);
int FMR_get_rssi(int idx, int *rssi);
int FMR_get_rt(int idx, uint8_t **rt, int *rt_len);
int FMR_active_af(int idx, uint16_t orig_pi, uint16_t *ret_freq);
int FMR_active_ta(int idx, uint16_t *ret_freq);
int FMR_deactive_ta(int idx, uint16_t *ret_freq);
int FMR_ana_switch(int idx, int antenna);
int FMR_get_badratio(int idx, int *badratio);
int FMR_get_stereomono(int idx, int *stemono);
int FMR_set_stereomono(int idx, int stemono);
int FMR_get_caparray(int idx, int *caparray);
int FMR_get_hw_info(int idx, int **info, int *info_len);
int FMR_Pre_Search(int idx);
int FMR_Restore_Search(int idx);
int FMR_EMSetTH(int idx, int th_idx, int th_val);
int FMR_EM_CQI_logger(int idx,uint16_t cycle);
void FM_interface_init(struct fm_cbk_tbl *cbk_tbl);
//common part
int COM_open_dev(const char *pname, int *fd);
int COM_close_dev(int fd);
int COM_pwr_up(int fd, int band, int freq);
int COM_pwr_down(int fd, int type);
int COM_seek(int fd, int *freq, int band, int dir, int lev);
int COM_Soft_Mute_Tune(int fd, fm_softmute_tune_t *para);
int COM_fastget_rssi(int fd, struct fm_rssi_req *rssi_req);
int COM_get_cqi(int fd, int num, char *buf, int buf_len);
int COM_stop_scan(int fd);
int COM_tune(int fd, int freq, int band);
int COM_set_mute(int fd, int mute);
int COM_is_fm_pwrup(int fd, int *pwrup);
int COM_is_rdsrx_support(int fd, int *supt);
int COM_turn_on_off_rds(int fd, int onoff);
int COM_get_chip_id(int fd, int *chipid);
int COM_read_rds_data(int fd, RDSData_Struct *rds, uint16_t *rds_status);
int COM_get_pi(int fd, RDSData_Struct *rds, uint16_t *pi);
int COM_get_ps(int fd, RDSData_Struct *rds, uint8_t **ps, int *ps_len);
int COM_get_pty(int fd, RDSData_Struct *rds, uint8_t *pty);
int COM_get_rssi(int fd, int *rssi);
int COM_get_rt(int fd, RDSData_Struct *rds, uint8_t **rt, int *rt_len);
int COM_active_af(int fd, RDSData_Struct *rds, CUST_cfg_ds *cfg, uint16_t orig_pi, uint16_t cur_freq, uint16_t *ret_freq);
int COM_active_ta(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *backup_freq, uint16_t *ret_freq);
int COM_deactive_ta(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *backup_freq, uint16_t *ret_freq);
int COM_ana_switch(int fd, int antenna);
int COM_get_badratio(int fd, int *badratio);
int COM_get_stereomono(int fd, int *stemono);
int COM_set_stereomono(int fd, int stemono);
int COM_get_caparray(int fd, int *caparray);
int COM_get_hw_info(int fd, struct fm_hw_info *info);
int COM_is_dese_chan(int fd, int freq);
int COM_desense_check(int fd, int freq, int rssi);
int COM_pre_search(int fd);
int COM_restore_search(int fd);
int COM_set_search_threshold(int fd, int th_idx,int th_val);
int COM_full_cqi_logger(int fd, fm_full_cqi_log_t *log_parm);
void CUST_update_cfg(struct CUST_cfg_ds *cfg, int chipid);
int CUST_get_cfg(struct CUST_cfg_ds *cfg);
#define FMR_ASSERT(a) { \
if ((a) == NULL) { \
LOGE("%s,invalid buf\n", __func__);\
return -ERR_INVALID_BUF; \
} \
}
#endif

1264
libfmjni/fmr_core.cpp Executable file

File diff suppressed because it is too large Load diff

45
libfmjni/fmr_err.cpp Executable file
View file

@ -0,0 +1,45 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fmr.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "FMLIB_ERR"
#define FMR_ERR_BASE -0x100
static int fmr_err = 0;
static char tmp[20] = {0};
char *FMR_strerr()
{
int ret = 0;
ret = sprintf(tmp, "%d", fmr_err);
if (ret < 0) {
LOGE("%s sprintf fail\n", __func__);
}
return tmp;
}
void FMR_seterr(int err)
{
fmr_err = err;
}

806
libfmjni/libfm_jni.cpp Executable file
View file

@ -0,0 +1,806 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <jni.h>
#include "fmr.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "FMLIB_JNI"
#define FM_AF_THRESHOLD -80
#define UNUSED(x) (void)(x)
static int g_idx = -1;
extern struct fmr_ds fmr_data;
static short g_CurrentRDS_PI;
jboolean openDev(JNIEnv *env, jobject thiz)
{
int ret = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_open_dev(g_idx); // if success, then ret = 0; else ret < 0
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
jboolean closeDev(JNIEnv *env, jobject thiz)
{
int ret = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_close_dev(g_idx);
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
jboolean powerUp(JNIEnv *env, jobject thiz, jfloat freq)
{
int ret = 0;
int tmp_freq;
UNUSED(env);
UNUSED(thiz);
LOGI("%s, [freq=%d]\n", __func__, (int)freq);
/* fix jfloat precision issue */
tmp_freq = (int)((float)freq * 100 + 0.5); //Eg, 87.5 * 100 --> 8750
ret = FMR_pwr_up(g_idx, tmp_freq);
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
jboolean powerDown(JNIEnv *env, jobject thiz, jint type)
{
int ret = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_pwr_down(g_idx, type);
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
jint readRssi(JNIEnv *env, jobject thiz) //jint = int
{
int ret = 0;
int rssi = -1;
UNUSED(env);
UNUSED(thiz);
ret = FMR_get_rssi(g_idx, &rssi);
LOGD("%s, [ret=%d]\n", __func__, ret);
return rssi;
}
jboolean tune(JNIEnv *env, jobject thiz, jfloat freq)
{
int ret = 0;
int tmp_freq;
UNUSED(env);
UNUSED(thiz);
/* fix jfloat precision issue */
tmp_freq = (int)((float)freq * 100 + 0.5); //Eg, 87.5 * 100 --> 8750
ret = FMR_tune(g_idx, tmp_freq);
if (!ret) /* clean global pi*/
g_CurrentRDS_PI = 0;
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
jfloat seek(JNIEnv *env, jobject thiz, jfloat freq, jboolean isUp) //jboolean isUp;
{
int ret = 0;
int tmp_freq;
int ret_freq;
float val;
UNUSED(env);
UNUSED(thiz);
/* fix jfloat precision issue */
tmp_freq = (int)((float)freq * 100 + 0.5); //Eg, 87.5 * 100 --> 8750
ret = FMR_set_mute(g_idx, 1);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [mute] [ret=%d]\n", __func__, ret);
ret = FMR_seek(g_idx, tmp_freq, (int)isUp, &ret_freq);
if (ret) {
ret_freq = tmp_freq; //seek error, so use original freq
}
LOGD("%s, [freq=%d] [ret=%d]\n", __func__, ret_freq, ret);
val = (float)ret_freq/100; //Eg, 8755 / 100 --> 87.55
return val;
}
jshortArray autoScan(JNIEnv *env, jobject thiz)
{
#define FM_SCAN_CH_SIZE_MAX 200
int ret = 0;
jshortArray scanChlarray;
int chl_cnt = FM_SCAN_CH_SIZE_MAX;
uint16_t ScanTBL[FM_SCAN_CH_SIZE_MAX];
UNUSED(thiz);
LOGI("%s, [tbl=%p]\n", __func__, ScanTBL);
FMR_Pre_Search(g_idx);
ret = FMR_scan(g_idx, ScanTBL, &chl_cnt);
if (ret < 0) {
LOGE("scan failed!\n");
scanChlarray = NULL;
goto out;
}
if (chl_cnt > 0) {
scanChlarray = env->NewShortArray(chl_cnt);
env->SetShortArrayRegion(scanChlarray, 0, chl_cnt, (const jshort*)&ScanTBL[0]);
} else {
LOGE("cnt error, [cnt=%d]\n", chl_cnt);
scanChlarray = NULL;
}
FMR_Restore_Search(g_idx);
if (fmr_data.scan_stop == fm_true) {
ret = FMR_tune(g_idx, fmr_data.cur_freq);
LOGI("scan stop!!! tune ret=%d",ret);
scanChlarray = NULL;
ret = -1;
}
out:
LOGD("%s, [cnt=%d] [ret=%d]\n", __func__, chl_cnt, ret);
return scanChlarray;
}
jboolean emsetth(JNIEnv *env, jobject thiz, jint index, jint value)
{
int ret = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_EMSetTH(g_idx, index, value);
LOGD("emsetth ret %d\n", ret);
return (ret < 0) ? JNI_FALSE : JNI_TRUE;
}
jshortArray emcmd(JNIEnv *env, jobject thiz, jshortArray val)
{
jshortArray eventarray = NULL;
uint16_t eventtbl[20]={0};
uint16_t* cmdtbl=NULL;
UNUSED(thiz);
cmdtbl = (uint16_t*) env->GetShortArrayElements(val, NULL);
if(cmdtbl == NULL)
{
LOGE("%s:get cmdtbl error\n", __func__);
goto out;
}
LOGI("EM cmd:=%x %x %x %x %x",cmdtbl[0],cmdtbl[1],cmdtbl[2],cmdtbl[3],cmdtbl[4]);
if(!cmdtbl[0]) //LANT
{
}
else //SANT
{
}
switch(cmdtbl[1])
{
case 0x02: //CQI log tool
{
FMR_EM_CQI_logger(g_idx, cmdtbl[2]);
}
break;
default:
break;
}
eventarray = env->NewShortArray(20);
env->SetShortArrayRegion(eventarray, 0, 20, (const jshort*)&eventtbl[0]);
//LOGD("emsetth ret %d\n", ret);
out:
return eventarray;
}
jshort readRds(JNIEnv *env, jobject thiz)
{
int ret = 0;
int rssi = -1;
uint16_t rds_status = 0;
uint16_t pi = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_read_rds_data(g_idx, &rds_status);
if (ret) {
rds_status = 0; // There's no event or some error happened
} else {
if (rds_status & RDS_EVENT_PI_CODE) {
ret = FMR_get_pi(0, &pi);
if (!ret) {
ret = FMR_get_rssi(g_idx, &rssi);
if (rssi > FM_AF_THRESHOLD)
g_CurrentRDS_PI = pi;
}
LOGE("get pi(0x%04x) \n", pi);
}
}
return rds_status;
}
jshort getPI(JNIEnv *env, jobject thiz)
{
int ret = 0;
uint16_t pi = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_get_pi(g_idx, &pi);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
pi = -1; //there's some error happened
}
return pi;
}
jbyte getECC(JNIEnv *env, jobject thiz)
{
int ret = 0;
uint8_t ecc = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_get_ecc(g_idx, &ecc);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
ecc = -1; //there's some error happened
}
return ecc;
}
jbyte getPTY(JNIEnv *env, jobject thiz)
{
int ret = 0;
uint8_t pty = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_get_pty(g_idx, &pty);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
pty = -1; //there's some error happened
}
return pty;
}
jbyteArray getPs(JNIEnv *env, jobject thiz)
{
int ret = 0;
jbyteArray PSname;
uint8_t *ps = NULL;
int ps_len = 0;
UNUSED(thiz);
ret = FMR_get_ps(g_idx, &ps, &ps_len);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
return NULL;
}
PSname = env->NewByteArray(ps_len);
env->SetByteArrayRegion(PSname, 0, ps_len, (const jbyte*)ps);
LOGD("%s, [ret=%d]\n", __func__, ret);
return PSname;
}
jbyteArray getLrText(JNIEnv *env, jobject thiz)
{
int ret = 0;
jbyteArray LastRadioText;
uint8_t *rt = NULL;
int rt_len = 0;
UNUSED(thiz);
ret = FMR_get_rt(g_idx, &rt, &rt_len);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
return NULL;
}
LastRadioText = env->NewByteArray(rt_len);
env->SetByteArrayRegion(LastRadioText, 0, rt_len, (const jbyte*)rt);
LOGD("%s, [ret=%d]\n", __func__, ret);
return LastRadioText;
}
jshort activeAf(JNIEnv *env, jobject thiz)
{
int ret = 0;
jshort ret_freq = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_active_af(g_idx, g_CurrentRDS_PI, (uint16_t*)&ret_freq);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
return 0;
}
LOGD("%s, [ret=%d], ret_freq=%d\n", __func__, ret, ret_freq);
return ret_freq;
}
jshortArray getAFList(JNIEnv *env, jobject thiz)
{
int ret = 0;
jshortArray AFList;
char *af = NULL;
int af_len = 0;
UNUSED(thiz);
//ret = FMR_get_af(g_idx, &af, &af_len); // If need, we should implemate this API
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
return NULL;
}
AFList = env->NewShortArray(af_len);
env->SetShortArrayRegion(AFList, 0, af_len, (const jshort*)af);
LOGD("%s, [ret=%d]\n", __func__, ret);
return AFList;
}
jshort activeTA(JNIEnv *env, jobject thiz)
{
int ret = 0;
jshort ret_freq = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_active_ta(g_idx, (uint16_t*)&ret_freq);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
return 0;
}
LOGD("%s, [ret=%d], ret_freq=%d\n", __func__, ret, ret_freq);
return ret_freq;
}
jshort deactiveTA(JNIEnv *env, jobject thiz)
{
int ret = 0;
jshort ret_freq = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_deactive_ta(g_idx, (uint16_t*)&ret_freq);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
return 0;
}
LOGD("%s, [ret=%d], ret_freq=%d\n", __func__, ret, ret_freq);
return ret_freq;
}
jint setRds(JNIEnv *env, jobject thiz, jboolean rdson)
{
int ret = 0;
int onoff = -1;
UNUSED(env);
UNUSED(thiz);
if (rdson == JNI_TRUE) {
onoff = FMR_RDS_ON;
} else {
onoff = FMR_RDS_OFF;
}
ret = FMR_turn_on_off_rds(g_idx, onoff);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [onoff=%d] [ret=%d]\n", __func__, onoff, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
jboolean stopScan(JNIEnv *env, jobject thiz)
{
int ret = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_stop_scan(g_idx);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
jint setMute(JNIEnv *env, jobject thiz, jboolean mute)
{
int ret = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_set_mute(g_idx, (int)mute);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [mute=%d] [ret=%d]\n", __func__, (int)mute, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
/******************************************
* Used to get chip ID.
*Parameter:
* None
*Return value
* 1000: chip AR1000
* 6616: chip mt6616
* -1: error
******************************************/
jint getchipid(JNIEnv *env, jobject thiz)
{
int ret = 0;
int chipid = -1;
UNUSED(env);
UNUSED(thiz);
ret = FMR_get_chip_id(g_idx, &chipid);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [chipid=%x] [ret=%d]\n", __func__, chipid, ret);
return chipid;
}
/******************************************
* Inquiry if RDS is support in driver.
* Parameter:
* None
*Return Value:
* 1: support
* 0: NOT support
* -1: error
******************************************/
jint isRdsSupport(JNIEnv *env, jobject thiz)
{
int ret = 0;
int supt = -1;
UNUSED(env);
UNUSED(thiz);
ret = FMR_is_rdsrx_support(g_idx, &supt);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [supt=%d] [ret=%d]\n", __func__, supt, ret);
return supt;
}
/******************************************
* Inquiry if FM is powered up.
* Parameter:
* None
*Return Value:
* 1: Powered up
* 0: Did NOT powered up
******************************************/
jint isFMPoweredUp(JNIEnv *env, jobject thiz)
{
int ret = 0;
int pwrup = -1;
UNUSED(env);
UNUSED(thiz);
ret = FMR_is_fm_pwrup(g_idx, &pwrup);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [pwrup=%d] [ret=%d]\n", __func__, pwrup, ret);
return pwrup;
}
/******************************************
* SwitchAntenna
* Parameter:
* antenna:
0 : switch to long antenna
1: switch to short antenna
*Return Value:
* 0: Success
* 1: Failed
* 2: Not support
******************************************/
jint switchAntenna(JNIEnv *env, jobject thiz, jint antenna)
{
int ret = 0;
jint jret = 0;
int ana = -1;
UNUSED(env);
UNUSED(thiz);
if (0 == antenna) {
ana = FM_LONG_ANA;
} else if (1 == antenna) {
ana = FM_SHORT_ANA;
} else {
LOGE("%s:fail, para error\n", __func__);
jret = JNI_FALSE;
goto out;
}
ret = FMR_ana_switch(g_idx, ana);
if (ret == -ERR_UNSUPT_SHORTANA) {
LOGW("Not support switchAntenna\n");
jret = 2;
} else if (ret) {
LOGE("switchAntenna(), error\n");
jret = 1;
} else {
jret = 0;
}
out:
LOGD("%s: [antenna=%d] [ret=%d]\n", __func__, ana, ret);
return jret;
}
/******************************************
* Inquiry if FM is stereoMono.
* Parameter:
* None
*Return Value:
* JNI_TRUE: stereo
* JNI_FALSE: mono
******************************************/
jboolean stereoMono(JNIEnv *env, jobject thiz)
{
int ret = 0;
int stemono = -1;
UNUSED(env);
UNUSED(thiz);
ret = FMR_get_stereomono(g_idx, &stemono);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [stemono=%d] [ret=%d]\n", __func__, stemono, ret);
return stemono?JNI_TRUE:JNI_FALSE;
}
/******************************************
* Force set to stero/mono mode.
* Parameter:
* type: JNI_TRUE, mono; JNI_FALSE, stero
*Return Value:
* JNI_TRUE: success
* JNI_FALSE: failed
******************************************/
jboolean setStereoMono(JNIEnv *env, jobject thiz, jboolean type)
{
int ret = 0;
UNUSED(env);
UNUSED(thiz);
ret = FMR_set_stereomono(g_idx, ((type == JNI_TRUE) ? 1 : 0));
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s,[ret=%d]\n", __func__, ret);
return (ret==0) ? JNI_TRUE : JNI_FALSE;
}
/******************************************
* Read cap array of short antenna.
* Parameter:
* None
*Return Value:
* CapArray
******************************************/
jshort readCapArray(JNIEnv *env, jobject thiz)
{
int ret = 0;
int caparray = -1;
UNUSED(env);
UNUSED(thiz);
ret = FMR_get_caparray(g_idx, &caparray);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
LOGD("%s, [caparray=%d] [ret=%d]\n", __func__, caparray, ret);
return (jshort)caparray;
}
/******************************************
* Read cap array of short antenna.
* Parameter:
* None
*Return Value:
* CapArray : 0~100
******************************************/
jshort readRdsBler(JNIEnv *env, jobject thiz)
{
int ret = 0;
int badratio = -1;
UNUSED(env);
UNUSED(thiz);
ret = FMR_get_badratio(g_idx, &badratio);
if(ret){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
}
if(badratio > 100){
badratio = 100;
LOGW("badratio value error, give a max value!");
}else if(badratio < 0){
badratio = 0;
LOGW("badratio value error, give a min value!");
}
LOGD("%s, [badratio=%d] [ret=%d]\n", __func__, badratio, ret);
return (jshort)badratio;
}
jintArray getHardwareVersion(JNIEnv *env, jobject thiz)
{
int ret = 0;
jintArray hw_info;
int *info = NULL;
int info_len = 0;
UNUSED(thiz);
ret = FMR_get_hw_info(g_idx, &info, &info_len);
if(ret < 0){
LOGE("%s, error, [ret=%d]\n", __func__, ret);
return NULL;
}
hw_info = env->NewIntArray(info_len);
env->SetIntArrayRegion(hw_info, 0, info_len, (const jint*)info);
LOGD("%s, [ret=%d]\n", __func__, ret);
return hw_info;
}
static const char *classPathNameRx = "com/android/fmradio/FmNative";
static JNINativeMethod methodsRx[] = {
{"openDev", "()Z", (void*)openDev},
{"closeDev", "()Z", (void*)closeDev},
{"powerUp", "(F)Z", (void*)powerUp},
{"powerDown", "(I)Z", (void*)powerDown},
{"tune", "(F)Z", (void*)tune},
{"seek", "(FZ)F", (void*)seek},
{"autoScan", "()[S", (void*)autoScan},
{"stopScan", "()Z", (void*)stopScan},
{"setRds", "(Z)I", (void*)setRds},
{"readRds", "()S", (void*)readRds},
{"getPs", "()[B", (void*)getPs},
{"getLrText", "()[B", (void*)getLrText},
{"activeAf", "()S", (void*)activeAf},
{"setMute", "(Z)I", (void*)setMute},
{"isRdsSupport", "()I", (void*)isRdsSupport},
{"switchAntenna", "(I)I", (void*)switchAntenna},
{"readRssi", "()I", (void*)readRssi},
{"stereoMono", "()Z", (void*)stereoMono},
{"setStereoMono", "(Z)Z", (void*)setStereoMono},
{"readCapArray", "()S", (void*)readCapArray},
{"readRdsBler", "()S", (void*)readRdsBler},
{"emcmd","([S)[S",(void*)emcmd},
{"emsetth","(II)Z",(void*)emsetth},
{"getHardwareVersion", "()[I", (void*)getHardwareVersion},
};
/*
* Register several native methods for one class.
*/
static jint registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = env->FindClass(className);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
if (clazz == NULL) {
LOGE("Native registration unable to find class '%s'", className);
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
LOGE("RegisterNatives failed for '%s'", className);
return JNI_FALSE;
}
LOGD("%s, success\n", __func__);
return JNI_TRUE;
}
/*
* Register native methods for all classes we know about.
*
* returns JNI_TRUE on success.
*/
static jint registerNatives(JNIEnv* env)
{
jint ret = JNI_FALSE;
if (registerNativeMethods(env, classPathNameRx,methodsRx,
sizeof(methodsRx) / sizeof(methodsRx[0]))) {
ret = JNI_TRUE;
}
LOGD("%s, done\n", __func__);
return ret;
}
// ----------------------------------------------------------------------------
/*
* This is called by the VM when the shared library is first loaded.
*/
typedef union {
JNIEnv* env;
void* venv;
} UnionJNIEnvToVoid;
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
jint result = -1;
JNIEnv* env = NULL;
UNUSED(reserved);
LOGI("JNI_OnLoad");
if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed");
goto fail;
}
env = uenv.env;
if (registerNatives(env) != JNI_TRUE) {
LOGE("ERROR: registerNatives failed");
goto fail;
}
if ((g_idx = FMR_init()) < 0) {
goto fail;
}
result = JNI_VERSION_1_4;
fail:
return result;
}