blob: 711eba4b4b36ce7f7a786369896fa8c97d2e6bc7 [file] [log] [blame]
/*
* Copyright (c) 2009,2012-2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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.
*/
package qcom.fmradio;
import android.content.Context;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.telephony.PhoneStateListener;
import android.util.Log;
import android.os.SystemProperties;
import java.util.Arrays;
import java.lang.Runnable;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.content.IntentFilter;
import android.bluetooth.BluetoothAdapter;
/**
* This class contains all interfaces and types needed to
* Control the FM receiver.
* @hide
*/
public class FmReceiver extends FmTransceiver
{
public static int mSearchState = subSrchLevel_NoSearch;
private IntentFilter mIntentFilter;
private IntentFilter mBtIntentFilter;
static final int STD_BUF_SIZE = 256;
static final int GRP_3A = 64;
static final int ENABLE_LPF = 1;
static final int DISABLE_LPF = 0;
private static final String TAG = "FMRadio";
private static int mEnableLpfGprs = 0x1;
private static int mEnableLpfEdge = 0x2;
private static int mEnableLpfUmts = 0x4;
private static int mEnableLpfCdma = 0x8;
private static int mEnableLpfEvdo0 = 0x10;
private static int mEnableLpfEvdoA = 0x20;
private static int mEnableLpf1xRtt = 0x40;
private static int mEnableLpfHsdpa = 0x80;
private static int mEnableLpfHsupa = 0x100;
private static int mEnableLpfHspa = 0x200;
private static int mEnableLpfIden = 0x400;
private static int mEnableLpfEvdoB = 0x800;
private static int mEnableLpfLte = 0x1000;
private static int mEnableLpfEhrpd = 0x2000;
private static int mEnableLpfHspap = 0x4000;
private static int mEnableLpfGsm = 0x8000;
private static int mEnableLpfScdma = 0x10000;
private static int mEnableLpfIwlan = 0x20000;
private static int mEnableLpfLteCa = 0x40000;
private static int mIsBtLpfEnabled = 0x01;
private static int mIsWlanLpfEnabled = 0x2;
/**
* Search (seek/scan/searchlist) by decrementing the frequency
*
* @see #FM_RX_SEARCHDIR_UP
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
* @see #searchStationList
*/
public static final int FM_RX_SEARCHDIR_DOWN=0;
/**
* Search (seek/scan/searchlist) by inrementing the frequency
*
* @see #FM_RX_SEARCHDIR_DOWN
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
* @see #searchStationList
*/
public static final int FM_RX_SEARCHDIR_UP=1;
/**
* Scan dwell (Preview) duration = 0 seconds
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_DWELL_PERIOD_0S=0;
/**
* Scan dwell (Preview) duration = 1 second
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_DWELL_PERIOD_1S=1;
/**
* Scan dwell (Preview) duration = 2 seconds
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_DWELL_PERIOD_2S=2;
/**
* Scan dwell (Preview) duration = 3 seconds
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_DWELL_PERIOD_3S=3;
/**
* Scan dwell (Preview) duration = 4 seconds
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_DWELL_PERIOD_4S=4;
/**
* Scan dwell (Preview) duration = 5 seconds
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_DWELL_PERIOD_5S=5;
/**
* Scan dwell (Preview) duration = 6 seconds
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_DWELL_PERIOD_6S=6;
/**
* Scan dwell (Preview) duration = 7 second
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_DWELL_PERIOD_7S=7;
/**
* Basic Seek Mode Option
*
* @see #searchStations(int, int, int)
*/
public static final int FM_RX_SRCH_MODE_SEEK =0;
/**
* Basic Scan Mode Option
*
* @see #searchStations(int, int, int)
*/
public static final int FM_RX_SRCH_MODE_SCAN =1;
/**
* Search list mode Options to search for Strong stations
*
* @see #searchStationList
*/
public static final int FM_RX_SRCHLIST_MODE_STRONG =2;
/**
* Search list mode Options to search for Weak stations
*
* @see #searchStationList
*/
public static final int FM_RX_SRCHLIST_MODE_WEAK =3;
/**
* Seek by Program Type
*
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_SRCHRDS_MODE_SEEK_PTY =4;
/**
* Scan by Program Type
*
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_SRCHRDS_MODE_SCAN_PTY =5;
/**
* Seek by Program identification
*
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_SRCHRDS_MODE_SEEK_PI =6;
/**
* Seek Alternate Frequency for the same station
*
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_SRCHRDS_MODE_SEEK_AF =7;
/**
* Search list mode Options to search for Strongest stations
*
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_SRCHLIST_MODE_STRONGEST =8;
/**
* Search list mode Options to search for Weakest stations
*
* @see #searchStations(int, int, int, int, int)
*/
public static final int FM_RX_SRCHLIST_MODE_WEAKEST =9;
/**
* Maximum number of stations the SearchStationList can
* support
*
* @see #searchStationList
*/
public static final int FM_RX_SRCHLIST_MAX_STATIONS =12;
/**
* Argument option for setMuteMode to unmute FM
*
* @see #setMuteMode
*/
public static final int FM_RX_UNMUTE =0;
/**
* Argument option for setMuteMode to Mute FM
*
* @see #setMuteMode
*/
public static final int FM_RX_MUTE =1;
/**
* Argument option for setStereoMode to set FM to Stereo
* Mode.
*
* @see #setStereoMode
*/
public static final int FM_RX_AUDIO_MODE_STEREO =0;
/**
* Argument option for setStereoMode to set FM to "Force
* Mono" Mode.
*
* @see #setStereoMode
*/
public static final int FM_RX_AUDIO_MODE_MONO =1;
/**
* Signal Strength
*
* @see #setSignalThreshold
* @see #getSignalThreshold
*/
public static final int FM_RX_SIGNAL_STRENGTH_VERY_WEAK =0;
public static final int FM_RX_SIGNAL_STRENGTH_WEAK =1;
public static final int FM_RX_SIGNAL_STRENGTH_STRONG =2;
public static final int FM_RX_SIGNAL_STRENGTH_VERY_STRONG=3;
/**
* Power settings
*
* @see #setPowerMode
* @see #getPowerMode
*/
public static final int FM_RX_NORMAL_POWER_MODE =0;
public static final int FM_RX_LOW_POWER_MODE =1;
/**
* RDS Processing Options
*
* @see #registerRdsGroupProcessing
* @see #getPSInfo
* @see #getRTInfo
* @see #getAFInfo
*/
public static final int FM_RX_RDS_GRP_RT_EBL =1;
public static final int FM_RX_RDS_GRP_PS_EBL =2;
public static final int FM_RX_RDS_GRP_PS_SIMPLE_EBL =4;
public static final int FM_RX_RDS_GRP_AF_EBL =8;
public static final int FM_RX_RDS_GRP_ECC_EBL =32;
public static final int FM_RX_RDS_GRP_PTYN_EBL =64;
public static final int FM_RX_RDS_GRP_RT_PLUS_EBL =128;
private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
private static final int V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH = V4L2_CID_PRIVATE_BASE + 8;
private static final int V4L2_CTRL_CLASS_USER = 0x00980000;
private static final int V4L2_CID_PRIVATE_IRIS_GET_SPUR_TBL = (V4L2_CTRL_CLASS_USER + 0x92E);
private static final int TAVARUA_BUF_SRCH_LIST=0;
private static final int TAVARUA_BUF_EVENTS=1;
private static final int TAVARUA_BUF_RT_RDS=2;
private static final int TAVARUA_BUF_PS_RDS=3;
private static final int TAVARUA_BUF_RAW_RDS=4;
private static final int TAVARUA_BUF_AF_LIST=5;
private static final int TAVARUA_BUF_MAX=6;
public static FmRxEvCallbacksAdaptor mCallback;
static FmRxEvCallbacks callback;
static FmReceiverJNI mFmReceiverJNI;
/**
* Internal Constants for Signal thresholds
*
* @see #setSignalThreshold
* @see #getSignalThreshold
*/
private static final int FM_RX_RSSI_LEVEL_VERY_WEAK = -105;
private static final int FM_RX_RSSI_LEVEL_WEAK = -100;
private static final int FM_RX_RSSI_LEVEL_STRONG = -96;
private static final int FM_RX_RSSI_LEVEL_VERY_STRONG = -90;
/**
* BUF_TYPE
*/
private static final int BUF_ERT = 12;
private static final int BUF_RTPLUS = 11;
private static final int LEN_IND = 0;
private static final int RT_OR_ERT_IND = 1;
private static final int ENCODE_TYPE_IND = 1;
private static final int ERT_DIR_IND = 2;
/**
* Search Algo type
*/
private static final int SEARCH_MPXDCC = 0;
private static final int SEARCH_SINR_INT = 1;
public boolean isSmdTransportLayer() {
String chip = SystemProperties.get("vendor.bluetooth.soc","default");
if (chip.equals("default"))
return true;
else
return false;
}
public static boolean isRomeChip() {
String chip = SystemProperties.get("vendor.bluetooth.soc");
if (chip.equals("rome"))
return true;
else
return false;
}
public static boolean isCherokeeChip() {
String chip = SystemProperties.get("vendor.bluetooth.soc");
if (chip.equals("cherokee"))
return true;
else
return false;
}
public PhoneStateListener mDataConnectionStateListener = new PhoneStateListener(){
public void onDataConnectionStateChanged(int state, int networkType) {
Log.d (TAG, "state: " + Integer.toString(state) + " networkType: " + Integer.toString(networkType));
if (state == TelephonyManager.DATA_CONNECTED) {
FMcontrolLowPassFilter(state, networkType, ENABLE_LPF);
} else if (state == TelephonyManager.DATA_DISCONNECTED) {
FMcontrolLowPassFilter(state, networkType, DISABLE_LPF);
}
}
};
/* Register for wan state changes to support wan-fm concurrency */
public void registerDataConnectionStateListener(Context mContext) {
Log.d (TAG, "registerDataConnectionStateListener");
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(mDataConnectionStateListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
}
/* UnRegister */
public void unregisterDataConnectionStateListener(Context mContext) {
Log.d (TAG, "unregisterDataConnectionStateListener: ");
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(mDataConnectionStateListener, PhoneStateListener.LISTEN_NONE);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d (TAG, "onReceive: Wifi State change intent");
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
int mBtWlanLpf = SystemProperties.getInt("persist.btwlan.lpfenabler", 0);
if (newState == WifiManager.WIFI_STATE_ENABLED) {
Log.d (TAG, "enable LPF on wifi enabled " + newState);
if ((mBtWlanLpf & mIsWlanLpfEnabled) == mIsWlanLpfEnabled)
mControl.enableLPF(sFd, ENABLE_LPF);
} else if ((mBtWlanLpf & mIsWlanLpfEnabled) == mIsWlanLpfEnabled) {
Log.d (TAG, "Disable LPF on wifi state other than enabled " + newState);
mControl.enableLPF(sFd, DISABLE_LPF);
}
} else {
Log.d (TAG, "WIFI_STATE_CHANGED_ACTION failed");
}
}
};
private final BroadcastReceiver mBtReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d (TAG, "onReceive: Bluetooth State change intent");
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
int mBtWlanLpf = SystemProperties.getInt("persist.btwlan.lpfenabler", 0);
if (newState == BluetoothAdapter.STATE_ON) {
Log.d (TAG, "enable LPF on BT enabled " + newState);
if ((mBtWlanLpf & mIsBtLpfEnabled) == mIsBtLpfEnabled)
mControl.enableLPF(sFd, ENABLE_LPF);
} else if ((mBtWlanLpf & mIsBtLpfEnabled) == mIsBtLpfEnabled) {
Log.d (TAG, "Disable LPF on BT state other than enabled " + newState);
mControl.enableLPF(sFd, DISABLE_LPF);
}
} else {
Log.d (TAG, "ACTION_STATE_CHANGED failed");
}
}
};
/**
* Constructor for the receiver Object
*/
public FmReceiver(){
mControl = new FmRxControls();
mRdsData = new FmRxRdsData (sFd);
mRxEvents = new FmRxEventListner();
}
/**
* Constructor for the receiver Object that takes path to
* radio and event callbacks.
* <p>
* @param devicePath FM Device path String.
* @param callback the callbacks to handle the events
* events from the FM receiver.
*
*/
public FmReceiver(String devicePath,
FmRxEvCallbacksAdaptor callback) throws InstantiationException {
mControl = new FmRxControls();
mRxEvents = new FmRxEventListner();
Log.e(TAG, "FmReceiver constructor");
//registerClient(callback);
mCallback = callback;
if (isCherokeeChip()) {
mFmReceiverJNI = new FmReceiverJNI(mCallback);
}
}
/*==============================================================
FUNCTION: registerClient
==============================================================*/
/**
* Registers a callback for FM receiver event
* notifications.
* <p>
* This is a synchronous command used to register for event
* notifications from the FM receiver driver. Since the FM
* driver performs some tasks asynchronously, this function
* allows the client to receive information asynchronously.
* <p>
* When calling this function, the client must pass a callback
* function which will be used to deliver asynchronous events.
* The argument callback must be a non-NULL value. If a NULL
* value is passed to this function, the registration will
* fail.
* <p>
* The client can choose which events will be sent from the
* receiver driver by simply implementing functions for events
* it wishes to receive.
* <p>
* @param callback the callbacks to handle the events
* events from the FM receiver.
* @return true if Callback registered, false if Callback
* registration failed.
* <p>
* @see #acquire
* @see #unregisterClient
*
*/
public boolean registerClient(FmRxEvCallbacks callback){
boolean status;
status = super.registerClient(callback);
/* Do Receiver Specific Stuff here.*/
return status;
}
/*==============================================================
FUNCTION: unregisterClient
==============================================================*/
/**
* UnRegisters a client's event notification callback.
*
* This is a synchronous command used to unregister a client's
* event callback.
* <p>
* @return true Always returns true.
* <p>
* @see #acquire
* @see #release
* @see #registerClient
*
*/
public boolean unregisterClient () {
boolean status;
status = super.unregisterClient();
/* Do Receiver Specific Stuff here.*/
return status;
}
/*==============================================================
FUNCTION: enable
==============================================================*/
/**
* Enables the FM device in Receiver Mode.
* <p>
* This is a synchronous method used to initialize the FM
* receiver. If already initialized this function will
* intialize the receiver with default settings. Only after
* successfully calling this function can many of the FM device
* interfaces be used.
* <p>
* When enabling the receiver, the client must also provide
* the regional settings in which the receiver will operate.
* These settings (included in argument configSettings) are
* typically used for setting up the FM receiver for operating
* in a particular geographical region. These settings can be
* changed after the FM driver is enabled through the use of
* the function {@link #configure}.
* <p>
* This command can only be issued by the owner of an FM
* receiver. To issue this command, the client must first
* successfully call {@link #acquire}.
* <p>
* @param configSettings the settings to be applied when
* turning on the radio
* @return true if Initialization succeeded, false if
* Initialization failed.
* <p>
* @see #enable
* @see #registerClient
* @see #disable
*
*/
public boolean enable (FmConfig configSettings, Context app_context){
boolean status = false;
/*
* Check for FM State.
* If FMRx already on, then return.
*/
int state = getFMState();
mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
mBtIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
if (state == FMState_Rx_Turned_On || state == FMState_Srch_InProg) {
Log.d(TAG, "enable: FM already turned On and running");
return status;
}else if (state == subPwrLevel_FMTurning_Off) {
Log.v(TAG, "FM is in the process of turning off.Pls wait for sometime.");
return status;
}else if (state == subPwrLevel_FMRx_Starting) {
Log.v(TAG, "FM is in the process of turning On.Pls wait for sometime.");
return status;
}else if ((state == FMState_Tx_Turned_On)
|| (state == subPwrLevel_FMTx_Starting)) {
Log.v(TAG, "FM Tx is turned on or in the process of turning on.");
return status;
}
setFMPowerState(subPwrLevel_FMRx_Starting);
Log.v(TAG, "enable: CURRENT-STATE : FMOff ---> NEW-STATE : FMRxStarting");
status = super.enable(configSettings, FmTransceiver.FM_RX);
if (status == true ) {
if (!isCherokeeChip()) {
/* Do Receiver Specific Enable Stuff here.*/
status = registerClient(mCallback);
}
mRdsData = new FmRxRdsData(sFd);
registerDataConnectionStateListener(app_context);
app_context.registerReceiver(mReceiver, mIntentFilter);
int mBtWlanLpf = SystemProperties.getInt("persist.btwlan.lpfenabler", 0);
WifiManager wifiManager = (WifiManager)app_context.getSystemService(app_context.WIFI_SERVICE);
if (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
if ((mBtWlanLpf & mIsWlanLpfEnabled) == mIsWlanLpfEnabled) {
Log.d(TAG, "enable LPF if WIFI is already on");
mControl.enableLPF(sFd, ENABLE_LPF);
}
}
app_context.registerReceiver(mBtReceiver, mBtIntentFilter);
BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
if (btAdapter != null) {
if ((mBtWlanLpf & mIsWlanLpfEnabled) == mIsWlanLpfEnabled) {
Log.d(TAG, "enable LPF if BT is already on");
mControl.enableLPF(sFd, ENABLE_LPF);
}
}
}
else {
status = false;
Log.e(TAG, "enable: Error while turning FM On");
Log.e(TAG, "enable: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMOff");
setFMPowerState(FMState_Turned_Off);
}
return status;
}
/*==============================================================
FUNCTION: reset
==============================================================*/
/**
* Reset the FM Device.
* <p>
* This is a synchronous command used to reset the state of FM
* device in case of unrecoverable error. This function is
* expected to be used when the client receives unexpected
* notification of radio disabled. Once called, most
* functionality offered by the FM device will be disabled
* until the client re-enables the device again via
* {@link #enable}.
* <p>
* @return true if reset succeeded, false if reset failed.
* @see #enable
* @see #disable
* @see #registerClient
*/
public boolean reset(){
boolean status = false;
int state = getFMState();
if(state == FMState_Turned_Off) {
Log.d(TAG, "FM already turned Off.");
return false;
}
setFMPowerState(FMState_Turned_Off);
Log.v(TAG, "reset: NEW-STATE : FMState_Turned_Off");
status = unregisterClient();
release("/dev/radio0");
return status;
}
/*==============================================================
FUNCTION: disable
==============================================================*/
/**
* Disables the FM Device.
* <p>
* This is a synchronous command used to disable the FM
* device. This function is expected to be used when the
* client no longer requires use of the FM device. Once
* called, most functionality offered by the FM device will be
* disabled until the client re-enables the device again via
* {@link #enable}.
* <p>
* @return true if disabling succeeded, false if disabling
* failed.
* @see #enable
* @see #registerClient
*/
public boolean disable(Context app_context){
boolean status = false;
/*
* Check for FM State. If search is in progress, then cancel the search prior
* to disabling FM.
*/
int state = getFMState();
switch(state) {
case FMState_Turned_Off:
Log.d(TAG, "FM already tuned Off.");
return false;
case FMState_Srch_InProg:
Log.v(TAG, "disable: Cancelling the on going search operation prior to disabling FM");
setSearchState(subSrchLevel_SrchAbort);
cancelSearch();
Log.v(TAG, "disable: Wait for the state to change from : Search ---> FMRxOn");
try {
/*
* The delay of 50ms here is very important.
* This delay is useful for the cleanup purpose
* when HS is abruptly plugged out when search
* is in progress.
*/
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case subPwrLevel_FMRx_Starting:
/*
* If, FM is in the process of turning On, then wait for
* the turn on operation to complete before turning off.
*/
Log.d(TAG, "disable: FM not yet turned On...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
/* Check for the state of FM device */
state = getFMState();
if(state == subPwrLevel_FMRx_Starting) {
Log.e(TAG, "disable: FM in bad state");
return status;
}
break;
case subPwrLevel_FMTurning_Off:
/*
* If, FM is in the process of turning Off, then wait for
* the turn off operation to complete.
*/
Log.v(TAG, "disable: FM is getting turned Off.");
return status;
}
setFMPowerState(subPwrLevel_FMTurning_Off);
Log.v(TAG, "disable: CURRENT-STATE : FMRxOn ---> NEW-STATE : FMTurningOff");
super.disable();
unregisterDataConnectionStateListener(app_context);
app_context.unregisterReceiver(mBtReceiver);
app_context.unregisterReceiver(mReceiver);
return true;
}
/*==============================================================
FUNCTION: getSearchState
==============================================================*/
/**
* Gets the current state of the search operation.
* <p>
* This function is expected to be used when searchStations()
* function wants to know whether any seek/scan/auto-select
* operation is already in-progress.
* If a seek command is issued when one is already in-progress,
* we cancel the on-going seek command and start a new search
* operation.
* <p>
* @return current state of FM Search operation:
* SRCH_COMPLETE
* SRCH_INPROGRESS
* SRCH_ABORTED
*/
static int getSearchState()
{
return mSearchState;
}
/*==============================================================
FUNCTION: setSearchState
==============================================================*/
/**
* Sets the current state of the search operation.
* <p>
* This function is used to set the current state of the
* search operation. If a seek command is issued when one
* is already in-progress, we cancel the on-going seek command,
* set the state of search operation to SRCH_ABORTED
* and start a new search.
* <p>
* @return none
*/
static void setSearchState(int state)
{
mSearchState = state;
switch(mSearchState) {
case subSrchLevel_SeekInPrg:
case subSrchLevel_ScanInProg:
case subSrchLevel_SrchListInProg:
setFMPowerState(FMState_Srch_InProg);
break;
case subSrchLevel_SrchComplete:
/* Update the state of the FM device */
mSearchState = subSrchLevel_NoSearch;
setFMPowerState(FMState_Rx_Turned_On);
break;
case subSrchLevel_SrchAbort:
break;
default:
mSearchState = subSrchLevel_NoSearch;
break;
}
}
/*==============================================================
FUNCTION: searchStations
==============================================================*/
/**
* Initiates basic seek and scan operations.
* <p>
* This command is used to invoke a basic seek/scan of the FM
* radio band.
* <p>
* <ul>
* This API is used to:
* <li> Invoke basic seek operations ({@link
* #FM_RX_SRCH_MODE_SEEK})
* <li> Invoke basic scan operations ({@link
* #FM_RX_SRCH_MODE_SCAN})
* </ul>
* <p>
* The most basic operation performed by this function
* is a {@link #FM_RX_SRCH_MODE_SEEK} command. The seek
* process is handled incrementing or decrementing the
* frequency in pre-defined channel steps (defined by the
* channel spacing) and measuring the resulting signal level.
* Once a station is successfully tuned and found to meet or
* exceed this signal level, the seek operation will be
* completed and a FmRxEvSearchComplete event will be returned
* to the client. If no stations are found to match the search
* criteria, the frequency will be returned to the originally
* tuned station.
* <p>
* Since seek always results in a frequency being tuned, each
* seek operation will also return a single
* FmRxEvRadioTuneStatus event to the client/application
* layer.
* <p>
* Much like {@link #FM_RX_SRCH_MODE_SEEK}, a {@link
* #FM_RX_SRCH_MODE_SCAN} command can be likened to many back
* to back seeks with a dwell period after each successful
* seek. Once issued, a scan will either increment or
* decrement frequencies by the defined channel spacing until
* a station is found to meet or exceed the set search
* threshold. Once this station is found, and is successfully
* tuned, an FmRxEvRadioTuneStatus event will be returned to
* the client and the station will remain tuned for the
* specific period of time indicated by argument dwellPeriod.
* After that time expires, an FmRxEvSearchInProgress event
* will be sent to the client and a new search will begin for
* the next station that meets the search threshold. After
* scanning the entire band, or after a cancel search has been
* initiated by the client, an FmRxEvRadioTuneStatus event
* will be sent to the client. Similar to a seek command, each
* scan will result in at least one station being tuned, even
* if this is the starting frequency.
* <p>
* Each time the driver initiates a search (seek or scan) the client
* will be notified via an FmRxEvSearchInProgress event.
* Similarly, each time a search completes, the client will be notified via an
* FmRxEvRadioTuneStatus event.
* <p>
* Once issuing a search command, several commands from the client
* may be disallowed until the search is completed or cancelled.
* <p>
* The search can be canceled at any time by using API
* cancelSearch (). Once cancelled, each search will tune to the
* last tuned station and generate both FmRxEvSearchComplete and
* FmRxEvRadioTuneStatus events.
* Valid Values for argument 'mode':
* <ul>
* <li>{@link #FM_RX_SRCH_MODE_SEEK}
* <li>{@link #FM_RX_SRCH_MODE_SCAN}
* </ul>
* <p>
* Valid Values for argument 'dwellPeriod' :
* <ul>
* <li>{@link #FM_RX_DWELL_PERIOD_1S}
* <li>{@link #FM_RX_DWELL_PERIOD_2S}
* <li>{@link #FM_RX_DWELL_PERIOD_3S}
* <li>{@link #FM_RX_DWELL_PERIOD_4S}
* <li>{@link #FM_RX_DWELL_PERIOD_5S}
* <li>{@link #FM_RX_DWELL_PERIOD_6S}
* <li>{@link #FM_RX_DWELL_PERIOD_7S}
* </ul>
* <p>
* Valid Values for argument 'direction' :
* <ul>
* <li>{@link #FM_RX_SEARCHDIR_DOWN}
* <li>{@link #FM_RX_SEARCHDIR_UP}
* </ul>
* <p>
*
* <p>
* @param mode the FM search mode.
* @param dwellPeriod the FM scan dwell time. Used only when
* mode={@link #FM_RX_SRCH_MODE_SCAN}
* @param direction the Search Direction.
* <p>
* @return true if Search Initiate succeeded, false if
* Search Initiate failed.
*
* @see #searchStations(int, int, int, int, int)
* @see #searchStationList
*/
public boolean searchStations (int mode,
int dwellPeriod,
int direction){
int state = getFMState();
boolean bStatus = true;
int re;
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "searchStations: Device currently busy in executing another command.");
return false;
}
Log.d (TAG, "Basic search...");
/* Validate the arguments */
if ( (mode != FM_RX_SRCH_MODE_SEEK) &&
(mode != FM_RX_SRCH_MODE_SCAN))
{
Log.d (TAG, "Invalid search mode: " + mode );
bStatus = false;
}
if ( (dwellPeriod < FM_RX_DWELL_PERIOD_0S ) ||
(dwellPeriod > FM_RX_DWELL_PERIOD_7S))
{
Log.d (TAG, "Invalid dwelling time: " + dwellPeriod);
bStatus = false;
}
if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
(direction != FM_RX_SEARCHDIR_UP))
{
Log.d (TAG, "Invalid search direction: " + direction);
bStatus = false;
}
if (bStatus)
{
Log.d (TAG, "searchStations: mode " + mode + "direction: " + direction);
if (mode == FM_RX_SRCH_MODE_SEEK)
setSearchState(subSrchLevel_SeekInPrg);
else if (mode == FM_RX_SRCH_MODE_SCAN)
setSearchState(subSrchLevel_ScanInProg);
Log.v(TAG, "searchStations: CURRENT-STATE : FMRxOn ---> NEW-STATE : SearchInProg");
re = mControl.searchStations(sFd, mode, dwellPeriod, direction, 0, 0);
if (re != 0) {
Log.e(TAG, "search station failed");
if (getFMState() == FMState_Srch_InProg)
setSearchState(subSrchLevel_SrchComplete);
return false;
}
state = getFMState();
if (state == FMState_Turned_Off) {
Log.d(TAG, "searchStations: CURRENT-STATE : FMState_Off (unexpected)");
return false;
}
}
return bStatus;
}
/*==============================================================
FUNCTION: searchStations
==============================================================*/
/**
* Initiates RDS based seek and scan operations.
*
* <p>
* This command allows the client to issue seeks and scans similar
* to commands found in basic searchStations(mode, scanTime,
* direction). However, each command has an additional RDS/RBDS
* component which must be satisfied before a station is
* successfully tuned. Please see searchStations(mode,
* scanTime, direction) for an understanding of how seeks and
* scans work.
*
* <p>
* <ul>
* This API is used to search stations using RDS:
* <li> Invokes seek based on program type ({@link
* #FM_RX_SRCHRDS_MODE_SEEK_PTY})
* <li> Invokes scan based on program type with specified dwell period
* ({@link #FM_RX_SRCHRDS_MODE_SCAN_PTY})
* <li> Invokes seek based on program identification ({@link
* #FM_RX_SRCHRDS_MODE_SEEK_PI})
* <li> Invokes seek for alternate frequency ({@link
* #FM_RX_SRCHRDS_MODE_SEEK_AF})
* </ul>
*
* <p>
* Much like {@link #FM_RX_SRCH_MODE_SEEK} in searchStations,
* {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY} allows the client to
* seek to stations which are broadcasting RDS/RBDS groups
* with a particular Program Type that matches the supplied
* Program Type (PTY). The behavior and events generated for a
* {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY} are very similar to
* that of {@link #FM_RX_SRCH_MODE_SEEK}, however only
* stations meeting the set search signal threshold and are
* also broadcasting the specified RDS Program Type (PTY) will
* be tuned. If no matching stations can be found, the
* original station will be re-tuned.
*
* <p>
* Just as {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}'s
* functionality matches {@link #FM_RX_SRCH_MODE_SEEK}, so
* does {@link #FM_RX_SRCHRDS_MODE_SCAN_PTY} match {@link
* #FM_RX_SRCH_MODE_SCAN}. The one of the differences between
* the two is that only stations meeting the set search
* threshold and are also broadcasting a RDS Program Type
* (PTY) matching tucRdsSrchPty are found and tuned. If no
* station is found to have the PTY as specified by argument
* "pty", then the original station will be re-tuned.
*
* <p> {@link #FM_RX_SRCHRDS_MODE_SEEK_PI} is used the same
* way as {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}, but only
* stations which meet the set search threshold and are also
* broadcasting the Program Identification matching the
* argument "pi" are tuned.
*
* <p>
* Lastly, {@link #FM_RX_SRCHRDS_MODE_SEEK_AF} functionality
* differs slightly compared to the other commands in this
* function. This command only seeks to stations which are
* known ahead of time to be Alternative Frequencies for the
* currently tune station. If no alternate frequencies are
* known, or if the Alternative Frequencies have weaker signal
* strength than the original frequency, the original
* frequency will be re-tuned.
*
* <p>
* Each time the driver initiates an RDS-based search, the client will be
* notified via a FmRxEvSearchInProgress event. Similarly, each
* time an RDS-based search completes, the client will be notified via a
* FmRxEvSearchComplete event.
*
* <p>
* Once issuing a search command, several commands from the client may be
* disallowed until the search is completed or canceled.
*
* <p>
* The search can be canceled at any time by using API
* cancelSearch (). Once canceled, each search will tune to the
* last tuned station and generate both
* FmRxEvSearchComplete and FmRxEvRadioTuneStatus events.
*
* Valid Values for argument 'mode':
* <ul>
* <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}
* <li>{@link #FM_RX_SRCHRDS_MODE_SCAN_PTY}
* <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_PI}
* <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_AF}
* </ul>
* <p>
* Valid Values for argument 'dwellPeriod' :
* <ul>
* <li>{@link #FM_RX_DWELL_PERIOD_1S}
* <li>{@link #FM_RX_DWELL_PERIOD_2S}
* <li>{@link #FM_RX_DWELL_PERIOD_3S}
* <li>{@link #FM_RX_DWELL_PERIOD_4S}
* <li>{@link #FM_RX_DWELL_PERIOD_5S}
* <li>{@link #FM_RX_DWELL_PERIOD_6S}
* <li>{@link #FM_RX_DWELL_PERIOD_7S}
* </ul>
* <p>
* Valid Values for argument 'direction' :
* <ul>
* <li>{@link #FM_RX_SEARCHDIR_DOWN}
* <li>{@link #FM_RX_SEARCHDIR_UP}
* </ul>
* <p>
* @param mode the FM search mode.
* @param dwellPeriod the FM scan dwell time. Used only when
* mode={@link #FM_RX_SRCHRDS_MODE_SCAN_PTY}
* @param direction the Search Direction.
* @param pty the FM RDS search Program Type
* @param pi the FM RDS search Program Identification Code
* <p>
* @return true if Search Initiate succeeded, false if
* Search Initiate failed.
*
* @see #searchStations(int, int, int)
* @see #searchStationList
*/
public boolean searchStations (int mode,
int dwellPeriod,
int direction,
int pty,
int pi) {
boolean bStatus = true;
int state = getFMState();
int re;
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "searchStations: Device currently busy in executing another command.");
return false;
}
Log.d (TAG, "RDS search...");
/* Validate the arguments */
if ( (mode != FM_RX_SRCHRDS_MODE_SEEK_PTY)
&& (mode != FM_RX_SRCHRDS_MODE_SCAN_PTY)
&& (mode != FM_RX_SRCHRDS_MODE_SEEK_PI)
&& (mode != FM_RX_SRCHRDS_MODE_SEEK_AF)
)
{
Log.d (TAG, "Invalid search mode: " + mode );
bStatus = false;
}
if ( (dwellPeriod < FM_RX_DWELL_PERIOD_1S) ||
(dwellPeriod > FM_RX_DWELL_PERIOD_7S))
{
Log.d (TAG, "Invalid dwelling time: " + dwellPeriod);
bStatus = false;
}
if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
(direction != FM_RX_SEARCHDIR_UP))
{
Log.d (TAG, "Invalid search direction: " + direction);
bStatus = false;
}
if (bStatus)
{
Log.d (TAG, "searchStations: mode " + mode);
Log.d (TAG, "searchStations: dwellPeriod " + dwellPeriod);
Log.d (TAG, "searchStations: direction " + direction);
Log.d (TAG, "searchStations: pty " + pty);
Log.d (TAG, "searchStations: pi " + pi);
setSearchState(subSrchLevel_ScanInProg);
re = mControl.searchStations(sFd, mode, dwellPeriod, direction, pty, pi);
if (re != 0) {
Log.e(TAG, "scan station failed");
if (getFMState() == FMState_Srch_InProg)
setSearchState(subSrchLevel_SrchComplete);
bStatus = false;
}
}
return bStatus;
}
/*==============================================================
FUNCTION: searchStationList
==============================================================*/
/** Initiates station list search operations.
* <p> This method will initate a search that will generate
* frequency lists based on strong and weak stations found in
* the FM band.
* <p>
* <ul>
* This API is used to generate station lists which consist of:
* <li>strong stations (FM_RX_SRCHLIST_MODE_STRONG,FM_RX_SRCHLIST_MODE_STRONGEST)
* <li>weak stations (FM_RX_SRCHLIST_MODE_WEAK, FM_RX_SRCHLIST_MODE_WEAKEST)
* </ul>
* <p>
* The range of frequencies scanned depends on the currently set band.
* The driver searches for all valid stations in the band and when complete,
* returns a channel list based on the client's selection. The client can
* choose to search for a list of the strongest stations in the band, the
* weakest stations in the band, or the first N strong or weak
* stations. By setting the maximumStations argument, the
* client can constrain the number of frequencies returned in
* the list. If user specifies argument maximumStations to be
* 0, the search will generate the maximum number of stations
* possible.
* <p>
* Each time the driver initiates a list-based search, the client will be
* notified via an FmRxEvSearchInProgress event. Similarly, each
* time a list-based search completes, the client will be
* notified via an FmRxEvSearchListComplete event.
* <p>
* On completion of the search, the originally tuned station
* will be tuned and the following events will be generated:
* FmRxEvSearchListComplete - The search has completed.
* FmRxEvRadioTuneStatus - The original frequency has been
* re-tuned.
* <p>
* Once issuing a search command, several commands from the client may be
* disallowed until the search is completed or cancelled.
* <p>
* The search can be canceled at any time by using API
* cancelSearch (). A cancelled search is treated as a completed
* search and the following events will be generated:
* FmRxEvSearchComplete - The search has completed.
* FmRxEvRadioTuneStatus - The original frequency has been re-tuned.
* <p>
* Valid Values for argument 'mode':
* <ul>
* <li>{@link #FM_RX_SRCHLIST_MODE_STRONG}
* <li>{@link #FM_RX_SRCHLIST_MODE_WEAK}
* <li>{@link #FM_RX_SRCHLIST_MODE_STRONGEST}
* <li>{@link #FM_RX_SRCHLIST_MODE_WEAKEST}
* <li>FM_RX_SRCHLIST_MODE_PTY (Will be implemented in the
* future)
* </ul>
* <p>
* Valid Values for argument 'direction' :
* <ul>
* <li>{@link #FM_RX_SEARCHDIR_DOWN}
* <li>{@link #FM_RX_SEARCHDIR_UP}
* </ul>
* <p>
* Valid Values for argument 'maximumStations' : 1-12
* <p>
* @param mode the FM search mode.
* @param direction the Search Direction.
* @param maximumStations the maximum number of stations that
* can be returned from a search. This parameter is
* ignored and 12 stations are returned if the
* search mode is either FM_RX_SRCHLIST_MODE_STRONGEST or
* FM_RX_SRCHLIST_MODE_WEAKEST
*
* @param pty the FM RDS search Program Type (Not used
* currently)
* <p>
* @return true if Search Initiate succeeded, false if
* Search Initiate failed.
*
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int, int, int)
*/
public boolean searchStationList (int mode,
int direction,
int maximumStations,
int pty){
int state = getFMState();
boolean bStatus = true;
int re = 0;
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "searchStationList: Device currently busy in executing another command.");
return false;
}
Log.d (TAG, "searchStations: mode " + mode);
Log.d (TAG, "searchStations: direction " + direction);
Log.d (TAG, "searchStations: maximumStations " + maximumStations);
Log.d (TAG, "searchStations: pty " + pty);
/* Validate the arguments */
if ( (mode != FM_RX_SRCHLIST_MODE_STRONG)
&& (mode != FM_RX_SRCHLIST_MODE_WEAK )
&& (mode != FM_RX_SRCHLIST_MODE_STRONGEST )
&& (mode != FM_RX_SRCHLIST_MODE_WEAKEST )
)
{
bStatus = false;
}
if ( (maximumStations < 0) ||
(maximumStations > FM_RX_SRCHLIST_MAX_STATIONS))
{
bStatus = false;
}
if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
(direction != FM_RX_SEARCHDIR_UP))
{
bStatus = false;
}
if (bStatus)
{
setSearchState(subSrchLevel_SrchListInProg);
Log.v(TAG, "searchStationList: CURRENT-STATE : FMRxOn ---> NEW-STATE : SearchInProg");
if ((mode == FM_RX_SRCHLIST_MODE_STRONGEST) || (mode == FM_RX_SRCHLIST_MODE_WEAKEST)) {
mode = (mode == FM_RX_SRCHLIST_MODE_STRONGEST)?
FM_RX_SRCHLIST_MODE_STRONG: FM_RX_SRCHLIST_MODE_WEAK;
re = mControl.searchStationList(sFd, mode, 0, direction, pty);
}
else
re = mControl.searchStationList(sFd, mode, maximumStations, direction, pty);
if (re != 0) {
Log.e(TAG, "search station list failed");
if (getFMState() == FMState_Srch_InProg)
setSearchState(subSrchLevel_SrchComplete);
bStatus = false;
}
}
return bStatus;
}
/*==============================================================
FUNCTION: cancelSearch
==============================================================*/
/**
* Cancels an ongoing search operation
* (seek, scan, searchlist, etc).
* <p>
* This method should be used to cancel a previously initiated
* search (e.g. Basic Seek/Scan, RDS Seek/Scans, Search list,
* etc...).
* <p>
* Once completed, this command will generate an
* FmRxEvSearchCancelledtr event to all registered clients.
* Following this event, the client may also receive search events related
* to the ongoing search now being complete.
*
* <p>
* @return true if Cancel Search initiate succeeded, false if
* Cancel Search initiate failed.
* @see #searchStations(int, int, int)
* @see #searchStations(int, int, int)
* @see #searchStationList
*/
public boolean cancelSearch () {
boolean status = false;
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Srch_InProg) {
Log.v(TAG, "cancelSearch: Cancelling the on going search operation");
setSearchState(subSrchLevel_SrchAbort);
mControl.cancelSearch(sFd);
return true;
} else
Log.d(TAG, "cancelSearch: No on going search operation to cancel");
return status;
}
/*==============================================================
FUNCTION: setMuteMode
==============================================================*/
/**
* Allows the muting and un-muting of the audio coming
* from the FM receiver.
* <p>
* This is a synchronous command used to mute or un-mute the
* FM audio. This command mutes the audio coming from the FM
* device. It is important to note that this only affects the
* FM audio and not any other audio system being used.
* <p>
* @param mode the mute Mode setting to apply
* <p>
* @return true if setMuteMode call was placed successfully,
* false if setMuteMode failed.
*
* @see #enable
* @see #registerClient
*
*/
public boolean setMuteMode (int mode) {
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "setMuteMode: Device currently busy in executing another command.");
return false;
}
switch (mode)
{
case FM_RX_UNMUTE:
mControl.muteControl(sFd, false);
break;
case FM_RX_MUTE:
mControl.muteControl(sFd, true);
break;
default:
break;
}
return true;
}
/*==============================================================
FUNCTION: setStereoMode
==============================================================*/
/**
* Sets the mono/stereo mode of the FM device.
*
* <p>
* This command allows the user to set the mono/stereo mode
* of the FM device. Using this function,
* the user can allow mono/stereo mixing or force the reception
* of mono audio only.
*
* @param stereoEnable true: Enable Stereo, false: Force Mono
*
* @return true if setStereoMode call was placed successfully,
* false if setStereoMode failed.
*/
public boolean setStereoMode (boolean stereoEnable) {
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg
|| state == subPwrLevel_FMTurning_Off) {
Log.d(TAG, "setStereoMode: Device currently busy in executing another command.");
return false;
}
int re = mControl.stereoControl(sFd, stereoEnable);
if (re == 0)
return true;
return false;
}
/*==============================================================
FUNCTION: setSignalThreshold
==============================================================*/
/**
* This function sets the threshold which the FM driver
* uses to determine which stations have service available.
*
* <p>
* This information is used to determine which stations are
* tuned during searches and Alternative Frequency jumps, as
* well as at what threshold FmRxEvServiceAvailable event
* callback are generated.
* <p>
* This is a command used to set the threshold used by the FM driver
* and/or hardware to determine which stations are "good" stations.
* Using this function, the client can allow very weak stations,
* relatively weak stations, relatively strong stations, or very.
* strong stations to be found during searches. Additionally,
* this threshold will be used to determine at what threshold a
* FmRxEvServiceAvailable event callback is generated.
* <p>
* @param threshold the new signal threshold.
* @return true if setSignalThreshold call was placed
* successfully, false if setSignalThreshold failed.
*/
public boolean setSignalThreshold (int threshold) {
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "setSignalThreshold: Device currently busy in executing another command.");
return false;
}
boolean bStatus = true;
int re;
Log.d(TAG, "Signal Threshhold input: "+threshold );
int rssiLev = 0;
switch(threshold)
{
case FM_RX_SIGNAL_STRENGTH_VERY_WEAK:
rssiLev = FM_RX_RSSI_LEVEL_VERY_WEAK;
break;
case FM_RX_SIGNAL_STRENGTH_WEAK:
rssiLev = FM_RX_RSSI_LEVEL_WEAK;
break;
case FM_RX_SIGNAL_STRENGTH_STRONG:
rssiLev = FM_RX_RSSI_LEVEL_STRONG;
break;
case FM_RX_SIGNAL_STRENGTH_VERY_STRONG:
rssiLev = FM_RX_RSSI_LEVEL_VERY_STRONG;
break;
default:
/* Should never reach here */
bStatus = false;
Log.d (TAG, "Invalid threshold: " + threshold );
return bStatus;
}
if (bStatus) {
re=FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH, rssiLev);
if (re !=0)
bStatus = false;
}
return bStatus;
}
/*==============================================================
FUNCTION: getStationParameters
==============================================================*
/**
* Returns various Paramaters related to the currently
* tuned station.
*
* <p>
* This is method retreives various parameters and statistics
* related to the currently tuned station. Included in these
* statistics are the currently tuned frequency, the RDS/RBDS
* sync status, the RSSI level, current mute settings and the
* stereo/mono status.
*
* <p>
* Once completed, this command will generate an asynchronous
* FmRxEvStationParameters event to the registered client.
* This event will contain the station parameters.
*
* <p>
* @return FmStationParameters: Object that contains
* all the station parameters
public FmStationParameters getStationParameters () {
return mStationParameters;
}
*/
/*==============================================================
FUNCTION: getTunedFrequency
==============================================================*/
/**
* Get the Frequency of the Tuned Station
*
* @return frequencyKHz: Tuned Station Frequency (in kHz)
* (Example: 96500 = 96.5Mhz)
* ERROR : If device is currently executing another command
*/
public int getTunedFrequency () {
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "getTunedFrequency: Device currently busy in executing another command.");
return ERROR;
}
int frequency = FmReceiverJNI.getFreqNative(sFd);
Log.d(TAG, "getFrequency: "+frequency);
return frequency;
}
/*==============================================================
FUNCTION: getPSInfo
==============================================================*/
/**
* Returns the current RDS/RBDS Program Service
* Information.
* <p>
* This is a command which returns the last complete RDS/RBDS
* Program Service information for the currently tuned station.
* To use this command, the client must first register for
* Program Service info by receiving either the
* FM_RX_RDS_GRP_PS_EBL or FM_RX_RDS_GRP_PS_SIMPLE_EBL event.
* Under normal operating mode, this information will
* automatically be sent to the client. However, if the client
* requires this information be sent again, this function can be
* used.
*
* Typicaly this method needs to be called when "FmRxEvRdsPsInfo"
* callback is invoked.
*
* <p>
* @return the RDS data including the Program Service
* Information
*
*/
public FmRxRdsData getPSInfo() {
byte [] buff = new byte[STD_BUF_SIZE];
int piLower = 0;
int piHigher = 0;
if(isCherokeeChip()) {
buff = FmReceiverJNI.getPsBuffer(buff);
}
else
FmReceiverJNI.getBufferNative(sFd, buff, 3);
/* byte is signed ;(
* knock down signed bits
*/
piLower = buff[3] & 0xFF;
piHigher = buff[2] & 0xFF;
int pi = ((piHigher << 8) | piLower);
Log.d (TAG, "PI= " + pi);
mRdsData.setPrgmId (pi);
mRdsData.setPrgmType ( (int)( buff[1] & 0x1F));
int numOfPs = (int)(buff[0] & 0x0F);
Log.d (TAG, "numofpsI= " + numOfPs);
try
{
String rdsStr = new String(buff, 5, numOfPs*8 );
mRdsData.setPrgmServices (rdsStr);
} catch (StringIndexOutOfBoundsException x)
{
Log.d (TAG, "Number of PS names " + numOfPs);
}
return mRdsData;
}
/*==============================================================
FUNCTION: getRTInfo
==============================================================*/
/**
* Returns the current RDS/RBDS RadioText Information.
*
* <p>
* This is a command which returns the last complete RadioText information
* for the currently tuned station. For this command to return meaningful
* information, the client must first register for RadioText events by registerring
* the FM_RX_RDS_GRP_RT_EBL callback function. Under normal operating mode, this information
* will automatically be sent to the client. However, if the client requires
* this information be sent again, this function can be used.
*
* <p>
* Typicaly this method needs to be called when
* "FmRxEvRdsRtInfo" callback is invoked.
*
* <p>
* @return the RDS data including the Radio Text Information
*/
public FmRxRdsData getRTInfo () {
byte [] buff = new byte[STD_BUF_SIZE];
int piLower = 0;
int piHigher = 0;
if (isCherokeeChip()) {
buff = FmReceiverJNI.getPsBuffer(buff);
}
else {
FmReceiverJNI.getBufferNative(sFd, buff, 2);
}
String rdsStr = new String(buff);
/* byte is signed ;(
* knock down signed bit
*/
piLower = buff[3] & 0xFF;
piHigher = buff[2] & 0xFF;
int pi = ((piHigher << 8) | piLower);
mRdsData.setPrgmId (pi);
mRdsData.setPrgmType ( (int)( buff[1] & 0x1F));
try
{
rdsStr = rdsStr.substring(5, (int) buff[0]+ 5);
mRdsData.setRadioText (rdsStr);
} catch (StringIndexOutOfBoundsException x)
{
Log.d (TAG, "StringIndexOutOfBoundsException ...");
}
return mRdsData;
}
public FmRxRdsData getRTPlusInfo() {
byte []rt_plus = new byte[STD_BUF_SIZE];
int bytes_read;
String rt = "";
int rt_len;
int i, count, avail_tag_num = 0;
byte tag_code, tag_len, tag_start_pos;
if (isCherokeeChip()) {
rt_plus = FmReceiverJNI.getPsBuffer(rt_plus);
}
else
{
bytes_read = FmReceiverJNI.getBufferNative(sFd, rt_plus, BUF_RTPLUS);
}
bytes_read = rt_plus[0];
if (bytes_read > 0) {
if (rt_plus[RT_OR_ERT_IND] == 0)
rt = mRdsData.getRadioText();
else
rt = mRdsData.getERadioText();
if ((rt != "") && (rt != null)) {
rt_len = rt.length();
mRdsData.setTagNums(0);
avail_tag_num = (rt_plus[LEN_IND] - 2)/3;
if (avail_tag_num > 2) {
avail_tag_num = 2;
}
count = 1;
for (i = 0; i < avail_tag_num; i++) {
tag_code = rt_plus[2+3*i];
tag_start_pos = rt_plus[3+3*i];
tag_len = rt_plus[4+3*i];
if (((tag_len + tag_start_pos) <= rt_len) && (tag_code > 0)) {
mRdsData.setTagValue(rt.substring(tag_start_pos,
(tag_len + tag_start_pos)), count);
mRdsData.setTagCode(tag_code, count);
count++;
}
}
} else {
mRdsData.setTagNums(0);
}
} else {
mRdsData.setTagNums(0);
}
return mRdsData;
}
public FmRxRdsData getERTInfo() {
byte [] raw_ert = new byte[STD_BUF_SIZE];
byte [] ert_text;
int i;
String s = "";
String encoding_type = "UCS-2";
int bytes_read;
if(isCherokeeChip())
{
raw_ert = FmReceiverJNI.getPsBuffer(raw_ert);
}
else
{
bytes_read = FmReceiverJNI.getBufferNative(sFd, raw_ert, BUF_ERT);
}
bytes_read = raw_ert[0];
if (bytes_read > 0) {
ert_text = new byte[raw_ert[LEN_IND]];
for(i = 3; (i - 3) < raw_ert[LEN_IND]; i++) {
ert_text[i - 3] = raw_ert[i];
}
if (raw_ert[ENCODE_TYPE_IND] == 1)
encoding_type = "UTF-8";
try {
s = new String (ert_text, encoding_type);
} catch (Exception e) {
e.printStackTrace();
}
mRdsData.setERadioText(s);
if (raw_ert[ERT_DIR_IND] == 0)
mRdsData.setFormatDir(false);
else
mRdsData.setFormatDir(true);
Log.d(TAG, "eRT: " + s + "dir: " +raw_ert[ERT_DIR_IND]);
}
return mRdsData;
}
public FmRxRdsData getECCInfo() {
byte [] raw_ecc = new byte[STD_BUF_SIZE];
int ecc_code =0;
int bytes_read;
raw_ecc = FmReceiverJNI.getPsBuffer(raw_ecc);
bytes_read = raw_ecc[0];
Log.d (TAG, "bytes_read = " + bytes_read);
if (bytes_read > 0) {
ecc_code = raw_ecc[9] & 0xFF;
mRdsData.setECountryCode(ecc_code);
Log.d(TAG, "ECC code: " + ecc_code );
}
return mRdsData;
}
/*==============================================================
FUNCTION: getAFInfo
==============================================================*/
/**
* Returns the current RDS/RBDS Alternative Frequency
* Information.
*
* <p>
* This is a command which returns the last known Alternative Frequency
* information for the currently tuned station. For this command to return
* meaningful information, the client must first register for Alternative
* Frequency events by registering an FM_RX_RDS_GRP_AF_EBL call back function.
* Under normal operating mode, this information will automatically be
* sent to the client. However, if the client requires this information
* be sent again, this function can be used.
*
* <p>
* Typicaly this method needs to be called when
* "FmRxEvRdsAfInfo" callback is invoked.
*
* @return the RDS data including the AF Information
*/
public int[] getAFInfo() {
byte [] buff = new byte[STD_BUF_SIZE];
int [] AfList = new int [50];
int lowerBand, i;
int tunedFreq, PI, size_AFLIST;
if (isCherokeeChip()) {
buff = FmReceiverJNI.getPsBuffer(buff);
}
else
{
FmReceiverJNI.getBufferNative(sFd, buff, TAVARUA_BUF_AF_LIST);
}
if (isSmdTransportLayer() || isRomeChip() || isCherokeeChip()) {
Log.d(TAG, "SMD transport layer or Rome chip");
tunedFreq = (buff[0] & 0xFF) |
((buff[1] & 0xFF) << 8) |
((buff[2] & 0xFF) << 16) |
((buff[3] & 0xFF) << 24) ;
Log.d(TAG, "tunedFreq = " +tunedFreq);
PI = (buff[4] & 0xFF) |
((buff[5] & 0xFF) << 8);
Log.d(TAG, "PI: " + PI);
size_AFLIST = buff[6] & 0xFF;
Log.d(TAG, "size_AFLIST : " +size_AFLIST);
for (i = 0;i < size_AFLIST;i++) {
AfList[i] = (buff[6 + i * 4 + 1] & 0xFF) |
((buff[6 + i * 4 + 2] & 0xFF) << 8) |
((buff[6 + i * 4 + 3] & 0xFF) << 16) |
((buff[6 + i * 4 + 4] & 0xFF) << 24) ;
Log.d(TAG, "AF: " + AfList[i]);
}
} else {
if ((buff[4] <= 0) || (buff[4] > 25))
return null;
lowerBand = FmReceiverJNI.getLowerBandNative(sFd);
Log.d (TAG, "Low band " + lowerBand);
Log.d (TAG, "AF_buff 0: " + (buff[0] & 0xff));
Log.d (TAG, "AF_buff 1: " + (buff[1] & 0xff));
Log.d (TAG, "AF_buff 2: " + (buff[2] & 0xff));
Log.d (TAG, "AF_buff 3: " + (buff[3] & 0xff));
Log.d (TAG, "AF_buff 4: " + (buff[4] & 0xff));
for (i=0; i<buff[4]; i++) {
AfList[i] = ((buff[i+4] & 0xFF) * 1000) + lowerBand;
Log.d (TAG, "AF : " + AfList[i]);
}
}
return AfList;
}
/*==============================================================
FUNCTION: setPowerMode
==============================================================*/
/**
* Puts the driver into or out of low power mode.
*
* <p>
* This is an synchronous command which can put the FM
* device and driver into and out of low power mode. Low power mode
* should be used when the receiver is tuned to a station and only
* the FM audio is required. The typical scenario for low power mode
* is when the FM application is no longer visible.
*
* <p>
* While in low power mode, all normal FM and RDS indications from
* the FM driver will be suppressed. By disabling these indications,
* low power mode can result in fewer interruptions and this may lead
* to a power savings.
*
* <p>
* @param powerMode the new driver operating mode.
*
* @return true if setPowerMode succeeded, false if
* setPowerMode failed.
*/
public boolean setPowerMode(int powerMode){
int re;
if (powerMode == FM_RX_LOW_POWER_MODE) {
re = mControl.setLowPwrMode (sFd, true);
}
else {
re = mControl.setLowPwrMode (sFd, false);
}
if (re == 0)
return true;
return false;
}
/*==============================================================
FUNCTION: getPowerMode
==============================================================*/
/**
* Get FM device low power mode.
* <p>
* This is an synchronous method that will read the power mode
* of the FM device and driver.
* <p>
* @return true if the FM Device is in Low power mode and
* false if the FM Device in Normal power mode.
*
* @see #setPowerMode
*/
public int getPowerMode(){
return mControl.getPwrMode (sFd);
}
/*==============================================================
FUNCTION: getRssiLimit
==============================================================*/
/**
* Returns the RSSI thresholds for the FM driver.
*
* <p>
* This method returns the RSSI thresholds for the FM driver.
* This function returns a structure containing the minimum RSSI needed
* for reception and the minimum RSSI value where reception is perfect.
* The minimum RSSI value for reception is the recommended threshold where
* an average user would consider the station listenable. Similarly,
* the minimum RSSI threshold for perfect reception is the point where
* reception quality will improve only marginally even if the RSSI level
* improves greatly.
*
* <p>
* These settings should only be used as a guide for describing
* the RSSI values returned by the FM driver. Used in conjunction
* with getRssiInfo, the client can use the values from this
* function to give meaning to the RSSI levels returned by the driver.
*
* <p>
* @return the RSSI level
*/
public int[] getRssiLimit () {
int[] rssiLimits = {0, 100};
return rssiLimits;
}
/*==============================================================
FUNCTION: getSignalThreshold
==============================================================*/
/**
* This function returns:
* currently set signal threshold - if API invocation
* is successful
* ERROR - if device is currently
* executing another command
* <p>
* This value used by the FM driver/hardware to determine which
* stations are tuned during searches and Alternative Frequency jumps.
* Additionally, this level is used to determine at what
* threshold FmRxEvServiceAvailable are generated.
*
* <p>
* This is a command used to return the currently set signal
* threshold used by the FM driver and/or hardware. This
* value is used to determine. which stations are tuned
* during searches and Alternative Frequency jumps as well as
* when Service available events are generated.
*
* <p>
* Once completed, this command will generate an asynchronous
* FmRxEvGetSignalThreshold event to the registered client.
* This event will contain the current signal threshold
* level.
*
* <p>
* @return the signal threshold
*/
public int getSignalThreshold () {
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "getSignalThreshold: Device currently busy in executing another command.");
return ERROR;
}
int threshold = FM_RX_SIGNAL_STRENGTH_VERY_WEAK, signalStrength;
int rmssiThreshold = FmReceiverJNI.getControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH);
Log.d(TAG, "Signal Threshhold: "+rmssiThreshold );
if ( (FM_RX_RSSI_LEVEL_VERY_WEAK < rmssiThreshold) && (rmssiThreshold <= FM_RX_RSSI_LEVEL_WEAK) )
{
signalStrength = FM_RX_RSSI_LEVEL_WEAK;
}
else if ( (FM_RX_RSSI_LEVEL_WEAK < rmssiThreshold) && (rmssiThreshold <= FM_RX_RSSI_LEVEL_STRONG))
{
signalStrength = FM_RX_RSSI_LEVEL_STRONG;
}
else if ((FM_RX_RSSI_LEVEL_STRONG < rmssiThreshold))
{
signalStrength = FM_RX_RSSI_LEVEL_VERY_STRONG;
}
else
{
signalStrength = FM_RX_RSSI_LEVEL_VERY_WEAK;
}
switch(signalStrength)
{
case FM_RX_RSSI_LEVEL_VERY_WEAK:
threshold = FM_RX_SIGNAL_STRENGTH_VERY_WEAK;
break;
case FM_RX_RSSI_LEVEL_WEAK:
threshold = FM_RX_SIGNAL_STRENGTH_WEAK;
break;
case FM_RX_RSSI_LEVEL_STRONG:
threshold = FM_RX_SIGNAL_STRENGTH_STRONG;
break;
case FM_RX_RSSI_LEVEL_VERY_STRONG:
threshold = FM_RX_SIGNAL_STRENGTH_VERY_STRONG;
break;
default:
/* Should never reach here */
break;
}
return threshold;
}
public int getAFJumpRmssiTh() {
int state = getFMState();
/* Check current state of FM device */
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getAFJumpThreshold: Device currently busy in executing another command.");
return ERROR;
}
return mControl.getAFJumpRmssiTh(sFd);
}
public boolean setAFJumpRmssiTh(int th) {
int state = getFMState();
/* Check current state of FM device */
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setAFJumpThreshold: Device currently busy in executing another command.");
return false;
}
return mControl.setAFJumpRmssiTh(sFd, th);
}
public int getAFJumpRmssiSamples() {
int state = getFMState();
/* Check current state of FM device */
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getAFJumpRmssiSamples: Device currently busy in executing another command.");
return ERROR;
}
return mControl.getAFJumpRmssiSamples(sFd);
}
public boolean setAFJumpRmssiSamples(int samples) {
int state = getFMState();
/* Check current state of FM device */
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setAFJumpRmssiSamples: Device currently busy in executing another command.");
return false;
}
return mControl.setAFJumpRmssiSamples(sFd, samples);
}
public int getGdChRmssiTh() {
int state = getFMState();
/* Check current state of FM device */
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getGdChRmssiTh: Device currently busy in executing another command.");
return ERROR;
}
return mControl.getGdChRmssiTh(sFd);
}
public boolean setGdChRmssiTh(int th) {
int state = getFMState();
/* Check current state of FM device */
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setGdChRmssiTh: Device currently busy in executing another command.");
return false;
}
return mControl.setGdChRmssiTh(sFd, th);
}
public int getSearchAlgoType() {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getSearchAlgoType: Device currently busy in executing another command.");
return Integer.MAX_VALUE;
}
return mControl.getSearchAlgoType(sFd);
}
public boolean setSearchAlgoType(int searchType) {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setSearchAlgoType: Device currently busy in executing another command.");
return false;
}
if((searchType != SEARCH_MPXDCC) && (searchType != SEARCH_SINR_INT)) {
Log.d(TAG, "Search Algo is invalid");
return false;
}else {
return mControl.setSearchAlgoType(sFd, searchType);
}
}
public int getSinrFirstStage() {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getSinrFirstStage: Device currently busy in executing another command.");
return Integer.MAX_VALUE;
}
return mControl.getSinrFirstStage(sFd);
}
public boolean setSinrFirstStage(int sinr) {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setSinrFirstStage: Device currently busy in executing another command.");
return false;
}
return mControl.setSinrFirstStage(sFd, sinr);
}
public int getRmssiFirstStage() {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getRmssiFirstStage: Device currently busy in executing another command.");
return Integer.MAX_VALUE;
}
return mControl.getRmssiFirstStage(sFd);
}
public boolean setRmssiFirstStage(int rmssi) {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setRmssiFirstStage: Device currently busy in executing another command.");
return false;
}
return mControl.setRmssiFirstStage(sFd, rmssi);
}
public int getCFOMeanTh() {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getCF0Th12: Device currently busy in executing another command.");
return Integer.MAX_VALUE;
}
return mControl.getCFOMeanTh(sFd);
}
public boolean setCFOMeanTh(int th) {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setRmssiFirstStage: Device currently busy in executing another command.");
return false;
}
return mControl.setCFOMeanTh(sFd, th);
}
public boolean setPSRxRepeatCount(int count) {
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off){
Log.d(TAG, "setRxRepeatcount failed");
return false;
}
return mControl.setPSRxRepeatCount(sFd, count);
}
public boolean getPSRxRepeatCount() {
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off){
Log.d(TAG, "setRxRepeatcount failed");
return false;
}
return mControl.getPSRxRepeatCount(sFd);
}
public byte getBlendSinr() {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getBlendSinr: Device currently busy in executing another command.");
return Byte.MAX_VALUE;
}
return mControl.getBlendSinr(sFd);
}
public boolean setBlendSinr(int sinrHi) {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setBlendSinr: Device currently busy in executing another command.");
return false;
}
return mControl.setBlendSinr(sFd, sinrHi);
}
public byte getBlendRmssi() {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "getBlendRmssi: Device currently busy in executing another command.");
return Byte.MAX_VALUE;
}
return mControl.getBlendRmssi(sFd);
}
public boolean setBlendRmssi(int rmssiHi) {
int state = getFMState();
if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) {
Log.d(TAG, "setBlendRmssi: Device currently busy in executing another command.");
return false;
}
return mControl.setBlendRmssi(sFd, rmssiHi);
}
/*==============================================================
FUNCTION: setRdsGroupOptions
==============================================================*/
/**
*
* This function enables or disables various RDS/RBDS
* group filtering and buffering features.
*
* <p>
* Included in these features are the RDS group enable mask, RDS/RBDS group
* change filter, and the RDS/RBDS group buffer size.
* <p>
* This is a function used to set or unset various Rx RDS/RBDS group filtering
* and buffering options in the FM driver.
* <p>
* Included in these options is the ability for the client to select
* which RDS/RBDS groups should be sent to the client. By default, all
* RDS/RBDS groups are filtered out before reaching the client. To allow one
* or more specific groups to be received, the client must set one or mors bits
* within the argument enRdsGrpsMask bitmask. Each bit in this
* mask corresponds to a specific RDS/RBDS group type. Once a
* group is enabled, and when a buffer holding those groups
* reaches the threshold defined by argument rdsBuffSize, the
* group or groups will be sent to the client as a
* FmRxEvRdsGroupData callback.
*
* <p>
* Additionally, this function also allows the client to enable or
* disable the RDS/RBDS group change filter. This filter allows the client
* to prevent duplicate groups of the same group type from being received.
* This filter only applies to consecutive groups, so
* identical groups received in different order will not be
* filtered out.
*
* <p>
* @param enRdsGrpsMask the bitMask that enables the RT/PS/AF.
*
* @param rdsBuffSize the number of RDS/RBDS groups the FM
* driver should buffer before sending to
* the client.
*
* @param enRdsChangeFilter the Flag used to determine whether
* the RDS/RBDS change filter
* should be enabled.
*
* @return true if the command was placed successfully, false
* if command failed.
*
*/
public boolean setRdsGroupOptions (int enRdsGrpsMask,
int rdsBuffSize,
boolean enRdsChangeFilter)
{
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "setRdsGroupOptions: Device currently busy in executing another command.");
return false;
}
// Enable RDS
int re = mRdsData.rdsOn(true);
if (re != 0)
return false;
re = mRdsData.rdsGrpOptions (enRdsGrpsMask, rdsBuffSize, enRdsChangeFilter);
if (re ==0)
return true;
return false;
}
public boolean setRawRdsGrpMask()
{
return super.setRDSGrpMask(GRP_3A);
}
/*==============================================================
FUNCTION: registerRdsGroupProcessing
==============================================================*/
/**
*
* This function enables or disables RDS/RBDS group processing features.
*
* <p>
* Included in these features is the ability for the FM driver
* to return Program Service, RadioText, and Alternative
* Frequency information.
*
* <p>
* These options free the client from the burden of collecting a continuous
* stream of RDS/RBDS groups and processing them. By setting the
* FM_RX_RDS_GRP_RT_EBL bit in argument fmGrpsToProc, the FM
* hardware or driver will collect RDS/RBDS 2A/2B groups and
* return complete RadioText strings and information in the
* form of a FmRxEvRdsRtInfo event. This event will be
* generated only when the RadioText information changes.
*
* <p>
* Similarly, by setting either the FM_RX_RDS_GRP_PS_EBL or
* FM_RX_RDS_GRP_PS_SIMPLE_EBL bit in argument fmGrpsToProc,
* the FM hardware or driver will collect RDS/RBDS 0A/0B
* groups and return Program Service information in the form
* of a FmRxEvRdsPsInfo event. This event will be generated
* whenever the Program Service information changes. This
* event will include one or more collected Program Service
* strings which can be continuously displayed by the client.
*
* <p>
* Additionally, by setting the FM_RX_RDS_GRP_AF_EBL bit in
* argument FmGrpsToProc, the FM hardware or driver will
* collect RDS/RBDS 0A/0B groups and return Alternative
* Frequency information in the form of a FmRxEvRdsAfInfo
* event. This event will be generated when the Alternative
* Frequency information changes and will include an up to
* date list of all known Alternative Frequencies.
*
* <p>
* Lastly, by setting the FM_RX_RDS_GRP_AF_JUMP_EBL bit in
* argument FmGrpsToProc, the FM hardware or driver will
* collect RDS/RBDS 0A/0B groups and automatically tune to a
* stronger alternative frequency when the signal level falls
* below the search threshold.
*
* @param fmGrpsToProc the bitMask that enables the RT/PS/AF.
*
* @return true if the command was placed successfully, false
* if command failed.
*
*/
public boolean registerRdsGroupProcessing (int fmGrpsToProc){
if (mRdsData == null)
return false;
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "registerRdsGroupProcessing: Device currently busy in executing another command.");
return false;
}
// Enable RDS
int re = mRdsData.rdsOn(true);
if (re != 0)
return false;
re = mRdsData.rdsOptions (fmGrpsToProc);
if (re ==0)
return true;
return false;
}
/*==============================================================
FUNCTION: enableAFjump
==============================================================*/
/**
* Enables automatic jump to alternative frequency
*
* <p>
* This method enables automatic seeking to stations which are
* known ahead of time to be Alternative Frequencies for the
* currently tuned station. If no alternate frequencies are
* known, or if the Alternative Frequencies have weaker signal
* strength than the original frequency, the original frequency
* will be re-tuned.
*
* <p>
* @return true if successful false otherwise.
*/
public boolean enableAFjump (boolean enable) {
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "enableAFjump: Device currently busy in executing another command.");
return false;
}
// Enable RDS
int re = mRdsData.rdsOn(true);
if (re != 0)
return false;
re = mRdsData.enableAFjump(enable);
if (re == 0)
return true;
return false;
}
/*==============================================================
FUNCTION: getStationList
==============================================================*/
/**
* Returns a frequency List of the searched stations.
*
* <p>
* This method retreives the results of the {@link
* #searchStationList}. This method should be called when the
* FmRxEvSearchListComplete is invoked.
*
* <p>
* @return An array of integers that corresponds to the
* frequency of the searched Stations
* @see #searchStationList
*/
public int[] getStationList ()
{
int state = getFMState();
/* Check current state of FM device */
if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
Log.d(TAG, "getStationList: Device currently busy in executing another command.");
return null;
}
int[] stnList = new int [100];
stnList = mControl.stationList (sFd);
return stnList;
}
/*==============================================================
FUNCTION: getRssi
==============================================================*/
/**
* Returns the signal strength of the currently tuned station
*
* <p>
* This method returns the signal strength of the currently
* tuned station.
*
* <p>
* @return RSSI of currently tuned station
*/
public int getRssi()
{
int rssi = FmReceiverJNI.getRSSINative (sFd);
return rssi;
}
/*==============================================================
FUNCTION: getIoverc
==============================================================*/
/**
* Returns the Estimated Interference Over Carrier of the currently tuned station
*
* <p>
* This method returns the Estimated Interference Over Carrier of the currently
* tuned station.
*
* <p>
* @return IOVERC of currently tuned station on Success.
* -1 on failure to retrieve the current IoverC.
*/
public int getIoverc()
{
int re;
re = mControl.IovercControl(sFd);
return re;
}
/*==============================================================
FUNCTION: getIntDet
==============================================================*/
/**
* Returns the IntDet the currently tuned station
*
* <p>
* This method returns the IntDet of the currently
* tuned station.
*
* <p>
* @return IntDet of currently tuned station.
* -1 on failure to retrieve the current IntDet
*/
public int getIntDet()
{
int re;
re = mControl.IntDet(sFd);
return re;
}
/*==============================================================
FUNCTION: getMpxDcc
==============================================================*/
/**
* Returns the MPX_DCC of the currently tuned station
*
* <p>
* This method returns the MPX_DCC of the currently
* tuned station.
*
* <p>
* @return MPX_DCC value of currently tuned station.
* -1 on failure to retrieve the current MPX_DCC
*/
public int getMpxDcc()
{
int re;
re = mControl.Mpx_Dcc(sFd);
return re;
}
/*==============================================================
FUNCTION: setHiLoInj
==============================================================*/
/**
* Sets the Hi-Lo injection
*
* <p>
* This method sets the hi-low injection.
*
* <p>
*/
public void setHiLoInj(int inj)
{
int re = mControl.setHiLoInj(sFd, inj);
}
/*==============================================================
FUNCTION: getRmssiDelta
==============================================================*/
/**
* Gets the value of currently set RMSSI Delta
*
* <p>
* This method gets the currently set RMSSI Delta value.
*
* <p>
*/
public int getRmssiDelta()
{
int re = mControl.getRmssiDelta(sFd);
Log.d (TAG, "The value of RMSSI Delta is " + re);
return re;
}
/*==============================================================
FUNCTION: setRmssiDel
==============================================================*/
/**
* Sets the RMSSI Delta
*
* <p>
* This method sets the RMSSI Delta.
*
* <p>
*/
public void setRmssiDel(int delta)
{
int re = mControl.setRmssiDel(sFd, delta);
}
/*==============================================================
FUNCTION: getRawRDS
==============================================================*/
/**
* Returns array of Raw RDS data
*
* <p>
* This is a non-blocking call and it returns raw RDS data.
* The data is packed in groups of three bytes. The lsb and
* msb bytes contain RDS block while the third byte contains
* Block description. This call is wrapper around V4L2 read
* system call. The FM driver collects RDS/RBDS groups to meet
* the threshold described by setRdsGroupOptions() method.
* The call returns when one or more groups have been enabled
* by setRdsGroupOptions() method.
*
* @param numBlocks Number of blocks of RDS data
*
* <p>
* @return byte[]
*/
public byte[] getRawRDS (int numBlocks)
{
byte[] rawRds = new byte [numBlocks*3];
int re;
re = FmReceiverJNI.getRawRdsNative (sFd, rawRds, numBlocks*3);
if (re == (numBlocks*3))
return rawRds;
if (re <= 0)
return null;
byte[] buff = new byte [re];
System.arraycopy (rawRds, 0, buff, 0 , re);
return buff;
}
/*
* getFMState() returns:
* '0' if FM State is OFF
* '1' if FM Rx is On
* '2' if FM Tx is On
* '3' if FM device is Searching
*/
public int getFMState()
{
/* Current State of FM device */
int currFMState = FmTransceiver.getFMPowerState();
return currFMState;
}
/*==============================================================
FUNCTION: setOnChannelThreshold
==============================================================*/
/**
* Sets the On channel threshold value
*
* <p>
* This method sets the On channel threshold value.
*
* <p>
*/
public boolean setOnChannelThreshold(int data)
{
int re = mControl.setOnChannelThreshold(sFd, data);
if (re < 0)
return false;
else
return true;
}
/*==============================================================
FUNCTION: getOnChannelThreshold
==============================================================*/
/**
* Gets the On channel threshold value
*
* <p>
* This method gets the currently set On channel threshold value.
*
* <p>
*/
public boolean getOnChannelThreshold()
{
int re = mControl.getOnChannelThreshold(sFd);
if (re != 0)
return false;
else
return true;
}
/*==============================================================
FUNCTION: setOffChannelThreshold
==============================================================*/
/**
* Sets the Off channel threshold value
*
* <p>
* This method sets the Off channel threshold value.
*
* <p>
*/
public boolean setOffChannelThreshold(int data)
{
int re = mControl.setOffChannelThreshold(sFd, data);
if (re < 0)
return false;
else
return true;
}
/*==============================================================
FUNCTION: getOffChannelThreshold
==============================================================*/
/**
* Gets the Off channel threshold value
*
* <p>
* This method gets the currently set Off channel threshold value.
*
* <p>
*/
public boolean getOffChannelThreshold()
{
int re = mControl.getOffChannelThreshold(sFd);
if (re != 0)
return false;
else
return true;
}
/*===============================================================
FUNCTION: getSINR
==============================================================*/
/**
* Gets the SINR value of currently tuned station
*
* <p>
* This method gets the SINR value for currently tuned station.
*
* <p>
*/
public int getSINR()
{
int re = mControl.getSINR(sFd);
Log.d (TAG, "The value of SINR is " + re);
return re;
}
/*==============================================================
FUNCTION: setSINRThreshold
==============================================================*/
/**
* Sets the SINR threshold value
*
* <p>
* This method sets the SINR threshold value.
*
* <p>
*/
public boolean setSINRThreshold(int data)
{
int re = mControl.setSINRThreshold(sFd, data);
if (re < 0)
return false;
else
return true;
}
/*==============================================================
FUNCTION: getSINRThreshold
==============================================================*/
/**
* Gets the SINR threshold value
*
* <p>
* This method gets the currently set SINR threshold value.
*
* <p>
*/
public int getSINRThreshold()
{
return mControl.getSINRThreshold(sFd);
}
/*==============================================================
FUNCTION: setRssiThreshold
==============================================================*/
/**
* Sets the RSSI threshold value
*
* <p>
* This method sets the RSSI threshold value.
*
* <p>
*/
public boolean setRssiThreshold(int data)
{
int re = mControl.setRssiThreshold(sFd, data);
if (re < 0)
return false;
else
return true;
}
/*==============================================================
FUNCTION: getRssiThreshold
==============================================================*/
/**
* Gets the Rssi threshold value
*
* <p>
* This method gets the currently set Rssi threshold value.
*
* <p>
*/
public int getRssiThreshold()
{
return mControl.getRssiThreshold(sFd);
}
/*==============================================================
FUNCTION: setAfJumpRssiThreshold
==============================================================*/
/**
* Sets the Af jump RSSI threshold value
*
* <p>
* This method sets the AF jump RSSI threshold value.
*
* <p>
*/
public boolean setAfJumpRssiThreshold(int data)
{
int re = mControl.setAfJumpRssiThreshold(sFd, data);
if (re < 0)
return false;
else
return true;
}
/*==============================================================
FUNCTION: getAfJumpRssiThreshold
==============================================================*/
/**
* Gets the Af jump RSSI threshold value
*
* <p>
* This method gets the currently set AF jump RSSI threshold value.
*
* <p>
*/
public int getAfJumpRssiThreshold()
{
return mControl.getAfJumpRssiThreshold(sFd);
}
/*==============================================================
FUNCTION: setRdsFifoCnt
==============================================================*/
/**
* Sets the RDS FIFO count value
*
* <p>
* This method sets the RDS FIFO count value.
*
* <p>
*/
public boolean setRdsFifoCnt(int data)
{
int re = mControl.setRdsFifoCnt(sFd, data);
if (re < 0)
return false;
else
return true;
}
/*==============================================================
FUNCTION: getRdsFifoCnt
==============================================================*/
/**
* Gets the RDS FIFO count value
*
* <p>
* This method gets the currently set RDS FIFO count value.
*
* <p>
*/
public int getRdsFifoCnt()
{
return mControl.getRdsFifoCnt(sFd);
}
/*==============================================================
FUNCTION: setSINRsamples
==============================================================*/
/**
* Sets the SINR samples
*
* <p>
* This method sets the number of SINR samples to calculate the SINR value.
*
* <p>
*/
public boolean setSINRsamples(int data)
{
int re = mControl.setSINRsamples(sFd, data);
if (re < 0)
return false;
else
return true;
}
/*==============================================================
FUNCTION: getSINRsamples
==============================================================*/
/**
* Gets the SINR samples value
*
* <p>
* This method gets the number of currently set SINR samples.
*
* <p>
*/
public int getSINRsamples()
{
return mControl.getSINRsamples(sFd);
}
public int updateSpurFreq(int freq, int rmssi, boolean enable)
{
return mControl.updateSpurTable(sFd, freq, rmssi, enable);
}
public int configureSpurTable()
{
return mControl.configureSpurTable(sFd);
}
public static int getSpurConfiguration(int freq)
{
int retval;
retval = FmReceiverJNI.setControlNative(sFd, V4L2_CID_PRIVATE_IRIS_GET_SPUR_TBL, freq);
if (retval !=0)
Log.d(TAG, "Failed/No Spurs for " +freq);
return retval;
}
public static void getSpurTableData()
{
int freq;
byte no_of_spurs;
int rotation_value;
byte lsbOfLen;
byte filterCoe;
byte isEnbale;
byte [] buff = new byte[STD_BUF_SIZE];
int i = 0;
FmReceiverJNI.getBufferNative(sFd, buff, 13);
freq = buff[0] & 0xFF;
freq |= ((buff[1] & 0xFF) << 8);
freq |= ((buff[2] & 0xFF) << 16);
Log.d (TAG, "freq = " +freq);
no_of_spurs = buff[3];
Log.d (TAG, "no_of_spurs = " + no_of_spurs);
for(i = 0; i < FmConfig.no_Of_Spurs_For_Entry; i++) {
rotation_value = buff[(i * 4) + 4] & 0xFF;
rotation_value |= ((buff[(i * 4) + 5] & 0xFF) << 8);
rotation_value |= ((buff[(i * 4) + 6] & 0x0F) << 12);
Log.d (TAG, "rotation_value = " +rotation_value);
lsbOfLen = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 4) & 0x01);
Log.d (TAG, "lsbOfLen = "+lsbOfLen);
filterCoe = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 5) & 0x03);
Log.d (TAG, "filterCoe = " +filterCoe);
isEnbale = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 7) & 0x01);
Log.d (TAG, "spur level: " +buff[(i * 4) + 7]);
}
return;
}
public void FMcontrolLowPassFilter(int state, int net_type, int enable) {
int RatConf = SystemProperties.getInt("persist.fm_wan.ratconf", 0);
Log.v (TAG, "FMcontrolLowPassFilter " + RatConf);
switch (net_type)
{
case TelephonyManager.NETWORK_TYPE_GPRS:
if ((mEnableLpfGprs & RatConf) == mEnableLpfGprs) {
Log.v (TAG, "set LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_EDGE:
if ((mEnableLpfEdge & RatConf) == mEnableLpfEdge) {
Log.v (TAG, "set LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_UMTS:
if ((mEnableLpfUmts & RatConf) == mEnableLpfUmts ) {
Log.v (TAG, "set LPF for net_type: " + Integer.toString(net_type));
Log.v (TAG, "enable:" + enable);
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_CDMA:
if ((mEnableLpfCdma & RatConf) == mEnableLpfCdma) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_EVDO_0:
if ((mEnableLpfEvdo0 & RatConf) == mEnableLpfEvdo0 ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_EVDO_A:
if ((mEnableLpfEvdoA & RatConf) == mEnableLpfEvdoA ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_1xRTT:
if ((mEnableLpf1xRtt & RatConf) == mEnableLpf1xRtt ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_HSDPA:
if ((mEnableLpfHsdpa & RatConf) == mEnableLpfHsdpa ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_HSUPA:
if ((mEnableLpfHsupa & RatConf) == mEnableLpfHsupa) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_HSPA:
if ((mEnableLpfHspa & RatConf) == mEnableLpfHspa ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_IDEN:
if ((mEnableLpfIden & RatConf) == mEnableLpfIden ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_EVDO_B:
if ((mEnableLpfEvdoB & RatConf) == mEnableLpfEvdoB ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_LTE:
if ((mEnableLpfLte & RatConf) == mEnableLpfLte ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_EHRPD:
if ((mEnableLpfEhrpd & RatConf) == mEnableLpfEhrpd ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_HSPAP:
if ((mEnableLpfHspap & RatConf) == mEnableLpfHspap ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_GSM:
if ((mEnableLpfGsm & RatConf) == mEnableLpfGsm ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
if ((mEnableLpfScdma & RatConf) == mEnableLpfScdma ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_IWLAN:
if ((mEnableLpfIwlan & RatConf) == mEnableLpfIwlan ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
case TelephonyManager.NETWORK_TYPE_LTE_CA:
if ((mEnableLpfLteCa & RatConf) == mEnableLpfLteCa ) {
Log.d (TAG, "enabling LPF for net_type: " + Integer.toString(net_type));
mControl.enableLPF(sFd, enable);
}
break;
default:
Log.d (TAG, "net_type " + Integer.toString(net_type) + " doesn't need LPF enabling");
break;
}
}
public void EnableSlimbus(int enable) {
Log.d(TAG, "EnableSlimbus :enable =" + enable);
mControl.enableSlimbus(sFd, enable);
}
public void EnableSoftMute(int enable) {
Log.d(TAG, "enableSoftMute :enable =" + enable);
mControl.enableSoftMute(sFd, enable);
}
}