blob: 613a06296b514f45a83cfcd48c74a1f2855b2ae7 [file] [log] [blame]
/*
Copyright (c) 2015, The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of The Linux Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <utils/Log.h>
#include <cutils/properties.h>
#include <sys/ioctl.h>
#include <math.h>
#include "FmRadioController.h"
#include "FmIoctlsInterface.h"
#include "ConfigFmThs.h"
#include <linux/videodev2.h>
//Reset all variables to default value
static FmIoctlsInterface * FmIoct;
FmRadioController :: FmRadioController
(
)
{
cur_fm_state = FM_OFF;
prev_freq = -1;
seek_scan_canceled = false;
af_enabled = 0;
rds_enabled = 0;
event_listener_canceled = false;
is_rds_support = false;
is_ps_event_received = false;
is_rt_event_received = false;
is_af_jump_received = false;
mutex_fm_state = PTHREAD_MUTEX_INITIALIZER;
mutex_seek_compl_cond = PTHREAD_MUTEX_INITIALIZER;
mutex_scan_compl_cond = PTHREAD_MUTEX_INITIALIZER;
mutex_tune_compl_cond = PTHREAD_MUTEX_INITIALIZER;
mutex_turn_on_cond = PTHREAD_MUTEX_INITIALIZER;
turn_on_cond = PTHREAD_COND_INITIALIZER;
seek_compl_cond = PTHREAD_COND_INITIALIZER;
scan_compl_cond = PTHREAD_COND_INITIALIZER;
tune_compl_cond = PTHREAD_COND_INITIALIZER;
event_listener_thread = 0;
fd_driver = -1;
FmIoct = new FmIoctlsInterface();
}
/* Turn off FM */
FmRadioController :: ~FmRadioController
(
)
{
if((cur_fm_state != FM_OFF)) {
Stop_Scan_Seek();
set_fm_state(FM_OFF_IN_PROGRESS);
FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_STATE, FM_DEV_NONE);
}
if(event_listener_thread != 0) {
event_listener_canceled = true;
pthread_join(event_listener_thread, NULL);
}
}
int FmRadioController ::open_dev()
{
int ret = FM_SUCCESS;
fd_driver = open(FM_DEVICE_PATH, O_RDONLY, O_NONBLOCK);
if (fd_driver < 0) {
ALOGE("%s failed, [fd=%d] %s\n", __func__, fd_driver, FM_DEVICE_PATH);
return FM_FAILURE;
}
ALOGD("%s, [fd=%d] \n", __func__, fd_driver);
return ret;
}
int FmRadioController ::close_dev()
{
int ret = 0;
if (fd_driver > 0) {
close(fd_driver);
fd_driver = -1;
}
ALOGD("%s, [fd=%d] [ret=%d]\n", __func__, fd_driver, ret);
return ret;
}
struct timespec FmRadioController :: set_time_out
(
int secs
)
{
struct timespec ts;
struct timeval tp;
gettimeofday(&tp, NULL);
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += secs;
return ts;
}
//Get current tuned frequency
//Return -1 if failed to get freq
long FmRadioController :: GetChannel
(
void
)
{
long freq = -1;
int ret;
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::get_cur_freq(fd_driver, freq);
if(ret == FM_SUCCESS) {
ALOGI("FM get freq is successfull, freq is: %ld\n", freq);
}else {
ALOGE("FM get frequency failed, freq is: %ld\n", freq);
}
}else {
ALOGE("FM get freq is not valid in current state\n");
}
return freq;
}
int FmRadioController ::Pwr_Up(int freq)
{
int ret = FM_SUCCESS;
struct timespec ts;
ConfigFmThs thsObj;
char value[PROPERTY_VALUE_MAX] = {'\0'};
ALOGI("%s,[freq=%d]\n", __func__, freq);
property_get("qcom.bluetooth.soc", value, NULL);
ALOGD("BT soc is %s\n", value);
if (fd_driver < 0) {
ret = open_dev();
if (ret != FM_SUCCESS) {
ALOGE("Dev open failed\n");
return FM_FAILURE;
}
}
if (cur_fm_state == FM_OFF) {
ALOGE("cur_fm_state = %d\n",cur_fm_state);
if (strcmp(value, "rome") != 0) {
ret = FmIoctlsInterface::start_fm_patch_dl(fd_driver);
if (ret != FM_SUCCESS) {
ALOGE("FM patch downloader failed: %d\n", ret);
close_dev();
set_fm_state(FM_OFF);
return FM_FAILURE;
}
}
if (event_listener_thread == 0) {
ret = pthread_create(&event_listener_thread, NULL,
handle_events, this);
if (ret == 0) {
ALOGI("Lock the mutex for FM turn on cond\n");
pthread_mutex_lock(&mutex_turn_on_cond);
ts = set_time_out(READY_EVENT_TIMEOUT);
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_STATE, FM_RX);
if (ret == FM_SUCCESS) {
ALOGI("Waiting for timedout or FM on\n");
pthread_cond_timedwait(&turn_on_cond,
&mutex_turn_on_cond, &ts);
ALOGI("Unlocked mutex & timedout or condition satisfied\n");
pthread_mutex_unlock(&mutex_turn_on_cond);
if (cur_fm_state == FM_ON) {//after READY event
ret = SetBand(BAND_87500_108000);
if (ret != FM_SUCCESS) {
ALOGE("set band failed\n");
ret = FM_FAILURE;
goto exit;
}
ret = SetChannelSpacing(CHAN_SPACE_100);
if (ret != FM_SUCCESS) {
ALOGE("set channel spacing failed\n");
ret = FM_FAILURE;
goto exit;
}
ret = SetDeConstant(DE_EMP50);
if (ret != FM_SUCCESS) {
ALOGE("set Emphasis failed\n");
ret = FM_FAILURE;
goto exit;
}
thsObj.SetRxSearchAfThs(FM_PERFORMANCE_PARAMS, fd_driver);
SetStereo();
ret = TuneChannel(freq);
if (ret != FM_SUCCESS) {
ALOGI("FM set freq command failed\n");
ret = FM_FAILURE;
goto exit;
}
return FM_SUCCESS;
} else { //if time out
ret = FM_FAILURE;
goto exit;
}
} else {
ALOGE("Set FM on control failed\n");
pthread_mutex_unlock(&mutex_turn_on_cond);
ALOGI("Unlocked the FM on cond mutex\n");
ret = FM_FAILURE;
goto close_fd;
}
} else {
ALOGE("FM event listener thread failed: %d\n", ret);
set_fm_state(FM_OFF);
return FM_FAILURE;
}
} else {
ALOGE("FM event listener threadi existed\n");
return FM_SUCCESS;
}
} else if(cur_fm_state != FM_ON_IN_PROGRESS) {
return FM_SUCCESS;
} else {
return FM_FAILURE;
}
exit:
FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_STATE, FM_DEV_NONE);
close_fd:
event_listener_canceled = true;
pthread_join(event_listener_thread, NULL);
close(fd_driver);
fd_driver = -1;
set_fm_state(FM_OFF);
ALOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
int FmRadioController ::Pwr_Down()
{
int ret = 0;
if((cur_fm_state != FM_OFF)) {
Stop_Scan_Seek();
set_fm_state(FM_OFF_IN_PROGRESS);
FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_STATE, FM_DEV_NONE);
}
if(event_listener_thread != 0) {
ALOGD("%s, event_listener_thread canceeled\n", __func__);
event_listener_canceled = true;
pthread_join(event_listener_thread, NULL);
}
ALOGD("%s, [ret=%d]\n", __func__, ret);
return ret;
}
//Tune to a Freq
//Return FM_SUCCESS on success FM_FAILURE
//on failure
int FmRadioController :: TuneChannel
(
long freq
)
{
int ret = FM_SUCCESS;
struct timespec ts;
if((cur_fm_state == FM_ON) &&
(freq > 0)) {
set_fm_state(FM_TUNE_IN_PROGRESS);
ret = FmIoctlsInterface::set_freq(fd_driver,
freq);
if(ret == FM_SUCCESS) {
ALOGI("FM set frequency command set successfully\n");
pthread_mutex_lock(&mutex_tune_compl_cond);
ts = set_time_out(TUNE_EVENT_TIMEOUT);
ret = pthread_cond_timedwait(&tune_compl_cond, &mutex_tune_compl_cond, &ts);
pthread_mutex_unlock(&mutex_tune_compl_cond);
}else {
if((cur_fm_state != FM_OFF)) {
set_fm_state(FM_ON);
}
ALOGE("FM set freq command failed\n");
}
}else {
ALOGE("Fm is not in proper state for tuning to a freq\n");
ret = FM_FAILURE;
}
return ret;
}
int FmRadioController :: Seek(int dir)
{
int ret = 0;
int freq = -1;
struct timespec ts;
if (cur_fm_state != FM_ON) {
ALOGE("%s error Fm state: %d\n", __func__,cur_fm_state);
return FM_FAILURE;
}
ALOGI("FM seek started\n");
set_fm_state(SEEK_IN_PROGRESS);
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_SRCHMODE, SEEK_MODE);
if (ret != FM_SUCCESS) {
set_fm_state(FM_ON);
return FM_FAILURE;
}
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_SCANDWELL, SEEK_DWELL_TIME);
if (ret != FM_SUCCESS) {
set_fm_state(FM_ON);
return FM_FAILURE;
}
if (dir == 1) {
ret = FmIoctlsInterface::start_search(fd_driver,
SEARCH_UP);
} else {
ret = FmIoctlsInterface::start_search(fd_driver,
SEARCH_DOWN);
}
if (ret != FM_SUCCESS) {
set_fm_state(FM_ON);
return FM_FAILURE;
}
pthread_mutex_lock(&mutex_seek_compl_cond);
ts = set_time_out(SEEK_COMPL_TIMEOUT);
ret = pthread_cond_timedwait(&seek_compl_cond, &mutex_seek_compl_cond, &ts);
pthread_mutex_unlock(&mutex_seek_compl_cond);
if ((cur_fm_state != SEEK_IN_PROGRESS) && !seek_scan_canceled) {
ALOGI("Seek completed without timeout\n");
freq = GetChannel();
}
seek_scan_canceled = false;
return freq;
}
bool FmRadioController ::IsRds_support
(
void
)
{
is_rds_support = true;
ALOGI("is_rds_support: \n", is_rds_support);
return is_rds_support;
}
//HardMute both audio channels
int FmRadioController ::MuteOn()
{
int ret;
ALOGE("cur_fm_state = %d\n", cur_fm_state);
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_AUDIO_MUTE, MUTE_L_R_CHAN);
ALOGE("CMD executed mute\n");
}else {
ret = FM_FAILURE;
}
return ret;
}
//Unmute both audio channel
int FmRadioController ::MuteOff()
{
int ret;
ALOGE("cur_fm_state = %d\n", cur_fm_state);
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_AUDIO_MUTE, UNMUTE_L_R_CHAN);
ALOGE("CMD executed for unmute\n");
}else {
ret = FM_FAILURE;
}
return ret;
}
//
int FmRadioController ::SetSoftMute(bool mode)
{
int ret;
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_SOFT_MUTE, mode);
}else {
ret = FM_FAILURE;
}
return ret;
}
int FmRadioController :: Set_mute(bool mute)
{
int ret = 0;
if (mute) {
ret = MuteOn();
} else {
ret = MuteOff();
}
if (ret)
ALOGE("%s failed, %d\n", __func__, ret);
ALOGD("%s, [mute=%d] [ret=%d]\n", __func__, mute, ret);
return ret;
}
int FmRadioController :: Stop_Scan_Seek
(
)
{
int ret;
if((cur_fm_state == SEEK_IN_PROGRESS) ||
(cur_fm_state == SCAN_IN_PROGRESS)) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_SRCHON, 0);
if (ret == FM_SUCCESS) {
ALOGI("FM Seek cancel command set successfully\n");
seek_scan_canceled = true;
} else {
ALOGE("FM Seek cancel command sent failed\n");
}
} else {
ALOGE("FM is not in proper state for cancelling Seek operation\n");
ret = FM_FAILURE;
}
return ret;
}
int FmRadioController :: ReadRDS() //todo define each RDS flag
{
int ret = 0;
if (is_ps_event_received)
ret |= RDS_EVT_PS_UPDATE;
if (is_rt_event_received)
ret |= RDS_EVT_RT_UPDATE;
if (is_af_jump_received)
ret |= RDS_EVT_AF_JUMP;
return ret;
}
int FmRadioController :: Get_ps(char *ps, int *ps_len)
{
int ret = 0;
int len = 0;
char raw_rds[STD_BUF_SIZE];
ret = FmIoctlsInterface::get_buffer(fd_driver,
raw_rds, STD_BUF_SIZE, PS_IND);
if (ret <= 0) {
return FM_FAILURE;
} else {
if (raw_rds[PS_STR_NUM_IND] > 0) {
if (ps != NULL) {
for(int i = 0; i < MAX_PS_LEN; i++) {
ps[i] = raw_rds[PS_DATA_OFFSET_IND + i];
if (ps[i] == 0) {
break;
} else if((ps[len] <= LAST_CTRL_CHAR) ||
(ps[len] >= FIRST_NON_PRNT_CHAR)) {
ps[i] = SPACE_CHAR;
continue;
}
len++;
}
if (len < (MAX_PS_LEN - 1)) {
ps[len] = '\0';
*ps_len = len + 1;
} else {
*ps_len = len;
}
ALOGI("PS is: %s\n", ps);
} else {
return FM_FAILURE;
}
}
}
is_ps_event_received = false;
ALOGD("%s, [ps_len=%d]\n", __func__, *ps_len);
return FM_SUCCESS;
}
int FmRadioController :: Get_rt(char *rt, int *rt_len)
{
int ret = 0;
int len = 0;
char raw_rds[STD_BUF_SIZE];
ret = FmIoctlsInterface::get_buffer(fd_driver,
raw_rds, STD_BUF_SIZE, RT_IND);
if (ret <= 0) {
return FM_FAILURE;
} else {
if (rt != NULL) {
if ((raw_rds[RT_LEN_IND] > 0) &&
(raw_rds[RT_LEN_IND] <= MAX_RT_LEN)) {
for(len = 0; len < raw_rds[RT_LEN_IND]; len++) {
rt[len] = raw_rds[RT_DATA_OFFSET_IND + len];
ALOGI("Rt byte[%d]: %d\n", len, rt[len]);
if ((rt[len] <= LAST_CTRL_CHAR) ||
(rt[len] >= FIRST_NON_PRNT_CHAR)) {
rt[len] = SPACE_CHAR;
continue;
}
}
if (len < (MAX_RT_LEN - 1)) {
rt[len] = '\0';
*rt_len = len + 1;
} else {
*rt_len = len;
}
ALOGI("Rt is: %s\n", rt);
ALOGI("RT text A / B: %d\n", raw_rds[RT_A_B_FLAG_IND]);
} else {
return FM_FAILURE;
}
} else {
return FM_FAILURE;
}
}
is_rt_event_received = false;
ALOGD("%s, [rt_len=%d]\n", __func__, *rt_len);
return FM_SUCCESS;
}
int FmRadioController :: Get_AF_freq(uint16_t *ret_freq)
{
int ret =0;
ULINT lowBand, highBand;
float real_freq = 0;
ALOGI("get_AF_freq\n");
ret = FmIoctlsInterface::get_lowerband_limit(fd_driver,
lowBand);
if (ret != FM_SUCCESS) {
ALOGE("failed to get lowerband: %d\n", ret);
return FM_FAILURE;
}
ALOGI("lowBand = %ld\n",lowBand);
ret = FmIoctlsInterface::get_upperband_limit(fd_driver,
highBand);
if (ret != FM_SUCCESS) {
ALOGE("failed to getgherband: %d\n", ret);
return FM_FAILURE;
}
ALOGI("highBand = %ld\n",highBand);
real_freq = GetChannel();
if ((real_freq < lowBand ) || (real_freq > highBand)) {
ALOGE("AF freq is not in band limits\ni");
return FM_FAILURE;
} else {
*ret_freq = real_freq/100;
}
is_af_jump_received = false;
return FM_SUCCESS;
}
//Emphasis:
//75microsec: 0, 50 microsec: 1
//return FM_SUCCESS on success, FM_FAILURE
//on failure
int FmRadioController :: SetDeConstant
(
long emphasis
)
{
int ret;
ALOGE("cur_fm_state: %d, emphasis: %d\n", cur_fm_state, emphasis);
if(cur_fm_state == FM_ON) {
switch(emphasis) {
case DE_EMP75:
case DE_EMP50:
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_EMPHASIS, emphasis);
break;
default:
ALOGE("FM value pass for set Deconstant is invalid\n");
ret = FM_FAILURE;
break;
}
}else {
ALOGE("FM is not in proper state to set De constant\n");
ret = FM_FAILURE;
}
return ret;
}
int FmRadioController :: GetStationList
(
uint16_t *scan_tbl, int *max_cnt
)
{
char srch_list[STD_BUF_SIZE];
int ret;
ULINT lowBand, highBand;
int station_num = 0;
int stationList[FM_RX_SRCHLIST_MAX_STATIONS];
int tmpFreqByte1=0;
int tmpFreqByte2=0;
int freq = 0;
float real_freq = 0;
int i = 0, j = 0;
ALOGI("getstationList\n");
ret = FmIoctlsInterface::get_lowerband_limit(fd_driver,
lowBand);
if (ret != FM_SUCCESS) {
ALOGE("failed to get lowerband: %d\n", ret);
return FM_FAILURE;
}
ALOGI("lowBand = %ld\n",lowBand);
ret = FmIoctlsInterface::get_upperband_limit(fd_driver,
highBand);
if (ret != FM_SUCCESS) {
ALOGE("failed to getgherband: %d\n", ret);
return FM_FAILURE;
}
ALOGI("highBand = %ld\n",highBand);
ret = FmIoctlsInterface::get_buffer(fd_driver,
srch_list, STD_BUF_SIZE, STATION_LIST_IND);
if ((int)srch_list[0] >0) {
station_num = (int)srch_list[0];
}
ALOGI("station_num: %d ", station_num);
*max_cnt = station_num;
for (i=0;i<station_num;i++) {
freq = 0;
ALOGI(" Byte1 = %d", srch_list[i * NO_OF_BYTES_EACH_FREQ + 1]);
ALOGI(" Byte2 = %d", srch_list[i * NO_OF_BYTES_EACH_FREQ + 2]);
tmpFreqByte1 = srch_list[i * NO_OF_BYTES_EACH_FREQ + 1] & 0xFF;
tmpFreqByte2 = srch_list[i * NO_OF_BYTES_EACH_FREQ + 2] & 0xFF;
ALOGI(" tmpFreqByte1 = %d", tmpFreqByte1);
ALOGI(" tmpFreqByte2 = %d", tmpFreqByte2);
freq = (tmpFreqByte1 & EXTRACT_FIRST_BYTE) << 8;
freq |= tmpFreqByte2;
ALOGI(" freq: %d", freq);
real_freq = (freq * FREQ_MULTIPLEX) + lowBand;
ALOGI(" real_freq: %d", real_freq);
if ( (real_freq < lowBand ) || (real_freq > highBand) ) {
ALOGI("Frequency out of band limits");
} else {
scan_tbl[j] = (real_freq/SRCH_DIV);
ALOGI(" scan_tbl: %d", scan_tbl[j]);
j++;
}
}
return FM_SUCCESS;
}
int FmRadioController ::ScanList
(
uint16_t *scan_tbl, int *max_cnt
)
{
int ret;
struct timespec ts;
/* Check current state of FM device */
if (cur_fm_state == FM_ON) {
ALOGI("FM searchlist started\n");
set_fm_state(SCAN_IN_PROGRESS);
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_SRCHMODE, SRCHLIST_MODE_STRONG);
if (ret != FM_SUCCESS) {
set_fm_state(FM_ON);
return FM_FAILURE;
}
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_SRCH_CNT, FM_RX_SRCHLIST_MAX_STATIONS);
if (ret != FM_SUCCESS) {
set_fm_state(FM_ON);
return FM_FAILURE;
}
ret = FmIoctlsInterface::start_search(fd_driver,
SEARCH_UP);
if (ret != FM_SUCCESS) {
set_fm_state(FM_ON);
return FM_FAILURE;
}
pthread_mutex_lock(&mutex_scan_compl_cond);
ts = set_time_out(SCAN_COMPL_TIMEOUT);
ALOGI("Wait for Scan Timeout or scan complete");
ret = pthread_cond_timedwait(&scan_compl_cond, &mutex_scan_compl_cond, &ts);
ALOGI("Scan complete or timedout");
pthread_mutex_unlock(&mutex_scan_compl_cond);
if (cur_fm_state == FM_ON && !seek_scan_canceled) {
GetStationList(scan_tbl, max_cnt);
} else {
seek_scan_canceled = false;
return FM_FAILURE;
}
} else {
ALOGI("Scanlist: not proper state %d\n",cur_fm_state );
return FM_FAILURE;
}
return FM_SUCCESS;
}
long FmRadioController :: GetCurrentRSSI
(
void
)
{
int ret;
long rmssi = -129;
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::get_rmssi(fd_driver, rmssi);
}else {
}
return rmssi;
}
//enable, disable value to receive data of a RDS group
//return FM_SUCCESS on success, FM_FAILURE on failure
int FmRadioController :: SetRdsGrpProcessing
(
int grps
)
{
int ret;
long mask;
if(cur_fm_state == FM_ON) {
ret = FmIoctlsInterface::get_control(fd_driver,
V4L2_CID_PRV_RDSGROUP_PROC, mask);
if(ret != FM_SUCCESS) {
return ret;
}
mask &= 0xC7;
mask |= ((grps & 0x07) << 3);
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_RDSGROUP_PROC, (int)mask);
}else {
ret = FM_FAILURE;
}
return ret;
}
//Enable RDS data receiving
//Enable RT, PS, AF Jump, RTPLUS, ERT etc
int FmRadioController :: EnableRDS
(
void
)
{
int ret = FM_FAILURE;
ALOGE("%s:cur_fm_state = %d\n", __func__, cur_fm_state);
if (cur_fm_state == FM_ON) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_RDSON, 1);
if (ret != FM_SUCCESS) {
ALOGE("RDS ON failed\n");
return ret;
}
ret = SetRdsGrpProcessing(FM_RX_RDS_GRP_RT_EBL |
FM_RX_RDS_GRP_PS_EBL |
FM_RX_RDS_GRP_AF_EBL |
FM_RX_RDS_GRP_PS_SIMPLE_EBL);
if (ret != FM_SUCCESS) {
ALOGE("Set RDS grp processing\n");
return ret;
}
ret = FM_SUCCESS;
rds_enabled = 1;
EnableAF();
} else {
ALOGE("%s:not in proper state cur_fm_state = %d\n", cur_fm_state);
return ret;
}
return ret;
}
//Disable all RDS data processing
//RT, ERT, RT PLUS, PS
int FmRadioController :: DisableRDS
(
void
)
{
int ret = FM_FAILURE;
ALOGE("%s:cur_fm_state = %d\n", __func__, cur_fm_state);
if (cur_fm_state == FM_ON) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_RDSON, 2);
if (ret != FM_SUCCESS) {
ALOGE("Disable RDS failed\n");
return ret;
}
ret = FM_SUCCESS;
rds_enabled = 0;
DisableAF();
} else {
ALOGE("%s:not in proper state cur_fm_state = %d\n", cur_fm_state);
ret = FM_FAILURE;
}
return ret;
}
int FmRadioController :: Turn_On_Off_Rds(bool onoff)
{
int ret = 0;
if (onoff) {
ret = EnableRDS();
} else {
ret = DisableRDS();
}
if (ret) {
ALOGE("%s, failed\n", __func__);
}
ALOGD("%s, [onoff=%d] [ret=%d]\n", __func__, onoff, ret);
return ret;
}
//Enables Alternate Frequency switching
int FmRadioController :: EnableAF
(
void
)
{
int ret;
long rdsgrps;
if(cur_fm_state == FM_ON) {
ret = FmIoctlsInterface::get_control(fd_driver,
V4L2_CID_PRV_RDSGROUP_PROC, rdsgrps);
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_RDSON, 1);
if(ret == FM_SUCCESS) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_AF_JUMP, 1);
if(ret == FM_SUCCESS) {
af_enabled = 1;
}
} else {
}
} else {
ret = FM_FAILURE;
}
return ret;
}
//Disables Alternate Frequency switching
int FmRadioController :: DisableAF
(
void
)
{
int ret;
long rdsgrps;
if(cur_fm_state == FM_ON) {
ret = FmIoctlsInterface::get_control(fd_driver,
V4L2_CID_PRV_RDSGROUP_PROC, rdsgrps);
if(ret == FM_SUCCESS) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_AF_JUMP, 0);
if(ret == FM_SUCCESS) {
af_enabled = 0;
}
}else {
}
}else {
ret = FM_FAILURE;
}
return ret;
}
//Set regional band
int FmRadioController :: SetBand
(
long band
)
{
int ret;
if(cur_fm_state == FM_ON) {
switch(band) {
case BAND_87500_108000:
ret = FmIoctlsInterface::set_band(fd_driver,
87500, 108000);
break;
case BAND_76000_108000:
ret = FmIoctlsInterface::set_band(fd_driver,
76000, 108000);
break;
case BAND_76000_90000:
ret = FmIoctlsInterface::set_band(fd_driver,
76000, 90000);
break;
default:
ALOGE("Band type: %ld is invalid\n", band);
ret = FM_FAILURE;
break;
}
}else {
ALOGE("FM is not in proper state to set band type\n");
ret = FM_FAILURE;
}
return ret;
}
//set spacing for successive channels
int FmRadioController :: SetChannelSpacing
(
long spacing
)
{
int ret;
if (cur_fm_state == FM_ON) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_CHAN_SPACING, spacing);
} else {
ALOGE("FM is not in proper state to set the channel spacing\n");
ret = FM_FAILURE;
}
return ret;
}
int FmRadioController :: SetStereo
(
)
{
int ret;
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::set_audio_mode(fd_driver,
STEREO);
}else {
ret = FM_FAILURE;
}
return ret;
}
int FmRadioController :: SetMono
(
)
{
int ret;
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::set_audio_mode(fd_driver,
MONO);
}else {
ret = FM_FAILURE;
}
return ret;
}
bool FmRadioController :: GetSoftMute
(
)
{
int ret = FM_SUCCESS;
long mode = SMUTE_DISABLED;
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::get_control(fd_driver,
V4L2_CID_PRV_SOFT_MUTE, mode);
if(ret == FM_SUCCESS) {
ALOGI("FM Get soft mute is successful: %ld\n", mode);
}else {
ALOGE("FM Get soft mute failed");
}
}else {
ALOGE("FM is not in proper state for getting soft mute\n");
ret = FM_FAILURE;
}
return mode;
}
int FmRadioController :: Antenna_Switch(int antenna)
{
int ret = 0;
if (antenna) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_ANTENNA, 1);
} else {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_ANTENNA, 0);
}
ALOGD("%s, antenna type = %d [ret=%d]\n", __func__, antenna, ret);
return ret;
}
int FmRadioController :: get_fm_state
(
)
{
return cur_fm_state;
}
void FmRadioController :: set_fm_state
(
int state
)
{
pthread_mutex_lock(&mutex_fm_state);
cur_fm_state = state;
pthread_mutex_unlock(&mutex_fm_state);
}
void* FmRadioController :: handle_events
(
void *arg
)
{
int bytesread;
char event_buff[STD_BUF_SIZE];
bool status = true;
FmRadioController *obj_p = static_cast<FmRadioController*>(arg);
while(status && !obj_p->event_listener_canceled) {
bytesread = FmIoctlsInterface::get_buffer(obj_p->fd_driver,
event_buff, STD_BUF_SIZE, EVENT_IND);
for(int i = 0; i < bytesread; i++) {
status = obj_p->process_radio_events(event_buff[i]);
if(status == false) {
break;
}
}
}
return NULL;
}
int FmRadioController :: SetRdsGrpMask
(
int mask
)
{
int ret;
if((cur_fm_state != FM_OFF) &&
(cur_fm_state != FM_OFF_IN_PROGRESS) &&
(cur_fm_state != FM_ON_IN_PROGRESS)) {
ret = FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_RDSGROUP_MASK, mask);
}else {
ret = FM_FAILURE;
}
return ret;
}
void FmRadioController :: handle_enabled_event
(
void
)
{
char value[PROPERTY_VALUE_MAX] = {'\0'};
ALOGI("FM handle ready Event\n");
FmIoctlsInterface::set_control(fd_driver,
V4L2_CID_PRV_AUDIO_PATH, AUDIO_DIGITAL_PATH);
property_get("qcom.bluetooth.soc", value, NULL);
if (strcmp(value, "rome") != 0) {
FmIoctlsInterface::set_calibration(fd_driver);
}
pthread_mutex_lock(&mutex_turn_on_cond);
set_fm_state(FM_ON);
pthread_cond_broadcast(&turn_on_cond);
pthread_mutex_unlock(&mutex_turn_on_cond);
}
void FmRadioController :: handle_tuned_event
(
void
)
{
long freq = -1;
ALOGI("FM handle Tune event\n");
freq = GetChannel();
switch(cur_fm_state) {
case FM_ON:
if(af_enabled && (freq != prev_freq)
&& (prev_freq > 0)) {
ALOGI("AF jump happened\n");
is_af_jump_received = true;
}
break;
case FM_TUNE_IN_PROGRESS:
pthread_mutex_lock(&mutex_tune_compl_cond);
set_fm_state(FM_ON);
pthread_cond_broadcast(&tune_compl_cond);
pthread_mutex_unlock(&mutex_tune_compl_cond);
break;
case SEEK_IN_PROGRESS:
pthread_mutex_lock(&mutex_seek_compl_cond);
set_fm_state(FM_ON);
pthread_cond_broadcast(&seek_compl_cond);
pthread_mutex_unlock(&mutex_seek_compl_cond);
break;
case SCAN_IN_PROGRESS:
break;
}
prev_freq = freq;
}
void FmRadioController :: handle_seek_next_event
(
void
)
{
ALOGI("FM handle seek next event\n");
}
void FmRadioController :: handle_seek_complete_event
(
void
)
{
ALOGI("FM handle seek complete event\n");
}
void FmRadioController :: handle_raw_rds_event
(
void
)
{
}
void FmRadioController :: handle_rt_event
(
void
)
{
ALOGI("FM handle RT event\n");
is_rt_event_received = true;
}
void FmRadioController :: handle_ps_event
(
void
)
{
ALOGI("FM handle PS event\n");
is_ps_event_received = true;
}
void FmRadioController :: handle_error_event
(
void
)
{
}
void FmRadioController :: handle_below_th_event
(
void
)
{
}
void FmRadioController :: handle_above_th_event
(
void
)
{
}
void FmRadioController :: handle_stereo_event
(
void
)
{
}
void FmRadioController :: handle_mono_event
(
void
)
{
}
void FmRadioController :: handle_rds_aval_event
(
void
)
{
ALOGI("Got rds_aval_event\n");
is_rds_support = true;
}
void FmRadioController :: handle_rds_not_aval_event
(
void
)
{
ALOGI("Got rds_not_aval_event\n");
}
void FmRadioController :: handle_srch_list_event
(
void
)
{
ALOGI("Got srch list event\n");
if (cur_fm_state == SCAN_IN_PROGRESS) {
pthread_mutex_lock(&mutex_scan_compl_cond);
set_fm_state(FM_ON);
pthread_cond_broadcast(&scan_compl_cond);
pthread_mutex_unlock(&mutex_scan_compl_cond);
}
}
void FmRadioController :: handle_af_list_event
(
void
)
{
char raw_rds[STD_BUF_SIZE];
int ret;
int aflist_size;
ULINT lower_band;
int AfList[MAX_AF_LIST_SIZE];
ALOGI("Got af list event\n");
ret = FmIoctlsInterface::get_buffer(fd_driver,
raw_rds, STD_BUF_SIZE, AF_LIST_IND);
lower_band = FmIoctlsInterface::get_lowerband_limit(fd_driver,
lower_band);
ALOGI("raw_rds[0]: %d\n", (raw_rds[0] & 0xff));
ALOGI("raw_rds[1]: %d\n", (raw_rds[1] & 0xff));
ALOGI("raw_rds[2]: %d\n", (raw_rds[2] & 0xff));
ALOGI("raw_rds[3]: %d\n", (raw_rds[3] & 0xff));
ALOGI("raw_rds[4]: %d\n", (raw_rds[4] & 0xff));
ALOGI("raw_rds[5]: %d\n", (raw_rds[5] & 0xff));
ALOGI("raw_rds[6]: %d\n", (raw_rds[6] & 0xff));
aflist_size = raw_rds[AF_SIZE_IDX] & 0xff;
for(int i = 0; i < aflist_size; i++) {
AfList[i] = (raw_rds[AF_SIZE_IDX + i * NO_OF_BYTES_AF + 1] & 0xFF) |
((raw_rds[AF_SIZE_IDX + i * NO_OF_BYTES_AF + 2] & 0xFF) << 8) |
((raw_rds[AF_SIZE_IDX + i * NO_OF_BYTES_AF + 3] & 0xFF) << 16) |
((raw_rds[AF_SIZE_IDX + i * NO_OF_BYTES_AF + 4] & 0xFF) << 24);
ALOGI("AF: %d\n", AfList[i]);
}
}
void FmRadioController :: handle_disabled_event
(
void
)
{
//Expected disabled
if(cur_fm_state == FM_OFF_IN_PROGRESS) {
ALOGI("Expected disabled event\n");
}else {//Enexpected disabled
ALOGI("Unexpected disabled event\n");
}
set_fm_state(FM_OFF);
close(fd_driver);
fd_driver = -1;
//allow tune function to exit
pthread_mutex_lock(&mutex_tune_compl_cond);
pthread_cond_broadcast(&tune_compl_cond);
pthread_mutex_unlock(&mutex_tune_compl_cond);
//allow scan function to exit
pthread_mutex_lock(&mutex_scan_compl_cond);
pthread_cond_broadcast(&scan_compl_cond);
pthread_mutex_unlock(&mutex_scan_compl_cond);
//Allow seek function to exit
pthread_mutex_lock(&mutex_seek_compl_cond);
pthread_cond_broadcast(&seek_compl_cond);
pthread_mutex_unlock(&mutex_seek_compl_cond);
}
void FmRadioController :: handle_rds_grp_mask_req_event
(
void
)
{
SetRdsGrpMask(0);
}
void FmRadioController :: handle_rt_plus_event
(
void
)
{
ALOGI("FM handle RT Plus event\n");
}
void FmRadioController :: handle_af_jmp_event
(
void
)
{
long freq = -1;
freq = GetChannel();
ALOGI("FM handle AF Jumped event\n");
if(af_enabled && (freq != prev_freq)) {
ALOGI("AF Jump occured, prevfreq is: %ld, af freq is: %ld\n", prev_freq, freq);
}
prev_freq = freq;
}
void FmRadioController :: handle_ert_event
(
void
)
{
ALOGI("FM handle ERT event\n");
}
bool FmRadioController :: process_radio_events
(
int event
)
{
bool ret = true;
switch(event) {
case READY_EVENT:
handle_enabled_event();
break;
case TUNE_EVENT:
handle_tuned_event();
break;
case SEEK_COMPLETE_EVENT:
handle_seek_complete_event();
break;
case SCAN_NEXT_EVENT:
handle_seek_next_event();
break;
case RAW_RDS_EVENT:
handle_raw_rds_event();
break;
case RT_EVENT:
handle_rt_event();
break;
case PS_EVENT:
handle_ps_event();
break;
case ERROR_EVENT:
handle_error_event();
break;
case BELOW_TH_EVENT:
handle_below_th_event();
break;
case ABOVE_TH_EVENT:
handle_above_th_event();
break;
case STEREO_EVENT:
handle_stereo_event();
break;
case MONO_EVENT:
handle_mono_event();
break;
case RDS_AVAL_EVENT:
handle_rds_aval_event();
break;
case RDS_NOT_AVAL_EVENT:
handle_rds_not_aval_event();
break;
case SRCH_LIST_EVENT:
handle_srch_list_event();
break;
case AF_LIST_EVENT:
handle_af_list_event();
break;
case DISABLED_EVENT:
handle_disabled_event();
ret = false;
break;
case RDS_GRP_MASK_REQ_EVENT:
handle_rds_grp_mask_req_event();
break;
case RT_PLUS_EVENT:
handle_rt_plus_event();
break;
case ERT_EVENT:
handle_ert_event();
break;
case AF_JMP_EVENT:
handle_af_jmp_event();
break;
default:
break;
}
return ret;
}