Commit f6b37817 authored by Bart Sears's avatar Bart Sears Committed by Android (Google) Code Review
Browse files

Merge "Revert "[FM] Move FM Radio JNI"" into lmp-mr1-dev

parents 8f5facc1 619e3f6a
# 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.
LOCAL_PATH:= $(call my-dir)
include $(call all-makefiles-under,$(LOCAL_PATH))
# 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
fmr_core.cpp \
fmr_err.cpp \
libfm_jni.cpp \
common.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
frameworks/base/include/media
LOCAL_SHARED_LIBRARIES := \
libcutils \
libdl \
libmedia \
LOCAL_MODULE := libfmjni
include $(BUILD_SHARED_LIBRARY)
/*
* 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_COM"
static int g_stopscan = 0;
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;
}
/*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};
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 };
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;
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_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_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_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;
}
int COM_active_af(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *ret_freq)
{
int ret = 0;
int i = 0;
struct fm_tune_parm parm;
uint16_t rds_on = 0;
uint16_t set_freq, sw_freq, org_freq, PAMD_Value, AF_PAMD_LBound, AF_PAMD_HBound;
uint16_t PAMD_Level[25];
uint16_t PAMD_DB_TBL[5] = {// 5dB, 10dB, 15dB, 20dB, 25dB,
// 13, 17, 21, 25, 29};
8, 12, 15, 18, 20};
FMR_ASSERT(rds);
FMR_ASSERT(ret_freq);
sw_freq = cur_freq; //current freq
org_freq = cur_freq;
parm.band = 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;
}
AF_PAMD_LBound = PAMD_DB_TBL[0]; //5dB
AF_PAMD_HBound = PAMD_DB_TBL[1]; //15dB
ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Value);
LOGI("current_freq=%d,PAMD_Value=%d\n", cur_freq, PAMD_Value);
if (PAMD_Value < AF_PAMD_LBound) {
rds_on = 0;
ioctl(fd, FM_IOCTL_RDS_ONOFF, &rds_on);
//make sure rds->AF_Data.AF_Num is valid
rds->AF_Data.AF_Num = (rds->AF_Data.AF_Num > 25)? 25 : rds->AF_Data.AF_Num;
for (i=0; i<rds->AF_Data.AF_Num; i++) {
set_freq = rds->AF_Data.AF[1][i]; //method A or B
if (set_freq != org_freq) {
parm.freq = set_freq;
ioctl(fd, FM_IOCTL_TUNE, &parm);
usleep(250*1000);
ioctl(fd, FM_IOCTL_GETCURPAMD, &PAMD_Level[i]);
LOGI("next_freq=%d,PAMD_Level=%d\n", parm.freq, PAMD_Level[i]);
if (PAMD_Level[i] > PAMD_Value) {
PAMD_Value = PAMD_Level[i];
sw_freq = set_freq;
}
}
}
LOGI("PAMD_Value=%d, sw_freq=%d\n", PAMD_Value, sw_freq);
if ((PAMD_Value > AF_PAMD_HBound)&&(sw_freq != 0)) {
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);
} else {
LOGD("RDS_EVENT_AF old freq:%d\n", org_freq);
}
*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;
}
/* 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;
}
}
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_ps = COM_get_ps;
cbk_tbl->get_rt = COM_get_rt;
cbk_tbl->active_af = COM_active_af;
//FM short antenna
cbk_tbl->ana_switch = COM_ana_switch;
cbk_tbl->desense_check = COM_desense_check;
//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;
return;
}
/*
* 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 <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <pthread.h>
#include <linux/fm.h>
#include <signal.h>
#include <errno.h>
#include <dlfcn.h>
#define FM_LIB_USE_XLOG
#ifdef FM_LIB_USE_XLOG
#include <cutils/xlog.h>
#undef LOGV
#define LOGV(...) XLOGV(__VA_ARGS__)
#undef LOGD
#define LOGD(...) XLOGD(__VA_ARGS__)
#undef LOGI
#define LOGI(...) XLOGI(__VA_ARGS__)
#undef LOGW
#define LOGW(...) XLOGW(__VA_ARGS__)
#undef LOGE
#define LOGE(...) XLOGE(__VA_ARGS__)
#endif
#define CUST_LIB_NAME "libfmcust.so"
#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 (*stop_scan)(int fd);
int (*tune)(int fd, int freq, int band);
int (*set_mute)(int fd, int mute);
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_ps)(int fd, RDSData_Struct *rds, uint8_t **ps, int *ps_len);
int (*get_rt)(int fd, RDSData_Struct *rds, uint8_t **rt, int *rt_len);
int (*active_af)(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *ret_freq);
//FM long/short antenna switch
int (*ana_switch)(int fd, int antenna);
int (*soft_mute_tune)(int fd, fm_softmute_tune_t *para);
int (*desense_check)(int fd, int freq, int rssi);
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_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_ps(int idx, uint8_t **ps, int *ps_len);
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 *ret_freq);
int FMR_ana_switch(int idx, int antenna);
int FMR_Pre_Search(int idx);
int FMR_Restore_Search(int idx);
//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_stop_scan(int fd);
int COM_tune(int fd, int freq, int band);
int COM_set_mute(int fd, int mute);
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_ps(int fd, RDSData_Struct *rds, uint8_t **ps, int *ps_len);
int COM_get_rt(int fd, RDSData_Struct *rds, uint8_t **rt, int *rt_len);
int COM_active_af(int fd, RDSData_Struct *rds, int band, uint16_t cur_freq, uint16_t *ret_freq);
int COM_ana_switch(int fd, int antenna);
int COM_desense_check(int fd, int freq, int rssi);
int COM_pre_search(int fd);
int COM_restore_search(int fd);
void FM_interface_init(struct fm_cbk_tbl *cbk_tbl);
#define FMR_ASSERT(a) { \
if ((a) == NULL) { \
LOGE("%s,invalid buf\n", __func__);\
return -ERR_INVALID_BUF; \
} \
}
#endif
This diff is collapsed.
/*
* 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()
{
sprintf(tmp, "%d", fmr_err);
return tmp;
}
void FMR_seterr(int err)
{
fmr_err = err;
}
/*
* 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"
static int g_idx = -1;
extern struct fmr_ds fmr_data;
jboolean openDev(JNIEnv *env, jobject thiz)
{
int ret = 0;
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;
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;
LOGI("%s, [freq=%d]\n", __func__, (int)freq);
tmp_freq = (int)(freq * 10); //Eg, 87.5 * 10 --> 875
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;
ret = FMR_pwr_down(g_idx, type);
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret?JNI_FALSE:JNI_TRUE;
}
jboolean tune(JNIEnv *env, jobject thiz, jfloat freq)
{
int ret = 0;
int tmp_freq;
tmp_freq = (int)(freq * 10); //Eg, 87.5 * 10 --> 875
ret = FMR_tune(g_idx, tmp_freq);
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;
tmp_freq = (int)(freq * 100); //Eg, 87.55 * 100 --> 8755
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];
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;
}
jshort readRds(JNIEnv *env, jobject thiz)
{
int ret = 0;
uint16_t status = 0;
ret = FMR_read_rds_data(g_idx, &status);
if (ret) {
//LOGE("%s,status = 0,[ret=%d]\n", __func__, ret);
status = 0; //there's no event or some error happened
}
return status;
}
jbyteArray getPs(JNIEnv *env, jobject thiz)
{
int ret = 0;
jbyteArray PSname;
uint8_t *ps = NULL;
int ps_len = 0;
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;
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;
ret = FMR_active_af(g_idx, (uint16_t*)&ret_freq);
if (ret) {
LOGE("%s, error, [ret=%d]\n", __func__, ret);
return 0;
}
LOGD("%s, [ret=%d]\n", __func__, ret);
return ret_freq;
}
jshortArray getAFList(JNIEnv *env, jobject thiz)
{
int ret = 0;
jshortArray AFList;
char *af = NULL;
int af_len = 0;
//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;
}
jint setRds(JNIEnv *env, jobject thiz, jboolean rdson)
{
int ret = 0;
int onoff = -1;
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;
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;
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;
}
/******************************************
* 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;
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;
}
/******************************************
* 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;
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;
}
static const char *classPathNameRx = "com/android/fmradio/FmNative";
static JNINativeMethod methodsRx[] = {
{"openDev", "()Z", (void*)openDev }, //1
{"closeDev", "()Z", (void*)closeDev }, //2
{"powerUp", "(F)Z", (void*)powerUp }, //3
{"powerDown", "(I)Z", (void*)powerDown }, //4
{"tune", "(F)Z", (void*)tune }, //5
{"seek", "(FZ)F", (void*)seek }, //6
{"autoScan", "()[S", (void*)autoScan }, //7
{"stopScan", "()Z", (void*)stopScan }, //8
{"setRds", "(Z)I", (void*)setRds }, //10
{"readRds", "()S", (void*)readRds }, //11 will pending here for get event status
{"getPs", "()[B", (void*)getPs }, //12
{"getLrText", "()[B", (void*)getLrText}, //13
{"activeAf", "()S", (void*)activeAf}, //14
{"setMute", "(Z)I", (void*)setMute}, //15
{"isRdsSupport", "()I", (void*)isRdsSupport}, //16
{"switchAntenna", "(I)I", (void*)switchAntenna}, //17
};
/*
* 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;
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;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment