diff options
author | Venkateshwarlu Domakonda <Venkateshwarlu@codeaurora.org> | 2013-03-25 16:53:03 +0530 |
---|---|---|
committer | Venkateshwarlu Domakonda <Venkateshwarlu@codeaurora.org> | 2013-03-25 19:07:22 +0530 |
commit | aa25363e9c44e916d469dcb21f43e826e660d8d9 (patch) | |
tree | f42b331d26567bede949430ee66ef2bc9c88bb97 /qcom | |
parent | 371d637753718494c6e4ae0bf72424d662766e77 (diff) | |
download | android_hardware_qcom_fm-aa25363e9c44e916d469dcb21f43e826e660d8d9.tar.gz android_hardware_qcom_fm-aa25363e9c44e916d469dcb21f43e826e660d8d9.tar.bz2 android_hardware_qcom_fm-aa25363e9c44e916d469dcb21f43e826e660d8d9.zip |
FM: Migrate FM Framework code base to new git
Change-Id: I4769b2381fc62d75e67c428071c320b8f63cce0e
Diffstat (limited to 'qcom')
-rw-r--r-- | qcom/fmradio/FmConfig.java | 180 | ||||
-rw-r--r-- | qcom/fmradio/FmReceiver.java | 2342 | ||||
-rw-r--r-- | qcom/fmradio/FmReceiverJNI.java | 285 | ||||
-rw-r--r-- | qcom/fmradio/FmRxControls.java | 550 | ||||
-rw-r--r-- | qcom/fmradio/FmRxEvCallbacks.java | 49 | ||||
-rw-r--r-- | qcom/fmradio/FmRxEvCallbacksAdaptor.java | 55 | ||||
-rw-r--r-- | qcom/fmradio/FmRxEventListner.java | 251 | ||||
-rw-r--r-- | qcom/fmradio/FmRxRdsData.java | 262 | ||||
-rw-r--r-- | qcom/fmradio/FmTransceiver.java | 644 | ||||
-rw-r--r-- | qcom/fmradio/FmTransmitter.java | 923 | ||||
-rw-r--r-- | qcom/fmradio/FmTransmitterCallbacks.java | 93 | ||||
-rw-r--r-- | qcom/fmradio/FmTransmitterCallbacksAdaptor.java | 45 | ||||
-rw-r--r-- | qcom/fmradio/FmTxEventListner.java | 141 |
13 files changed, 5820 insertions, 0 deletions
diff --git a/qcom/fmradio/FmConfig.java b/qcom/fmradio/FmConfig.java new file mode 100644 index 0000000..3044cc2 --- /dev/null +++ b/qcom/fmradio/FmConfig.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2009-2011, 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.util.Log; +import android.os.SystemProperties; + + +/** + * + * Class to be used when changing radio settings + * @hide + */ +public class FmConfig { + + /* V4l2 Controls */ + private static final int V4L2_CID_PRIVATE_BASE = 0x8000000; + private static final int V4L2_CID_PRIVATE_TAVARUA_REGION = V4L2_CID_PRIVATE_BASE + 7; + private static final int V4L2_CID_PRIVATE_TAVARUA_EMPHASIS = V4L2_CID_PRIVATE_BASE + 12; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDS_STD = V4L2_CID_PRIVATE_BASE + 13; + private static final int V4L2_CID_PRIVATE_TAVARUA_SPACING = V4L2_CID_PRIVATE_BASE + 14; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM = V4L2_CID_PRIVATE_BASE + 0x2B; + + private static final String TAG = "FmConfig"; + + + + private int mRadioBand; + /** + * FM pre-emphasis/de-emphasis + * + * Possible Values: + * + * FmTransceiver.FM_DE_EMP75, + * FmTransceiver.FM_DE_EMP50 + */ + private int mEmphasis; + /** + * Channel spacing + * + * Possible Values: + * + * FmTransceiver.FM_CHSPACE_200_KHZ, + * FmTransceiver.FM_CHSPACE_100_KHZ, + * FmTransceiver.FM_CHSPACE_50_KHZ + */ + private int mChSpacing; + /** + * RDS standard type + * + * Possible Values: + * + * FmTransceiver.FM_RDS_STD_RBDS, + * FmTransceiver.FM_RDS_STD_RDS, + * FmTransceiver.FM_RDS_STD_NONE + */ + private int mRdsStd; + + /** + * FM Frequency Band Lower Limit in KHz + */ + private int mBandLowerLimit; + /** + * FM Frequency Band Upper Limit in KHz + */ + private int mBandUpperLimit; + + public int getRadioBand(){ + return mRadioBand; + } + + public void setRadioBand (int band){ + mRadioBand = band; + } + + public int getEmphasis(){ + return mEmphasis; + } + + public void setEmphasis (int emp){ + mEmphasis = emp; + } + + public int getChSpacing (){ + return mChSpacing; + } + + public void setChSpacing(int spacing) { + mChSpacing = spacing; + } + + public int getRdsStd () { + return mRdsStd; + } + + public void setRdsStd (int rdsStandard) { + mRdsStd = rdsStandard; + } + + public int getLowerLimit(){ + return mBandLowerLimit; + } + + public void setLowerLimit(int lowLimit){ + mBandLowerLimit = lowLimit; + } + + public int getUpperLimit(){ + return mBandUpperLimit; + } + + public void setUpperLimit(int upLimit){ + mBandUpperLimit = upLimit; + } + + /* + * fmConfigure() + * This method call v4l2 private controls to set regional settings for the + * FM core + */ + protected static boolean fmConfigure (final int fd, final FmConfig configSettings) { + + int re; + + Log.v (TAG, "In fmConfigure"); + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_EMPHASIS, configSettings.getEmphasis()); + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_RDS_STD, configSettings.getRdsStd() ); + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SPACING, configSettings.getChSpacing() ); + + boolean fmSrchAlg = SystemProperties.getBoolean("persist.fm.new.srch.algorithm",false); + if (fmSrchAlg) { + Log.v (TAG, "fmConfigure() : FM Srch Alg : NEW "); + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, 1); + } + else { + Log.v (TAG, "fmConfigure() : FM Srch Alg : OLD "); + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, 0); + } + if (re < 0) + return false; + + re = FmReceiverJNI.setBandNative (fd, configSettings.getLowerLimit(), configSettings.getUpperLimit()); + if (re < 0) + return false; + + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_REGION, configSettings.mRadioBand); + /* setControlNative for V4L2_CID_PRIVATE_TAVARUA_REGION triggers the config change*/ + if (re < 0) + return false; + + return true; + } + +} diff --git a/qcom/fmradio/FmReceiver.java b/qcom/fmradio/FmReceiver.java new file mode 100644 index 0000000..969656b --- /dev/null +++ b/qcom/fmradio/FmReceiver.java @@ -0,0 +1,2342 @@ +/* + * Copyright (c) 2009,2012, 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.util.Log; + +/** + * This class contains all interfaces and types needed to + * Control the FM receiver. + * @hide + */ +public class FmReceiver extends FmTransceiver +{ + + public static int mSearchState = 0; + + static final int STD_BUF_SIZE = 256; + static final int GRP_3A = 64; + private static final String TAG = "FMRadio"; + + /** + * 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_AF_EBL =4; + public static final int FM_RX_RDS_GRP_PS_SIMPLE_EBL =16; + + + 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 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; + + private FmRxEvCallbacksAdaptor mCallback; + /** + * 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; + /** + * 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(); + + //registerClient(callback); + mCallback = callback; + } + + + /*============================================================== + 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){ + boolean status = false; + /* + * Check for FM State. + * If FMRx already on, then return. + */ + int state = getFMState(); + 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; + } + + setFMPowerState(subPwrLevel_FMRx_Starting); + Log.v(TAG, "enable: CURRENT-STATE : FMOff ---> NEW-STATE : FMRxStarting"); + status = super.enable(configSettings, FmTransceiver.FM_RX); + + if( status == true ) { + /* Do Receiver Specific Enable Stuff here.*/ + status = registerClient(mCallback); + mRdsData = new FmRxRdsData(sFd); + } + 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(){ + 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(); + + 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 */ + setFMPowerState(FMState_Rx_Turned_On); + 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) { + 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; + + 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); + mRdsData.setPrgmId (pi); + mRdsData.setPrgmType ( (int)( buff[1] & 0x1F)); + int numOfPs = (int)(buff[0] & 0x0F); + 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; + + 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, j = 2; + byte tag_code, tag_len, tag_start_pos; + + bytes_read = FmReceiverJNI.getBufferNative(sFd, rt_plus, BUF_RTPLUS); + 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); + for (i = 1; (i <= 2) && (j < rt_plus[LEN_IND]); i++) { + tag_code = rt_plus[j++]; + tag_start_pos = rt_plus[j++]; + tag_len = rt_plus[j++]; + if (((tag_len + tag_start_pos) <= rt_len) && (tag_code > 0)) { + mRdsData.setTagValue(rt.substring(tag_start_pos, + (tag_len + tag_start_pos)), i); + mRdsData.setTagCode(tag_code, i); + } + } + } 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; + + bytes_read = FmReceiverJNI.getBufferNative(sFd, raw_ert, BUF_ERT); + 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; + } + + /*============================================================== + 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 [40]; + int lowerBand; + + FmReceiverJNI.getBufferNative(sFd, buff, TAVARUA_BUF_AF_LIST); + + 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 (int 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; + } + + + /*============================================================== + 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 int getOnChannelThreshold() + { + return mControl.getOnChannelThreshold(sFd); + } + +/*============================================================== + 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 int getOffChannelThreshold() + { + return mControl.getOffChannelThreshold(sFd); + } +/*=============================================================== + 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: 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); + } +} diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java new file mode 100644 index 0000000..3c779c2 --- /dev/null +++ b/qcom/fmradio/FmReceiverJNI.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2009-2012, 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; + +class FmReceiverJNI { + /** + * General success + */ + static final int FM_JNI_SUCCESS = 0; + + /** + * General failure + */ + static final int FM_JNI_FAILURE = -1; + + /** + * native method: Open device + * @return The file descriptor of the device + * + */ + static native int acquireFdNative(String path); + + + /** + * native method: + * @param fd + * @param control + * @param field + * @return + */ + static native int audioControlNative(int fd, int control, int field); + + /** + * native method: cancels search + * @param fd file descriptor of device + * @return May return + * {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int cancelSearchNative(int fd); + + /** + * native method: release control of device + * @param fd file descriptor of device + * @return May return + * {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int closeFdNative(int fd); + + /** + * native method: get frequency + * @param fd file descriptor of device + * @return Returns frequency in int form + */ + static native int getFreqNative(int fd); + + /** + * native method: set frequency + * @param fd file descriptor of device + * @param freq freq to be set in int form + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + * + */ + static native int setFreqNative(int fd, int freq); + + /** + * native method: get v4l2 control + * @param fd file descriptor of device + * @param id v4l2 id to be retrieved + * @return Returns current value of the + * v4l2 control + */ + static native int getControlNative (int fd, int id); + + /** + * native method: set v4l2 control + * @param fd file descriptor of device + * @param id v4l2 control to be set + * @param value value to be set + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setControlNative (int fd, int id, int value); + + /** + * native method: start search + * @param fd file descriptor of device + * @param dir search direction + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int startSearchNative (int fd, int dir); + + /** + * native method: get buffer + * @param fd file descriptor of device + * @param buff[] buffer + * @param index index of the buffer to be retrieved + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int getBufferNative (int fd, byte buff[], int index); + + /** + * native method: get RSSI value of the + * received signal + * @param fd file descriptor of device + * @return Returns signal strength in int form + * Signal value range from -120 to 10 + */ + static native int getRSSINative (int fd); + + /** + * native method: set FM band + * @param fd file descriptor of device + * @param low lower band + * @param high higher band + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setBandNative (int fd, int low, int high); + + /** + * native method: get lower band + * @param fd file descriptor of device + * @return Returns lower band in int form + */ + static native int getLowerBandNative (int fd); + + /** + * native method: get upper band + * @param fd file descriptor of device + * @return Returns upper band in int form + */ + static native int getUpperBandNative (int fd); + + /** + * native method: force Mono/Stereo mode + * @param fd file descriptor of device + * @param val force mono/stereo indicator + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setMonoStereoNative (int fd, int val); + + /** + * native method: get Raw RDS data + * @param fd file descriptor of device + * @param buff[] buffer + * @param count number of bytes to be read + * @return Returns number of bytes read + */ + static native int getRawRdsNative (int fd, byte buff[], int count); + + /** + * native method: set v4l2 control + * @param fd file descriptor of device + * @param id v4l2 control to be set + * @param value value to be set + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setNotchFilterNative(int fd, int id, boolean value); + + /** + * native method: enable/disable Analog Mode + */ + static native int setAnalogModeNative(boolean value); + + /** + * native method: Starts the RT transmission + * @param fd file descriptor of device + * @param buff[] buffer + * @param count number of bytes to be read + * @return Returns number of bytes read + */ + static native int startRTNative(int fd, String str, int count); + + /** + * native method: Stops the RT transmission + * @param fd file descriptor of device + * @param buff[] buffer + * @param count number of bytes to be read + * @return Returns number of bytes read + */ + static native int stopRTNative(int fd); + + /** + * native method: Starts the PS transmission + * @param fd file descriptor of device + * @param buff[] buffer + * @param count number of bytes to be read + * @return Returns number of bytes read + */ + static native int startPSNative(int fd, String str, int count); + + /** + * native method: Stops the PS transmission + * @param fd file descriptor of device + * @param buff[] buffer + * @param count number of bytes to be read + */ + static native int stopPSNative(int fd); + /** + * native method: Sets the Programme type for transmission + * @param fd file descriptor of device + * @param pty program type to be transmited + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setPTYNative (int fd, int pty); + + /** + * native method: Sets the Programme Id for transmission + * @param fd file descriptor of device + * @param pty program Id to be transmited + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setPINative (int fd, int pi); + + + /** + * native method: Sets the repeat count for Programme service + * transmission. + * @param fd file descriptor of device + * @param repeatcount number of times PS string to be transmited + * repeatedly. + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setPSRepeatCountNative(int fd, int repeatCount); + /** + * native method: Sets the power level for the tramsmitter + * transmission. + * @param fd file descriptor of device + * @param powLevel is the level at which transmitter operates. + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setTxPowerLevelNative(int fd, int powLevel); + /** + * native method: Sets the calibration + * @param fd file descriptor of device + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int SetCalibrationNative(int fd); + + /** + * native method: Configures the spur table + * @param fd file descriptor of device + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int configureSpurTable(int fd); +} diff --git a/qcom/fmradio/FmRxControls.java b/qcom/fmradio/FmRxControls.java new file mode 100644 index 0000000..5c2d42c --- /dev/null +++ b/qcom/fmradio/FmRxControls.java @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2009-2012, 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.util.Log; + + +class FmRxControls +{ + + private boolean mStateStereo; + private boolean mStateMute; + private int mFreq; + + static final int FREQ_MUL = 1000; + static final int SEEK_FORWARD = 0; + static final int SEEK_BACKWARD = 1; + static final int SCAN_FORWARD = 2; + static final int SCAN_BACKWARD = 3; + static final int FM_DIGITAL_PATH = 0; + static final int FM_ANALOG_PATH = 1; + private int mSrchMode; + private int mScanTime; + private int mSrchDir; + private int mSrchListMode; + private int mPrgmType; + private int mPrgmId; + private static final String TAG = "FmRxControls"; + + + /* V4l2 Controls */ + private static final int V4L2_CID_PRIVATE_BASE = 0x8000000; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCHMODE = V4L2_CID_PRIVATE_BASE + 1; + private static final int V4L2_CID_PRIVATE_TAVARUA_SCANDWELL = V4L2_CID_PRIVATE_BASE + 2; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCHON = V4L2_CID_PRIVATE_BASE + 3; + private static final int V4L2_CID_PRIVATE_TAVARUA_STATE = V4L2_CID_PRIVATE_BASE + 4; + private static final int V4L2_CID_PRIVATE_TAVARUA_TRANSMIT_MODE = V4L2_CID_PRIVATE_BASE + 5; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK = V4L2_CID_PRIVATE_BASE + 6; + private static final int V4L2_CID_PRIVATE_TAVARUA_REGION = V4L2_CID_PRIVATE_BASE + 7; + private static final int V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH = V4L2_CID_PRIVATE_BASE + 8; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY = V4L2_CID_PRIVATE_BASE + 9; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_PI = V4L2_CID_PRIVATE_BASE + 10; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT = V4L2_CID_PRIVATE_BASE + 11; + private static final int V4L2_CID_PRIVATE_TAVARUA_EMPHASIS = V4L2_CID_PRIVATE_BASE + 12; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDS_STD = V4L2_CID_PRIVATE_BASE + 13; + private static final int V4L2_CID_PRIVATE_TAVARUA_SPACING = V4L2_CID_PRIVATE_BASE + 14; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSON = V4L2_CID_PRIVATE_BASE + 15; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC = V4L2_CID_PRIVATE_BASE + 16; + private static final int V4L2_CID_PRIVATE_TAVARUA_LP_MODE = V4L2_CID_PRIVATE_BASE + 17; + private static final int V4L2_CID_PRIVATE_TAVARUA_IOVERC = V4L2_CID_PRIVATE_BASE + 24; + private static final int V4L2_CID_PRIVATE_TAVARUA_INTDET = V4L2_CID_PRIVATE_BASE + 25; + private static final int V4L2_CID_PRIVATE_TAVARUA_MPX_DCC = V4L2_CID_PRIVATE_BASE + 26; + private static final int V4L2_CID_PRIVATE_TAVARUA_AF_JUMP = V4L2_CID_PRIVATE_BASE + 27; + private static final int V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA = V4L2_CID_PRIVATE_BASE + 28; + private static final int V4L2_CID_PRIVATE_TAVARUA_HLSI = V4L2_CID_PRIVATE_BASE + 29; + private static final int V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH = V4L2_CID_PRIVATE_BASE + 41; + private static final int V4L2_CID_PRIVATE_SINR = V4L2_CID_PRIVATE_BASE + 44; + private static final int V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD = V4L2_CID_PRIVATE_BASE + 0x2D; + private static final int V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD = V4L2_CID_PRIVATE_BASE + 0x2E; + private static final int V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD = V4L2_CID_PRIVATE_BASE + 0x2F; + private static final int V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES = V4L2_CID_PRIVATE_BASE + 0x30; + private static final int V4L2_CID_PRIVATE_SPUR_FREQ = V4L2_CID_PRIVATE_BASE + 0x31; + private static final int V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI = V4L2_CID_PRIVATE_BASE + 0x32; + private static final int V4L2_CID_PRIVATE_SPUR_SELECTION = V4L2_CID_PRIVATE_BASE + 0x33; + + private static final int V4L2_CTRL_CLASS_USER = 0x980000; + private static final int V4L2_CID_BASE = V4L2_CTRL_CLASS_USER | 0x900; + private static final int V4L2_CID_AUDIO_MUTE = V4L2_CID_BASE + 9; + + private int sOnData ; + private int sOffData ; + + + + /* + * Turn on FM Rx/Tx. + * Rx = 1 and Tx = 2 + */ + public void fmOn(int fd, int device) { + int re; + FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_STATE, device ); + setAudioPath(fd, false); + re = FmReceiverJNI.SetCalibrationNative(fd); + if (re != 0) + Log.d(TAG,"Calibration failed"); + } + + /* + * Turn off FM Rx/Tx + */ + public void fmOff(int fd){ + FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_STATE, 0 ); + } + + /* + * set mute control + */ + public void muteControl(int fd, boolean on) { + if (on) + { + int err = FmReceiverJNI.setControlNative(fd, V4L2_CID_AUDIO_MUTE, 3 ); + } else + { + int err = FmReceiverJNI.setControlNative(fd, V4L2_CID_AUDIO_MUTE, 0 ); + } + } + /* + * Get Interference over channel + */ + public int IovercControl(int fd) + { + int ioverc = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_IOVERC); + Log.d(TAG, "IOVERC value is : "+ioverc); + return ioverc; + } + /* + * Get IntDet + */ + public int IntDet(int fd) + { + int intdet = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_INTDET); + Log.d(TAG, "IOVERC value is : "+intdet); + return intdet; + } + + /* + * Get MPX_DCC + */ + public int Mpx_Dcc(int fd) + { + int mpx_dcc = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_MPX_DCC); + Log.d(TAG, "MPX_DCC value is : " + mpx_dcc); + return mpx_dcc; + } + + /* + * Set Hi-Low injection + */ + public int setHiLoInj(int fd, int inj) + { + int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_HLSI, inj); + return re; + } + + /* + * Set On channel threshold + */ + public int setOnChannelThreshold(int fd, int sBuff) + { + int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD, sBuff); + if ( re < 0) + Log.e(TAG, "Failed to set On channel threshold data"); + return re; + } + + /* + * Set Off channel threshold + */ + public int setOffChannelThreshold(int fd, int sBuff) + { + int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD, sBuff); + if ( re < 0) + Log.e(TAG, "Failed to set Off channel Threshold data"); + return re; + } + + /* + * Get On channel threshold + */ + public int getOnChannelThreshold(int fd) + { + return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD); + } + + /* + * Get Off channel threshold + */ + public int getOffChannelThreshold(int fd) + { + return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD); + } + + /* + * Set sinr threshold + */ + public int setSINRThreshold(int fd, int sBuff) + { + int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD, sBuff); + if ( re < 0) + Log.e(TAG, "Failed to set SINR threshold data"); + return re; + } + + /* + * Set number of sinr samples to take in to account for SINR avg calculation + */ + public int setSINRsamples(int fd, int sBuff) + { + int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES, sBuff); + if ( re < 0) + Log.e(TAG, "Failed to set SINR samples "); + return re; + } + + /* + * Get SINR threshold + */ + public int getSINRThreshold(int fd) + { + return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD); + } + + /* + * Get SINR samples + */ + public int getSINRsamples(int fd) + { + return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES); + } + + /* + * Get RMSSI Delta + */ + public int getRmssiDelta(int fd) + { + int rmssiDel = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA); + return rmssiDel; + } + + /* + * Set RMSSI Delta + */ + public int setRmssiDel(int fd, int delta) + { + int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA, delta); + return re; + } + + /* + * Set the audio path as analog/digital + */ + public int setAudioPath(int fd, boolean value) + { + int mode; + if (value) + mode = FM_ANALOG_PATH; + else + mode = FM_DIGITAL_PATH; + int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH, mode); + return re; + } + + /* + * Tune FM core to specified freq. + */ + public int setStation(int fd) { + Log.d(TAG, "** Tune Using: "+fd); + int ret = FmReceiverJNI.setFreqNative(fd, mFreq); + Log.d(TAG, "** Returned: "+ret); + return ret; + } + + /* + * Get currently tuned freq + */ + public int getTunedFrequency(int fd) { + int frequency = FmReceiverJNI.getFreqNative(fd); + Log.d(TAG, "getTunedFrequency: "+frequency); + return frequency; + } + + public int getFreq (){ + return mFreq; + } + + public void setFreq (int f){ + mFreq = f; + } + /* + * Get SINR value + */ + public int getSINR(int fd) + { + return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_SINR); + } + + + /* + * Start search list for auto presets + */ + public int searchStationList (int fd, int mode, int preset_num, + int dir, int pty ) + { + int re; + + + /* set search mode. */ + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode); + if (re != 0) { + return re; + } + + /* set number of stations to be returned in the list */ + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT, preset_num); + if (re != 0) { + return re; + } + + // RDS search list? + if (pty > 0 ){ + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty); + } + if (re != 0) { + return re; + } + + /* This triigers the search and once completed the FM core generates + * searchListComplete event */ + re = FmReceiverJNI.startSearchNative (fd, dir ); + if (re != 0) { + return re; + } + else { + return 0; + } + + } + + /* Read search list from buffer */ + public int[] stationList (int fd) + { + int freq = 0; + int i=0, j = 0; + int station_num = 0; + float real_freq = 0; + int [] stationList; + byte [] sList = new byte[100]; + int tmpFreqByte1=0; + int tmpFreqByte2=0; + float lowBand, highBand; + + + lowBand = (float) (FmReceiverJNI.getLowerBandNative(fd) / 1000.00); + highBand = (float) (FmReceiverJNI.getUpperBandNative(fd) / 1000.00); + + Log.d(TAG, "lowBand: " + lowBand); + Log.d(TAG, "highBand: " + highBand); + + FmReceiverJNI.getBufferNative(fd, sList, 0); + + if ((int)sList[0] >0) { + station_num = (int)sList[0]; + } + stationList = new int[station_num+1]; + Log.d(TAG, "station_num: " + station_num); + + for (i=0;i<station_num;i++) { + freq = 0; + Log.d(TAG, " Byte1 = " + sList[i*2+1]); + Log.d(TAG, " Byte2 = " + sList[i*2+2]); + tmpFreqByte1 = sList[i*2+1] & 0xFF; + tmpFreqByte2 = sList[i*2+2] & 0xFF; + Log.d(TAG, " tmpFreqByte1 = " + tmpFreqByte1); + Log.d(TAG, " tmpFreqByte2 = " + tmpFreqByte2); + freq = (tmpFreqByte1 & 0x03) << 8; + freq |= tmpFreqByte2; + Log.d(TAG, " freq: " + freq); + real_freq = (float)(freq * 50) + (lowBand * FREQ_MUL);//tuner.rangelow * FREQ_MUL; + Log.d(TAG, " real_freq: " + real_freq); + if ( (real_freq < (lowBand * FREQ_MUL)) || (real_freq > (highBand * FREQ_MUL)) ) { + Log.e(TAG, "Frequency out of band limits"); + } + else { + stationList[j] = (int)(real_freq); + Log.d(TAG, " stationList: " + stationList[j]); + j++; + } + } + + try { + // mark end of list + stationList[station_num] = 0; + } + catch (ArrayIndexOutOfBoundsException e) { + Log.d(TAG, "ArrayIndexOutOfBoundsException !!"); + } + + return stationList; + + } + + + /* configure various search parameters and start search */ + public int searchStations (int fd, int mode, int dwell, + int dir, int pty, int pi){ + int re = 0; + + + Log.d(TAG, "Mode is " + mode + " Dwell is " + dwell); + Log.d(TAG, "dir is " + dir + " PTY is " + pty); + Log.d(TAG, "pi is " + pi + " id " + V4L2_CID_PRIVATE_TAVARUA_SRCHMODE); + + + + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode); + if (re != 0) { + Log.e(TAG, "setting of search mode failed"); + return re; + } + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, dwell); + if (re != 0) { + Log.e(TAG, "setting of scan dwell time failed"); + return re; + } + if (pty != 0) + { + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty); + if (re != 0) { + Log.e(TAG, "setting of PTY failed"); + return re; + } + } + + if (pi != 0) + { + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, pi); + if (re != 0) { + Log.e(TAG, "setting of PI failed"); + return re; + } + } + + re = FmReceiverJNI.startSearchNative (fd, dir ); + return re; + } + + /* force mono/stereo mode */ + public int stereoControl(int fd, boolean stereo) { + + if (stereo){ + return FmReceiverJNI.setMonoStereoNative (fd, 1); + } + else { + return FmReceiverJNI.setMonoStereoNative (fd, 0); + } + + + } + + + public void searchRdsStations(int mode,int dwelling, + int direction, int RdsSrchPty, int RdsSrchPI){ + } + + /* public void searchStationList(int listMode,int direction, + int listMax,int pgmType) { + } + */ + + /* cancel search in progress */ + public void cancelSearch (int fd){ + FmReceiverJNI.cancelSearchNative(fd); + } + + /* Set LPM. This disables all FM core interrupts */ + public int setLowPwrMode (int fd, boolean lpmOn){ + + int re=0; + + if (lpmOn){ + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE, 1); + } + else { + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE, 0); + } + + return re; + + } + + /* get current powermode of the FM core. 1 for LPM and 0 Normal mode */ + public int getPwrMode (int fd) { + + int re=0; + + re = FmReceiverJNI.getControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE); + + return re; + + } + + public int updateSpurTable(int fd, int freq, int rmssi, boolean enable) { + + int re; + + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_FREQ, freq); + if (re < 0) { + Log.e(TAG, "Failed to program the Spur frequency value"); + return re; + } + + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI, rmssi); + if (re < 0) { + Log.e(TAG, "Failed to program the RMSSI level of the Spur frequency"); + return re; + } + + if (enable) { + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_SELECTION, 1); + } + else { + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_SELECTION, 0); + } + if (re < 0) { + Log.e(TAG, "Failed to program Spur selection"); + return re; + } + + return re; + } + + public int configureSpurTable(int fd) { + return FmReceiverJNI.configureSpurTable(fd); + } +} diff --git a/qcom/fmradio/FmRxEvCallbacks.java b/qcom/fmradio/FmRxEvCallbacks.java new file mode 100644 index 0000000..50d2fb2 --- /dev/null +++ b/qcom/fmradio/FmRxEvCallbacks.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009,2012 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; +interface FmRxEvCallbacks { + + public void FmRxEvEnableReceiver(); + public void FmRxEvDisableReceiver(); + public void FmRxEvRadioReset(); + public void FmRxEvRadioTuneStatus(int freq); + public void FmRxEvRdsLockStatus(boolean rdsAvail); + public void FmRxEvStereoStatus(boolean stereo); + public void FmRxEvServiceAvailable(boolean service); + public void FmRxEvSearchInProgress(); + public void FmRxEvSearchCancelled(); + public void FmRxEvSearchComplete(int freq); + public void FmRxEvSearchListComplete(); + public void FmRxEvRdsGroupData(); + public void FmRxEvRdsPsInfo(); + public void FmRxEvRdsRtInfo(); + public void FmRxEvRdsAfInfo(); + public void FmRxEvRTPlus(); + public void FmRxEvERTInfo(); +} diff --git a/qcom/fmradio/FmRxEvCallbacksAdaptor.java b/qcom/fmradio/FmRxEvCallbacksAdaptor.java new file mode 100644 index 0000000..458ff59 --- /dev/null +++ b/qcom/fmradio/FmRxEvCallbacksAdaptor.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009,2012 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; +/** + * + * Class to be implemented for event callbacks + * @hide + */ + +public class FmRxEvCallbacksAdaptor implements FmRxEvCallbacks { + public void FmRxEvEnableReceiver() {}; + public void FmRxEvDisableReceiver() {}; + public void FmRxEvRadioReset() {}; + public void FmRxEvRadioTuneStatus(int freq) {}; + public void FmRxEvRdsLockStatus(boolean rdsAvail) {}; + public void FmRxEvStereoStatus(boolean stereo) {}; + public void FmRxEvServiceAvailable(boolean service) {}; + public void FmRxEvSearchInProgress() {}; + public void FmRxEvSearchCancelled() {}; + public void FmRxEvSearchComplete(int freq) {}; + public void FmRxEvSearchListComplete() {}; + public void FmRxEvRdsGroupData() {}; + public void FmRxEvRdsPsInfo() {}; + public void FmRxEvRdsRtInfo() {}; + public void FmRxEvRdsAfInfo() {}; + public void FmRxEvRTPlus() {}; + public void FmRxEvERTInfo() {}; +} + diff --git a/qcom/fmradio/FmRxEventListner.java b/qcom/fmradio/FmRxEventListner.java new file mode 100644 index 0000000..376e430 --- /dev/null +++ b/qcom/fmradio/FmRxEventListner.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2009,2012, 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 qcom.fmradio.FmReceiver; +import qcom.fmradio.FmTransceiver; +import java.util.Arrays; +import android.util.Log; + + +class FmRxEventListner { + + private final int EVENT_LISTEN = 1; + + private final int STD_BUF_SIZE = 256; + + private enum FmRxEvents { + READY_EVENT, + TUNE_EVENT, + SEEK_COMPLETE_EVENT, + SCAN_NEXT_EVENT, + RAW_RDS_EVENT, + RT_EVENT, + PS_EVENT, + ERROR_EVENT, + BELOW_TH_EVENT, + ABOVE_TH_EVENT, + STEREO_EVENT, + MONO_EVENT, + RDS_AVAL_EVENT, + RDS_NOT_AVAL_EVENT, + TAVARUA_EVT_NEW_SRCH_LIST, + TAVARUA_EVT_NEW_AF_LIST + } + + private Thread mThread; + private static final String TAG = "FMRadio"; + + public void startListner (final int fd, final FmRxEvCallbacks cb) { + /* start a thread and listen for messages */ + mThread = new Thread(){ + public void run(){ + byte [] buff = new byte[STD_BUF_SIZE]; + Log.d(TAG, "Starting listener " + fd); + + while ((!Thread.currentThread().isInterrupted())) { + + try { + int index = 0; + int state = 0; + Arrays.fill(buff, (byte)0x00); + int freq = 0; + int eventCount = FmReceiverJNI.getBufferNative (fd, buff, EVENT_LISTEN); + + if (eventCount >= 0) + Log.d(TAG, "Received event. Count: " + eventCount); + + for ( index = 0; index < eventCount; index++ ) { + Log.d(TAG, "Received <" +buff[index]+ ">" ); + + switch(buff[index]){ + case 0: + Log.d(TAG, "Got READY_EVENT"); + if(FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMRx_Starting) { + /*Set the state as FMRxOn */ + FmTransceiver.setFMPowerState(FmTransceiver.FMState_Rx_Turned_On); + Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMRxOn"); + cb.FmRxEvEnableReceiver(); + } + else if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) { + /*Set the state as FMOff */ + FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off); + Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff"); + FmTransceiver.release("/dev/radio0"); + cb.FmRxEvDisableReceiver(); + Thread.currentThread().interrupt(); + } + break; + case 1: + Log.d(TAG, "Got TUNE_EVENT"); + freq = FmReceiverJNI.getFreqNative(fd); + if (freq > 0) + cb.FmRxEvRadioTuneStatus(freq); + else + Log.e(TAG, "get frequency command failed"); + break; + case 2: + Log.d(TAG, "Got SEEK_COMPLETE_EVENT"); + state = FmReceiver.getSearchState(); + switch(state) { + case FmTransceiver.subSrchLevel_SeekInPrg : + case FmTransceiver.subSrchLevel_ScanInProg: + Log.v(TAG, "Current state is " + state); + FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); + Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); + cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd)); + break; + case FmTransceiver.subSrchLevel_SrchAbort: + Log.v(TAG, "Current state is SRCH_ABORTED"); + Log.v(TAG, "Aborting on-going search command..."); + FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); + Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); + cb.FmRxEvSearchCancelled(); + break; + } + break; + case 3: + Log.d(TAG, "Got SCAN_NEXT_EVENT"); + cb.FmRxEvSearchInProgress(); + break; + case 4: + Log.d(TAG, "Got RAW_RDS_EVENT"); + cb.FmRxEvRdsGroupData(); + break; + case 5: + Log.d(TAG, "Got RT_EVENT"); + cb.FmRxEvRdsRtInfo(); + break; + case 6: + Log.d(TAG, "Got PS_EVENT"); + cb.FmRxEvRdsPsInfo(); + break; + case 7: + Log.d(TAG, "Got ERROR_EVENT"); + break; + case 8: + Log.d(TAG, "Got BELOW_TH_EVENT"); + cb.FmRxEvServiceAvailable (false); + break; + case 9: + Log.d(TAG, "Got ABOVE_TH_EVENT"); + cb.FmRxEvServiceAvailable(true); + break; + case 10: + Log.d(TAG, "Got STEREO_EVENT"); + cb.FmRxEvStereoStatus (true); + break; + case 11: + Log.d(TAG, "Got MONO_EVENT"); + cb.FmRxEvStereoStatus (false); + break; + case 12: + Log.d(TAG, "Got RDS_AVAL_EVENT"); + cb.FmRxEvRdsLockStatus (true); + break; + case 13: + Log.d(TAG, "Got RDS_NOT_AVAL_EVENT"); + cb.FmRxEvRdsLockStatus (false); + break; + case 14: + Log.d(TAG, "Got NEW_SRCH_LIST"); + state = FmReceiver.getSearchState(); + switch(state) { + case FmTransceiver.subSrchLevel_SrchListInProg: + Log.v(TAG, "FmRxEventListener: Current state is AUTO_PRESET_INPROGRESS"); + FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); + Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); + cb.FmRxEvSearchListComplete (); + break; + case FmTransceiver.subSrchLevel_SrchAbort: + Log.v(TAG, "Current state is SRCH_ABORTED"); + Log.v(TAG, "Aborting on-going SearchList command..."); + FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); + Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); + cb.FmRxEvSearchCancelled(); + break; + } + break; + case 15: + Log.d(TAG, "Got NEW_AF_LIST"); + cb.FmRxEvRdsAfInfo(); + break; + case 18: + Log.d(TAG, "Got RADIO_DISABLED"); + if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) { + /*Set the state as FMOff */ + FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off); + Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff"); + FmTransceiver.release("/dev/radio0"); + cb.FmRxEvDisableReceiver(); + Thread.currentThread().interrupt(); + } else { + Log.d(TAG, "Unexpected RADIO_DISABLED recvd"); + cb.FmRxEvRadioReset(); + } + break; + case 19: + FmTransceiver.setRDSGrpMask(0); + break; + case 20: + Log.d(TAG, "got RT plus event"); + cb.FmRxEvRTPlus(); + break; + case 21: + Log.d(TAG, "got eRT event"); + cb.FmRxEvERTInfo(); + break; + default: + Log.d(TAG, "Unknown event"); + break; + } + }//end of for + } catch ( Exception ex ) { + Log.d( TAG, "RunningThread InterruptedException"); + ex.printStackTrace(); + Thread.currentThread().interrupt(); + } + } + } + }; + mThread.start(); + } + + public void stopListener(){ + //mThread.stop(); + //Thread stop is deprecate API + //Interrupt the thread and check for the thread status + // and return from the run() method to stop the thread + //properly + Log.d( TAG, "stopping the Listener\n"); + if( mThread != null ) { + mThread.interrupt(); + } + } + +} diff --git a/qcom/fmradio/FmRxRdsData.java b/qcom/fmradio/FmRxRdsData.java new file mode 100644 index 0000000..dac4194 --- /dev/null +++ b/qcom/fmradio/FmRxRdsData.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2009,2012, 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.util.Log; +/** + * + * @hide + */ +public class FmRxRdsData { + + + private String mRadioText = ""; + private String mPrgmServices; + private String mERadioText = ""; + // false means left-right + // true means right-left + private boolean formatting_dir = false; + private byte []mTagCode = new byte[2]; + private String []mTag = new String[2]; + private int tag_nums = 0; + private static final int MAX_NUM_TAG = 2; + private boolean rt_ert_flag; + private int mPrgmId; + private int mPrgmType; + private int mFd; + + /* V4L2 controls */ + private static final int V4L2_CID_PRIVATE_BASE = 0x8000000; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK = V4L2_CID_PRIVATE_BASE + 6; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSON = V4L2_CID_PRIVATE_BASE + 15; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC = V4L2_CID_PRIVATE_BASE + 16; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF = V4L2_CID_PRIVATE_BASE + 19; + private static final int V4L2_CID_PRIVATE_TAVARUA_PSALL = V4L2_CID_PRIVATE_BASE + 20; + private static final int V4L2_CID_PRIVATE_TAVARUA_AF_JUMP = V4L2_CID_PRIVATE_BASE + 27; + + + private static final int RDS_GROUP_RT = 0x1; + private static final int RDS_GROUP_PS = 1 << 1; + private static final int RDS_GROUP_AF = 1 << 2; + private static final int RDS_AF_AUTO = 1 << 6; + private static final int RDS_PS_ALL = 1 << 4; + private static final int RDS_AF_JUMP = 0x1; + private static final int MAX_TAG_CODES = 64; + + private static final String LOGTAG="FmRxRdsData"; + + + public FmRxRdsData (int fd) + { + mFd = fd; + } + + /* turn on/off RDS processing */ + public int rdsOn (boolean on) + { + + int ret; + + Log.d(LOGTAG, "In rdsOn: RDS is " + on); + + if (on) { + ret = FmReceiverJNI.setControlNative (mFd, V4L2_CID_PRIVATE_TAVARUA_RDSON, 1); + } + else { + ret = FmReceiverJNI.setControlNative (mFd, V4L2_CID_PRIVATE_TAVARUA_RDSON, 0); + } + + + return ret; + + + } + + /* process raw RDS group filtering */ + public int rdsGrpOptions (int grpMask, int buffSize, boolean rdsFilter) + { + + int rdsFilt; + int re; + + byte rds_group_mask = (byte)FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC); + + rds_group_mask &= 0xFE; + + + if (rdsFilter) + rdsFilt = 1; + else + rdsFilt = 0; + + rds_group_mask |= rdsFilt; + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, rds_group_mask); + + if (re != 0) + return re; + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF, buffSize); + + if (re != 0) + return re; + + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, grpMask); + + return re; + + + } + + /* configure RT/PS/AF RDS processing */ + public int rdsOptions (int rdsMask) + { + + int re=0; + + byte rds_group_mask = (byte)FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC); + byte rdsFilt = 0; + int psAllVal=rdsMask & RDS_PS_ALL; + + Log.d(LOGTAG, "In rdsOptions: rdsMask: " + rdsMask); + + + rds_group_mask &= 0xC7; + + + rds_group_mask |= ((rdsMask & 0x07) << 3); + + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, rds_group_mask); + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_PSALL, psAllVal >> 4 ); + + return re; + + } + + /* Enable auto seek to alternate frequency */ + public int enableAFjump(boolean AFenable) + { + int re; + int rds_group_mask = 0; + + Log.d(LOGTAG, "In enableAFjump: AFenable : " + AFenable); + + rds_group_mask = FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC); + Log.d(LOGTAG, "Currently set rds_group_mask : " + rds_group_mask); + + if (AFenable) + re = FmReceiverJNI.setControlNative(mFd ,V4L2_CID_PRIVATE_TAVARUA_AF_JUMP, 1); + else + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_AF_JUMP, 0); + + rds_group_mask = FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC); + + if (AFenable) + Log.d(LOGTAG, "After enabling the rds_group_mask is : " + rds_group_mask); + else + Log.d(LOGTAG, "After disabling the rds_group_mask is : " + rds_group_mask); + + return re; + } + + + public String getRadioText () { + return mRadioText; + } + + public void setRadioText (String x) { + + mRadioText = x; + } + + public String getPrgmServices () { + return mPrgmServices; + } + public void setPrgmServices (String x) { + mPrgmServices = x; + } + + public int getPrgmId () { + return mPrgmId; + } + public void setPrgmId (int x) { + mPrgmId = x; + } + + public int getPrgmType () { + return mPrgmType; + } + public void setPrgmType (int x) { + mPrgmType = x; + } + public String getERadioText () { + return mERadioText; + } + public void setERadioText (String x) { + mERadioText = x; + } + public boolean getFormatDir() { + return formatting_dir; + } + public void setFormatDir(boolean dir) { + formatting_dir = dir; + } + public void setTagValue (String x, int tag_num) { + if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG)) { + mTag[tag_num - 1] = x; + tag_nums++; + } + } + public void setTagCode (byte tag_code, int tag_num) { + if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG)) + mTagCode[tag_num - 1] = tag_code; + } + public String getTagValue (int tag_num) { + if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG)) + return mTag[tag_num - 1]; + else + return ""; + } + public byte getTagCode (int tag_num) { + if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG)) + return mTagCode[tag_num - 1]; + else + return 0; + } + public int getTagNums() { + return tag_nums; + } + public void setTagNums(int x) { + if ((x >= 0) && (x <= MAX_NUM_TAG)) + tag_nums = x; + } +} diff --git a/qcom/fmradio/FmTransceiver.java b/qcom/fmradio/FmTransceiver.java new file mode 100644 index 0000000..8a02c2d --- /dev/null +++ b/qcom/fmradio/FmTransceiver.java @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2009-2012, 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.util.Log; + +/** <code>FmTransceiver</code> is the superclass of classes + * <code>FmReceiver</code> and <code>FmTransmitter</code> + * @hide + */ +public class FmTransceiver +{ + /* Primary FM States : + * FM will be in one of the 4 states at any point of time + * '0' - FMState_Turned_Off + * '1' - FMState_Rx_Turned_On + * '2' - FMState_Tx_Turned_On + * '3' - FMState_Srch_InProg + */ + public static final int FMState_Turned_Off = 0; + public static final int FMState_Rx_Turned_On = 1; + public static final int FMState_Tx_Turned_On = 2; + public static final int FMState_Srch_InProg = 3; + + /* Intermediate FM power levels */ + public static final int subPwrLevel_FMRx_Starting = 4; + public static final int subPwrLevel_FMTx_Starting = 5; + public static final int subPwrLevel_FMTurning_Off = 6; + + /* Intermediate FM search levels : + * These are the sub-levels of FM Search operations : seek/scan/auto-preset. + * Used internally for distinguishing between the various search operations. + */ + public static final int subSrchLevel_SeekInPrg = 0; + public static final int subSrchLevel_ScanInProg = 1; + public static final int subSrchLevel_SrchListInProg = 2; + public static final int subSrchLevel_SrchComplete = 3; + public static final int subSrchLevel_SrchAbort = 4; + + /* Holds the current state of the FM device */ + public static int FMState = FMState_Turned_Off; + + /** + * FMConfigure FM Radio band setting for US/Europe + */ + public static final int FM_US_BAND = 0; + /** + * FMConfigure FM Radio band setting for US/Europe + */ + public static final int FM_EU_BAND = 1; + /** + * FMConfigure FM Radio band setting for Japan + */ + public static final int FM_JAPAN_STANDARD_BAND = 2; + /** + * FMConfigure FM Radio band setting for Japan-Wideband + */ + public static final int FM_JAPAN_WIDE_BAND = 3; + /** + * FMConfigure FM Radio band setting for "User defined" band + */ + public static final int FM_USER_DEFINED_BAND = 4; + + /** + * FM channel spacing settings = 200KHz + */ + public static final int FM_CHSPACE_200_KHZ =0; + /** + * FM channel spacing settings = 100KHz + */ + public static final int FM_CHSPACE_100_KHZ =1; + /** + * FM channel spacing settings = 50KHz + */ + public static final int FM_CHSPACE_50_KHZ =2; + + /** + * FM de-emphasis/pre-emphasis settings = 75KHz + */ + public static final int FM_DE_EMP75 = 0; + /** + * FM de-emphasis/pre-emphasis settings = 50KHz + */ + public static final int FM_DE_EMP50 = 1; + + /** + * RDS standard type: RBDS (North America) + */ + public static final int FM_RDS_STD_RBDS =0; + /** + * RDS standard type: RDS (Rest of the world) + */ + public static final int FM_RDS_STD_RDS =1; + /** + * RDS standard type: No RDS + */ + public static final int FM_RDS_STD_NONE =2; + + protected static final int FM_RX =1; + protected static final int FM_TX =2; + + private final int READY_EVENT = 0x01; + private final int TUNE_EVENT = 0x02; + private final int RDS_EVENT = 0x08; + private final int MUTE_EVENT = 0x04; + private final int SEEK_COMPLETE_EVENT = 0x03; + + private static final int V4L2_CID_PRIVATE_BASE = 0x8000000; + private static final int V4L2_CID_PRIVATE_TAVARUA_ANTENNA = V4L2_CID_PRIVATE_BASE + 18; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK = V4L2_CID_PRIVATE_BASE + 6; + private static final int V4L2_CID_PRIVATE_TAVARUA_SET_NOTCH_FILTER = V4L2_CID_PRIVATE_BASE + 40; + + private final String TAG = "FmTransceiver"; + private final String V4L2_DEVICE = "/dev/radio0"; + + protected static int sFd; + protected FmRxControls mControl; + protected int mPowerMode; + protected FmRxEventListner mRxEvents; + protected FmRxRdsData mRdsData; + protected FmTxEventListner mTxEvents; + + public static final int ERROR = -1; + + /*============================================================== + FUNCTION: acquire + ==============================================================*/ + /** + * Allows access to the V4L2 FM device. + * + * This synchronous call allows a client to use the V4L2 FM + * device. This must be the first call issued by the client + * before any receiver interfaces can be used. + * + * This call also powers up the FM Module. + * + * @param device String that is path to radio device + * + * @return true if V4L2 FM device acquired, false if V4L2 FM + * device could not be acquired, possibly acquired by + * other client + * @see #release + * + */ + protected boolean acquire(String device){ + boolean bStatus = true; + if (sFd <= 0) { // if previous open fails fd will be -ve. + sFd = FmReceiverJNI.acquireFdNative(V4L2_DEVICE); + + if (sFd > 0) { + Log.d(TAG, "Opened "+ sFd); + bStatus = true; + } + else { + Log.d(TAG, "Fail to Open "+ sFd); + bStatus = false; + } + } + else { + Log.d(TAG, "Already Opened:" + sFd); + /*This should be case + * Where User try to opne the device + * secondtime. + * Case where Tx and Rx try to + * acquire the device + */ + bStatus = false; + } + return (bStatus); + } + + /*============================================================== + FUNCTION: release + ==============================================================*/ + /** + * Releases access to the V4L2 FM device. + * <p> + * This synchronous call allows a client to release control of + * V4L2 FM device. This function should be called when the FM + * device is no longer needed. This should be the last call + * issued by the FM client. Once called, the client must call + * #acquire to re-aquire the V4L2 device control before the + * FM device can be used again. + * <p> + * Before the client can release control of the FM receiver + * interface, it must disable the FM receiver, if the client + * enabled it, and unregister any registered callback. If the + * client has ownership of the receiver, it will automatically + * be returned to the system. + * <p> + * This call also powers down the FM Module. + * <p> + * @param device String that is path to radio device + * @return true if V4L2 FM device released, false if V4L2 FM + * device could not be released + * @see #acquire + */ + static boolean release(String device) { + if (sFd!=0) + { + FmReceiverJNI.closeFdNative(sFd); + sFd = 0; + Log.d("FmTransceiver", "Turned off: " + sFd); + } else + { + Log.d("FmTransceiver", "Error turning off"); + } + return true; + } + + /*============================================================== + FUNCTION: registerClient + ==============================================================*/ + /** + * Registers a callback for FM receiver event notifications. + * <p> + * This is a synchronous call 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 callback to handle the events events + * from the FM receiver. + * @return true if Callback registered, false if Callback + * registration failed. + * + * @see #acquire + * @see #unregisterClient + * + */ + public boolean registerClient(FmRxEvCallbacks callback){ + boolean bReturnStatus = false; + if (callback!=null) + { + mRxEvents.startListner(sFd, callback); + bReturnStatus = true; + } else + { + Log.d(TAG, "Null, do nothing"); + } + return bReturnStatus; + } + + /*============================================================== + FUNCTION: unregisterClient + ==============================================================*/ + /** + * Unregisters a client's event notification callback. + * <p> + * This is a synchronous call used to unregister a client's + * event callback. + * <p> + * @return true always. + * + * @see #acquire + * @see #release + * @see #registerClient + * + */ + public boolean unregisterClient () { + mRxEvents.stopListener(); + return true; + } + + + /*============================================================== + FUNCTION: registerTransmitClient + ==============================================================*/ + /** + * Registers a callback for FM Transmitter event + * notifications. + * <p> + * This is a synchronous call used to register for event + * notifications from the FM Transmitter 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 callback to handle the events events + * from the FM Transmitter. + * @return true if Callback registered, false if Callback + * registration failed. + * + * @see #acquire + * @see #unregisterTransmitClient + * + */ + public boolean registerTransmitClient( FmTransmitterCallbacks callback){ + boolean bReturnStatus = false; + if (callback!=null) + { + mTxEvents.startListner(sFd, callback); + bReturnStatus = true; + } else + { + Log.d(TAG, "Null, do nothing"); + } + return bReturnStatus; + } + + /*============================================================== + FUNCTION: unregisterTransmitClient + ==============================================================*/ + /** + * Unregisters Transmitter event notification callback. + * <p> + * This is a synchronous call used to unregister a Transmitter + * client's event callback. + * <p> + * @return true always. + * + * @see #acquire + * @see #release + * @see #registerTransmitClient + * + */ + public boolean unregisterTransmitClient () { + mTxEvents.stopListener(); + return true; + } + + /*============================================================== + FUNCTION: enable + ==============================================================*/ + /** + * Initializes the FM device. + * <p> + * This is a synchronous call is used to initialize the FM + * tranceiver. If already initialized this function will + * intialize the tranceiver 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 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 #configure. + * <p> + * This call can only be issued by the owner of an FM + * receiver. To issue this call, the client must first + * successfully call #acquire. + * <p> + * @param configSettings the settings to be applied when + * turning on the radio + * @return true if Initialization succeeded, false if + * Initialization failed. + * @see #registerClient + * @see #disable + * + */ + public boolean enable (FmConfig configSettings, int device){ + + boolean status; + //Acquire the deviceon Enable + if( !acquire("/dev/radio0")){ + return false; + } + Log.d(TAG, "turning on " + device); + mControl.fmOn(sFd, device); + + Log.d(TAG, "Calling fmConfigure"); + status = FmConfig.fmConfigure (sFd, configSettings); + if (!status) { + Log.d(TAG, "fmConfigure failed"); + FmReceiverJNI.closeFdNative(sFd); + sFd = 0; + } + return status; + } + + /*============================================================== + FUNCTION: disable + ==============================================================*/ + /** + * Disables the FM Device. + * <p> + * This is a synchronous call 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 + * #enable. + * <p> + * @return true if disabling succeeded, false if disabling + * failed. + * <p> + * @see #enable + * @see #registerClient + */ + public boolean disable(){ + mControl.fmOff(sFd); + return true; + } + + /*============================================================== + FUNCTION: configure + ==============================================================*/ + /** + * Reconfigures the device's regional settings + * (FM Band, De-Emphasis, Channel Spacing, RDS/RBDS mode). + * <p> + * This is a synchronous call used to reconfigure settings on + * the FM device. Included in the passed structure are + * settings which typically differ from one geographical + * region to another. + * <p> + * @param configSettings Contains settings for the FM radio + * (FM band, De-emphasis, channel + * spacing, RDS/RBDS mode) + * <p> + * @return true if configure succeeded, false if + * configure failed. + */ + public boolean configure(FmConfig configSettings){ + boolean status=true; + int lowerFreq = configSettings.getLowerLimit(); + Log.d(TAG, "fmConfigure"); + status = FmConfig.fmConfigure (sFd, configSettings); + status = setStation (lowerFreq); + return status; + } + + /*============================================================== + FUNCTION: setStation + ==============================================================*/ + /** + * Tunes the FM device to the specified FM frequency. + * <p> + * This method tunes the FM device to a station specified by the + * provided frequency. Only valid frequencies within the band + * set by enable or configure can be tuned by this function. + * Attempting to tune to frequencies outside of the set band + * will result in an error. + * <p> + * Once tuning to the specified frequency is completed, the + * event callback FmRxEvRadioTuneStatus will be called. + * + * @param frequencyKHz Frequency (in kHz) to be tuned + * (Example: 96500 = 96.5Mhz) + * @return true if setStation call was placed successfully, + * false if setStation failed. + */ + public boolean setStation (int frequencyKHz) { + int ret; + + mControl.setFreq(frequencyKHz); + ret = mControl.setStation(sFd); + if(ret < 0 ) + { + return false; + } + else + { + return true; + } + } + + /*============================================================== + FUNCTION: SetNotchFilter + ==============================================================*/ + /** + * Sets the desired notch filter for WAN avoidance. + * <p> + * This method sets the required Notch filter based on the current + * WAN band frequency to achieve the FM-WAN concurrency. + * Application should listen to Data call events and call the function + * on every data call connection set-u, to achieve the FM-WAN concurrency. + * + */ + public void setNotchFilter(boolean value) { + FmReceiverJNI.setNotchFilterNative(sFd, V4L2_CID_PRIVATE_TAVARUA_SET_NOTCH_FILTER, value); + } + + /*============================================================== + FUNCTION: SetAnalogMode + ==============================================================*/ + /** + * Enable/Disable the Analog lowpower mode. + * <p> + * This method enables/disables the analog lowpower mode. + * + */ + public boolean setAnalogMode(boolean value) { + int re = mControl.setAudioPath(sFd, value); + re = FmReceiverJNI.setAnalogModeNative(value); + if (re == 1) + return true; + return false; + } + + /*============================================================== + FUNCTION: getInternalAntenna + ==============================================================*/ + /** + * Returns true if internal FM antenna is available + * + * <p> + * This method returns true is internal FM antenna is + * available, false otherwise + * + * <p> + * @return true/false + */ + public boolean getInternalAntenna() + { + + int re = FmReceiverJNI.getControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA); + + if (re == 1) + return true; + + return false; + } + + /*============================================================== + FUNCTION: setInternalAntenna + ==============================================================*/ + /** + * Returns true if successful, false otherwise + * + * <p> + * This method sets internal antenna type to true/false + * + * @param intAntenna true is Internal antenna is present + * + * <p> + * @return true/false + */ + public boolean setInternalAntenna(boolean intAnt) + { + + int iAntenna ; + + if (intAnt) + iAntenna = 1; + else + iAntenna = 0; + + + int re = FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna); + + if (re == 0) + return true; + + return false; + } +/*============================================================== + FUNCTION: setFMPowerState + ==============================================================*/ + /** + * Sets the FM power state + * + * <p> + * This method sets the FM power state. + * + * <p> + */ + static void setFMPowerState(int state) + { + FMState = state; + } +/*============================================================== + FUNCTION: getFMPowerState + ==============================================================*/ + /** + * Returns : + * + * FMOff - If the FM Radio is turned off + * FMRxOn - If the FM Receiver is currently turned on + * FMTxOn - If the FM Transmitter is currently turned on + * FMReset - If the FM Radio is reset + * + * Gets the FM power state + * + * <p> + * This method gets the FM power state. + * + * <p> + */ + public static int getFMPowerState() + { + return FMState; + } + public static boolean setRDSGrpMask(int mask) + { + int re; + re = FmReceiverJNI.setControlNative(sFd, + V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, mask); + if (re == 0) + return true; + else + return false; + } +} diff --git a/qcom/fmradio/FmTransmitter.java b/qcom/fmradio/FmTransmitter.java new file mode 100644 index 0000000..1ae356b --- /dev/null +++ b/qcom/fmradio/FmTransmitter.java @@ -0,0 +1,923 @@ +/* + * Copyright (c) 2009-2012, 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.util.Log; + + +/** + * This class contains all interfaces and types needed to control the FM transmitter. + * @hide + */ +public class FmTransmitter extends FmTransceiver +{ + private final String TAG = "FmTransmitter"; + /** + * An object that contains the PS Features that SoC supports + * + * @see #getPSFeatures + */ + public class FmPSFeatures + { + public int maxPSCharacters; + public int maxPSStringRepeatCount; + }; + + + /** + * Command types for the RDS group transmission. + * This is used as argument to #transmitRdsGroupControl to + * control the RDS group transmission. + * + * @see #transmitRdsGroupControl + */ + + public static final int RDS_GRPS_TX_PAUSE = 0; /* Pauses the Group transmission*/ + + public static final int RDS_GRPS_TX_RESUME = 1; /* Resumes the Group transmission*/ + + public static final int RDS_GRPS_TX_STOP = 2; /* Stops and clear the Group transmission */ + + public static final int FM_TX_MAX_PS_LEN = (96+1); + public static final int FM_TX_MAX_RT_LEN = (64-1); /*One space to include NULL*/ + + private static final int MAX_PS_CHARS = 97; + private static final int MAX_PS_REP_COUNT = 15; + private static final int MAX_RDS_GROUP_BUF_SIZE = 62; + + private FmTransmitterCallbacksAdaptor mTxCallbacks; + private boolean mPSStarted = false; + private boolean mRTStarted = false; + private static final int V4L2_CID_PRIVATE_BASE = 0x8000000; + private static final int V4L2_CID_PRIVATE_TAVARUA_ANTENNA = V4L2_CID_PRIVATE_BASE + 18; + + /** + * Power settings + * + * @see #setPowerMode + * @see #getPowerMode + */ + public static final int FM_TX_NORMAL_POWER_MODE =0; + public static final int FM_TX_LOW_POWER_MODE =1; + + /** + * Transmit Power level settings + * + * @see #setTxPowerLevel + */ + public static final int FM_TX_PWR_LEVEL_0 =0; + public static final int FM_TX_PWR_LEVEL_1 =1; + public static final int FM_TX_PWR_LEVEL_2 =2; + public static final int FM_TX_PWR_LEVEL_3 =3; + public static final int FM_TX_PWR_LEVEL_4 =4; + public static final int FM_TX_PWR_LEVEL_5 =5; + public static final int FM_TX_PWR_LEVEL_6 =6; + public static final int FM_TX_PWR_LEVEL_7 =7; + + + /** + * Constructor for the transmitter class that takes path to + * radio device and event callback adapter + */ + public FmTransmitter(String path, FmTransmitterCallbacksAdaptor callbacks) throws InstantiationException{ + + mTxEvents = new FmTxEventListner(); + mControl = new FmRxControls(); + mTxCallbacks = callbacks; + } + + /*============================================================== + FUNCTION: enable + ==============================================================*/ + /** + * Enables the FM device in Transmit Mode. + * <p> + * This is a synchronous method used to initialize the FM + * device in transmitt mode. If already initialized this function will + * intialize the Fm device with default settings. Only after + * successfully calling this function can many of the FM device + * interfaces be used. + * <p> + * When enabling the transmitter, the application must also + * provide the regional settings in which the transmitter will + * operate. These settings (included in argument + * configSettings) are typically used for setting up the FM + * Transmitter 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 + * transmitter. + * + * @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 #registerTransmitClient + * @see #disable + * + */ + public boolean enable (FmConfig configSettings){ + boolean status = true; + + int state = getFMState(); + if (state == FMState_Tx_Turned_On) { + Log.d(TAG, "enable: FM Tx 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_FMTx_Starting) { + Log.v(TAG, "FM is in the process of turning On.Pls wait for sometime."); + return status; + } + setFMPowerState(subPwrLevel_FMTx_Starting); + Log.v(TAG, "enable: CURRENT-STATE : FMOff ---> NEW-STATE : FMTxStarting"); + status = super.enable(configSettings, FmTransceiver.FM_TX); + if(status == true) { + registerTransmitClient(mTxCallbacks); + mRdsData = new FmRxRdsData(sFd); + } else { + status = false; + Log.e(TAG, "enable: failed to turn On FM TX"); + Log.e(TAG, "enable: CURRENT-STATE : FMTxStarting ---> NEW-STATE : FMOff"); + setFMPowerState(FMState_Turned_Off); + } + return status; + } + /*============================================================== + FUNCTION: setRdsOn + ==============================================================*/ + /** + * + * This function enables RDSCTRL register for SoC. + * + * <p> + * This API enables the ability of the FM driver + * to send Program Service, RadioText information. + * + * + * @return true if the command was placed successfully, false + * if command failed. + * + */ + public boolean setRdsOn (){ + + if (mRdsData == null) + return false; + // Enable RDS + int re = mRdsData.rdsOn(true); + + if (re ==0) + return true; + + return false; + } + + /*============================================================== + FUNCTION: disable + ==============================================================*/ + /** + * Disables the FM Transmitter Device. + * <p> + * This is a synchronous command used to disable the FM + * device. This function is expected to be used when the + * application no longer requires use of the FM device. Once + * called, most functionality offered by the FM device will be + * disabled until the application re-enables the device again + * via {@link #enable}. + * + * <p> + * @return true if disabling succeeded, false if disabling + * failed. + * + * @see #enable + * @see #registerTransmitClient + */ + public boolean disable(){ + boolean status = false; + int state; + + state = getFMState(); + switch(state) { + case FMState_Turned_Off: + Log.d(TAG, "FM already tuned Off."); + return true; + case subPwrLevel_FMTx_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_FMTx_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 : FMTxOn ---> NEW-STATE : FMTurningOff"); + //Stop all the RDS transmissions if there any + if(mPSStarted) { + if(!stopPSInfo()) { + Log.d(TAG, "FmTrasmitter:stopPSInfo failed\n"); + } + } + if(mRTStarted) { + if(!stopRTInfo()) { + Log.d(TAG, "FmTrasmitter:stopRTInfo failed\n"); + } + } + if(!transmitRdsGroupControl(RDS_GRPS_TX_STOP) ) { + Log.d(TAG, "FmTrasmitter:transmitRdsGroupControl failed\n"); + } + super.disable(); + return true; + } + + /*============================================================== + 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 #registerTransmitClient + */ + public boolean reset(){ + boolean status = false; + + status = unregisterTransmitClient(); + return status; + } + + /*============================================================== + FUNCTION: setStation + ==============================================================*/ + /** + * Tunes the FM device to the specified FM frequency. + * <p> + * This method tunes the FM device to a station specified by the + * provided frequency. Only valid frequencies within the band + * set by enable or configure can be tuned by this function. + * Attempting to tune to frequencies outside of the set band + * will result in an error. + * <p> + * Once tuning to the specified frequency is completed, the + * event callback FmTransmitterCallbacks::onTuneStatusChange will be called. + * + * @param frequencyKHz Frequency (in kHz) to be tuned + * (Example: 96500 = 96.5Mhz) + * @return true if setStation call was placed successfully, + * false if setStation failed. + */ + public boolean setStation (int frequencyKHz) { + + //Stop If there is any ongoing RDS transmissions + boolean status = false; + if( mPSStarted ){ + Log.d(TAG,"FmTransmitter:setStation mPSStarted"); + if( !stopPSInfo() ) return status; + } + if( mRTStarted ) { + Log.d(TAG,"FmTransmitter:setStation mRTStarted"); + if(!stopRTInfo()) return status; + } + if(!transmitRdsGroupControl(RDS_GRPS_TX_STOP) )return status; + + Log.d(TAG, "FmTrasmitter:SetStation\n"); + status = super.setStation(frequencyKHz); + + return status; + } + /*============================================================== + 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_TX_LOW_POWER_MODE) { + re = mControl.setLowPwrMode (sFd, true); + } + else { + re = mControl.setLowPwrMode (sFd, false); + } + + if (re == 0) + return true; + return false; + } + + + /*============================================================== + FUNCTION: getPSFeatures + ==============================================================*/ + /** + * This function returns the features supported by the FM + * driver when using {@link #setPSInfo}. + * <p> + * This function is used to get the features the FM driver + * supports when transmitting Program Service information. + * Included in the returned features is the number of Program + * Service (PS) characters which can be transmitted using + * {@link #setPSInfo}. If the driver supports continuous + * transmission of Program Service Information, this function + * will return a value greater than 0 for + * FmPSFeatures.maxPSCharacters. Although the RDS/RBDS + * standard defines each Program Service (PS) string as eight + * characters in length, the FM driver may have the ability to + * accept a string that is greater than eight character. This + * extended string will thenbe broken up into multiple strings + * of length eight and transmitted continuously. + * <p> + * When transmitting more than one string, the application may + * want to control the timing of how long each string is + * transmitted. Included in the features returned from this + * function is the maximum Program Service string repeat count + * (FmPSFeatures.maxPSStringRepeatCount). When using the + * function {@link #setPSInfo}, the application can specify how + * many times each string is repeated before the next string is + * transmitted. + * + * @return the Program service maximum characters and repeat + * count + * + * @see #setPSInfo + * + */ + public FmPSFeatures getPSFeatures(){ + FmPSFeatures psFeatures = new FmPSFeatures(); + + psFeatures.maxPSCharacters = MAX_PS_CHARS; + psFeatures.maxPSStringRepeatCount = MAX_PS_REP_COUNT; + return psFeatures; + } + + /*============================================================== + FUNCTION: startPSInfo + ==============================================================*/ + /** + * Continuously transmit RDS/RBDS Program Service information + * over an already tuned station. + * <p> + * This is a synchronous function used to continuously transmit Program + * Service information over an already tuned station. While + * Program Service information can be transmitted using {@link + * #transmitRdsGroups} and 0A/0B groups, this function makes + * the same output possible with limited input needed from the + * application. + * <p> + * Included in the Program Service information is an RDS/RBDS + * program type (PTY), and one or more Program Service + * strings. The program type (PTY) is used to describe the + * content being transmitted and follows the RDS/RBDS program + * types described in the RDS/RBDS specifications. + * <p> + * Program Service information also includes an eight + * character string. This string can be used to display any + * information, but is typically used to display information + * about the audio being transmitted. Although the RDS/RBDS + * standard defines a Program Service (PS) string as eight + * characters in length, the FM driver may have the ability to + * accept a string that is greater than eight characters. This + * extended string will then be broken up into multiple eight + * character strings which will be transmitted continuously. + * All strings passed to this function must be terminated by a + * null character (0x00). + * <p> + * When transmitting more than one string, the application may + * want to control the timing of how long each string is + * transmitted. To control this timing and to ensure that the FM + * receiver receives each string, the application can specify + * how many times each string is repeated before the next string + * is transmitted. This command can only be issued by the owner + * of an FM transmitter. + * <p> + * Maximux Programme service string lenght that can be sent is + * FM_TX_MAX_PS_LEN. If the application sends PS string longer than + * this threshold, string will be truncated to FM_TX_MAX_PS_LEN. + * + * @param psStr the program service strings to transmit + * @param pty the program type to use in the program Service + * information. + * @param pi the program type to use in the program Service + * information. + * @param repeatCount the number of times each 8 char string is + * repeated before next string + * + * @return true if PS information was successfully sent to the + * driver, false if PS information could not be sent + * to the driver. + * + * @see #getPSFeatures + * @see #stopPSInfo + */ + public boolean startPSInfo(String psStr, int pty, int pi, int repeatCount){ + + //Set the PTY + if((pty < 0) || (pty > 31 )) { + Log.d(TAG,"pTy is expected from 0 to 31"); + return false; + } + + int err = FmReceiverJNI.setPTYNative( sFd, pty ); + if( err < 0 ){ + Log.d(TAG,"setPTYNative is failure"); + return false; + } + + if((pi < 0) || (pi > 65535)) { + Log.d(TAG,"pi is expected from 0 to 65535"); + return false; + } + + //Set the PI + err = FmReceiverJNI.setPINative( sFd, pi ); + if( err < 0 ){ + Log.d(TAG,"setPINative is failure"); + return false; + } + + if((repeatCount < 0) || (repeatCount > 15)) { + Log.d(TAG,"repeat count is expected from 0 to 15"); + return false; + } + + err = FmReceiverJNI.setPSRepeatCountNative( sFd, repeatCount ); + if( err < 0 ){ + Log.d(TAG,"setPSRepeatCountNative is failure"); + return false; + } + + if( psStr.length() > FM_TX_MAX_PS_LEN ){ + /*truncate the PS string to + MAX possible length*/ + psStr = psStr.substring( 0, FM_TX_MAX_PS_LEN ); + + } + + err = FmReceiverJNI.startPSNative( sFd, psStr , psStr.length() ); + Log.d(TAG,"return for startPS is "+err); + + if( err < 0 ){ + Log.d(TAG, "FmReceiverJNI.startPSNative returned false\n"); + return false; + + } else { + Log.d(TAG,"startPSNative is successful"); + mPSStarted = true; + return true; + } + } + + /*============================================================== + FUNCTION: stopPSInfo + ==============================================================*/ + /** + * Stops an active Program Service transmission. + * + * <p> + * This is a synchrnous function used to stop an active Program Service transmission + * started by {@link #startPSInfo}. + * + * @return true if Stop PS information was successfully sent to + * the driver, false if Stop PS information could not + * be sent to the driver. + * + * @see #getPSFeatures + * @see #startPSInfo + * + */ + public boolean stopPSInfo(){ + int err =0; + if( (err =FmReceiverJNI.stopPSNative( sFd )) < 0 ){ + Log.d(TAG,"return for startPS is "+err); + return false; + } else{ + Log.d(TAG,"stopPSNative is successful"); + mPSStarted = false; + return true; + } + } + + + /*============================================================== + FUNCTION: startRTInfo + ==============================================================*/ + /** + * Continuously transmit RDS/RBDS RadioText information over an + * already tuned station. + * + * <p> + * This is a synchronous function used to continuously transmit RadioText + * information over an already tuned station. While RadioText + * information can be transmitted using + * {@link #transmitRdsGroups} and 2A/2B groups, this function + * makes the same output possible with limited input needed from + * the application. + * <p> + * Included in the RadioText information is an RDS/RBDS program type (PTY), + * and a single string of up to 64 characters. The program type (PTY) is used + * to describe the content being transmitted and follows the RDS/RBDS program + * types described in the RDS/RBDS specifications. + * <p> + * RadioText information also includes a string that consists of up to 64 + * characters. This string can be used to display any information, but is + * typically used to display information about the audio being transmitted. + * This RadioText string is expected to be at 64 characters in length, or less + * than 64 characters and terminated by a return carriage (0x0D). All strings + * passed to this function must be terminated by a null character (0x00). + * <p> + * <p> + * Maximux Radio Text string length that can be sent is + * FM_TX_MAX_RT_LEN. If the application sends RT string longer than + * this threshold, string will be truncated to FM_TX_MAX_RT_LEN. + * + * @param rtStr the Radio Text string to transmit + * @param pty the program type to use in the Radio text + * transmissions. + * @param pi the program identifier to use in the Radio text + * transmissions. + * + * @return true if RT information String was successfully sent + * to the driver, false if RT information string + * could not be sent to the driver. + * + * @see #stopRTInfo + */ + public boolean startRTInfo(String rtStr, int pty, int pi){ + + if((pty < 0) || (pty > 31 )) { + Log.d(TAG,"pTy is expected from 0 to 31"); + return false; + } + //Set the PTY + int err = FmReceiverJNI.setPTYNative( sFd, pty ); + if( err < 0 ){ + Log.d(TAG,"setPTYNative is failure"); + return false; + } + + if((pi < 0) || (pi > 65535)) { + Log.d(TAG,"pi is expected from 0 to 65535"); + return false; + } + + err = FmReceiverJNI.setPINative( sFd, pi ); + if( err < 0 ){ + Log.d(TAG,"setPINative is failure"); + return false; + } + + + if( rtStr.length() > FM_TX_MAX_RT_LEN ) + { + //truncate it to max length + rtStr = rtStr.substring( 0, FM_TX_MAX_RT_LEN ); + } + + err = FmReceiverJNI.startRTNative( sFd, rtStr, rtStr.length() ); + + if( err < 0 ){ + Log.d(TAG, "FmReceiverJNI.startRTNative returned false\n"); + return false; + } else { + Log.d(TAG,"mRTStarted is true"); + mRTStarted = true; + return true; + } + } + + /*============================================================== + FUNCTION: stopRTInfo + ==============================================================*/ + /** + * Stops an active Radio Text information transmission. + * + * <p> + * This is a synchrnous function used to stop an active Radio Text + * transmission started by {@link #startRTInfo}. + * + * @return true if Stop RT information was successfully sent to + * the driver, false if Stop RT information could not + * be sent to the driver. + * + * @see #startRTInfo + * + */ + public boolean stopRTInfo(){ + + if( FmReceiverJNI.stopRTNative( sFd ) < 0 ){ + Log.d(TAG,"stopRTNative is failure"); + return false; + } else{ + Log.d(TAG,"mRTStarted is false"); + mRTStarted = false; + return true; + } + } + + /*============================================================== + FUNCTION: getRdsGroupBufSize + ==============================================================*/ + /** + * Get the maximum number of RDS/RBDS groups which can be passed + * to the FM driver. + * <p> + * This is a function used to determine the maximum RDS/RBDS + * buffer size for use when calling {@link #transmitRdsGroups} + * + * @return the maximum number of RDS/RBDS groups which can be + * passed to the FM driver at any one time. + * + */ + public int getRdsGroupBufSize(){ + + return MAX_RDS_GROUP_BUF_SIZE; + } + + + /*============================================================== + FUNCTION: transmitRdsGroups + ==============================================================*/ + /** + * This function will transmit RDS/RBDS groups + * over an already tuned station. + * This is an asynchronous function used to transmit RDS/RBDS + * groups over an already tuned station. This functionality is + * is currently unsupported. + * <p> + * This function accepts a buffer (rdsGroups) containing one or + * more RDS groups. When sending this buffer, the application + * must also indicate how many groups should be taken from this + * buffer (numGroupsToTransmit). It may be possible that the FM + * driver can not accept the number of group contained in the + * buffer and will indicate how many group were actually + * accepted through the return value. + * + * <p> + * The FM driver will indicate to the application when it is + * ready to accept more data via both the + * "onRDSGroupsAvailable()" and "onRDSGroupsComplete()" events + * callbacks. The "onRDSGroupsAvailable()" callback will + * indicate to the application that the FM driver can accept + * additional groups even though all groups may not have been + * passed to the FM transmitter. The onRDSGroupsComplete() + * callback will indicate when the FM driver has a complete + * buffer to transmit RDS data. In many cases all data passed to + * the FM driver will be passed to the FM hardware and only a + * onRDSGroupsComplete() event will be generated by the + * FM driver. + * <p> If the application attempts to send more groups than the + * FM driver can handle, the application must wait until it + * receives a onRDSGroupsAvailable or a onRDSGroupsComplete + * event before attempting to transmit more groups. Failure to + * do so may result in no group being consumed by the FM driver. + * <p> It is important to note that switching between continuous + * and non-continuous transmission of RDS groups can only happen + * when no RDS/RBDS group transmission is underway. If an + * RDS/RBDS group transmission is already underway, the + * application must wait for a onRDSGroupsComplete. If the application + * wishes to switch from continuous to non-continuous (or + * vice-versa) without waiting for the current transmission to + * complete, the application can clear all remaining groups + * using the {@link #transmitRdsGroupControl} command. + * <p> + * Once completed, this command will generate a + * onRDSGroupsComplete event to all registered applications. + * + * @param rdsGroups The RDS/RBDS groups buffer to transmit. + * @param numGroupsToTransmit The number of groups in the buffer + * to transmit. + * + * @return The number of groups the FM driver actually accepted. + * A value >0 indicates the command was successfully + * accepted and a return value of "-1" indicates error. + * + * @see #transmitRdsGroupControl + */ + + public int transmitRdsGroups(byte[] rdsGroups, long numGroupsToTransmit){ + /* + * This functionality is currently unsupported + */ + + return -1; + } + /*============================================================== + FUNCTION: transmitContRdsGroups + ==============================================================*/ + /** + * This function will continuously transmit RDS/RBDS groups over an already tuned station. + * <p> + * This is an asynchronous function used to continuously + * transmit RDS/RBDS groups over an already tuned station. + * This functionality is currently unsupported. + * <p> + * This function accepts a buffer (rdsGroups) containing one or + * more RDS groups. When sending this buffer, the application + * must also indicate how many groups should be taken from this + * buffer (numGroupsToTransmit). It may be possible that the FM + * driver can not accept the number of group contained in the + * buffer and will indicate how many group were actually + * accepted through the return value. + * + * <p> + * Application can send a complete RDS group buffer for the transmission. + * This data will be sent continuously to the driver. Only single RDS + * group can be continuously transmitter at a time. So, application has to + * send the complete RDS buffer it intends to transmit. trying to pass the + * single buffer in two calls will be interprted as two different RDS/RBDS + * groups and hence all the unset groups will be cleared. + * <p> + * As continuous RDS/RBDS group transmission is done over single buffer, + * Application has to wait for the "onContRDSGroupsComplete()" callback + * to initiate the further RDS/RBDS group transmissions. Failure to + * do so may result in no group being consumed by the FM driver. + * <p> It is important to note that switching between continuous + * and non-continuous transmission of RDS groups can only happen + * when no RDS/RBDS group transmission is underway. If an + * RDS/RBDS group transmission is already underway, the + * application must wait for a onRDSGroupsComplete or onContRDSGroupsComplete. + * If the application wishes to switch from continuous to non-continuous (or + * vice-versa) without waiting for the current transmission to + * complete, the application can clear all remaining groups + * using the {@link #transmitRdsGroupControl} command. + * <p> + * Once completed, this command will generate a + * onRDSContGroupsComplete event to all registered applications. + * + * @param rdsGroups The RDS/RBDS groups buffer to transmit. + * @param numGroupsToTransmit The number of groups in the buffer + * to transmit. + * + * @return The number of groups the FM driver actually accepted. + * A value >0 indicates the command was successfully + * accepted and a return value of "-1" indicates error. + * + * @see #transmitRdsGroupControl + */ + + public int transmitRdsContGroups(byte[] rdsGroups, long numGroupsToTransmit){ + /* + * This functionality is currently unsupported. + */ + return -1; + } + + /*============================================================== + FUNCTION: transmitRdsGroupControl + ==============================================================*/ + /** + * Pause/Resume RDS/RBDS group transmission, or stop and clear + * all RDS groups. + * <p> + * This is a function used to pause/resume RDS/RBDS + * group transmission, or stop and clear all RDS groups. This + * function can be used to control continuous and + * non-continuous RDS/RBDS group transmissions. This functionality + * is currently unsupported. + * <p> + * @param ctrlCmd The Tx RDS group control.This should be one of the + * contants RDS_GRPS_TX_PAUSE/RDS_GRPS_TX_RESUME/RDS_GRPS_TX_STOP + * + * @return true if RDS Group Control command was + * successfully sent to the driver, false if RDS + * Group Control command could not be sent to the + * driver. + * + * @see #rdsGroupControlCmdType + * @see #transmitRdsGroups + */ + public boolean transmitRdsGroupControl(int ctrlCmd){ + boolean bStatus = true; + /* + * This functionality is currently unsupported. + */ + int val = 0; + switch( ctrlCmd ) { + case RDS_GRPS_TX_PAUSE:break; + case RDS_GRPS_TX_RESUME:break; + case RDS_GRPS_TX_STOP:break; + default: + /*Shouldn't reach here*/ + bStatus = false; + } + return bStatus; + } + + /*============================================================== + FUNCTION: setTxPowerLevel + ==============================================================*/ + /** + * Sets the transmitter power level. + * + * <p> + * This is a function used for setting the power level of + * Tx device. + * <p> + * @param powLevel The Tx power level value to be set. The value should be + * in range 0-7.If input is -ve level will be set to 0 + * and if it is above 7 level will be set to max i.e.,7. + * + * @return true on success, false on failure. + * + */ + public boolean setTxPowerLevel(int powLevel){ + boolean bStatus = true; + int err = FmReceiverJNI.setTxPowerLevelNative( sFd, powLevel ); + if( err < 0 ){ + Log.d(TAG,"setTxPowerLevel is failure"); + return false; + } + return bStatus; + } + + /* + * 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; + } +}; diff --git a/qcom/fmradio/FmTransmitterCallbacks.java b/qcom/fmradio/FmTransmitterCallbacks.java new file mode 100644 index 0000000..a868c29 --- /dev/null +++ b/qcom/fmradio/FmTransmitterCallbacks.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011-2012, 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; + /** @hide + * The interface that provides the applications to get callback + * for asynchronous events. + * An Adapter that implements this interface needs to be used to + * register to receive the callbacks using {@link + * #FmTransmitter}. + * <p> + * Application has to register for these callbacks by sending + * a valid instance of TransmitterCallbacks's adapter while + * instantiating the FMTransmitter. + * + * @see #FmTransmitter + */ + public interface FmTransmitterCallbacks + { + /** + * The callback indicates that the transmitter is tuned to a + * new frequency Typically received after setStation. + */ + public void FmTxEvTuneStatusChange(int freq); + + /** + * The callback to indicate to the application that the FM + * driver can accept additional groups even though all groups + * may not have been passed to the FM transmitter. + * + * Application can start to send down the remaining groups + * to the available group buffers upon recieving this callback. + */ + public void FmTxEvRDSGroupsAvailable(); + /** + * The callback will indicate the succesful completion of #transmitRdsGroups. + * This indicates that the FM driver has a complete buffer to transmit the + * RDS/RBDS data to the Application. Application can free to switch between continuous or + * non-continuous RDS/RBDS group transmissions. + */ + public void FmTxEvRDSGroupsComplete(); + /** + * The callback will indicate the succesful completion of #transmitRdsContGroups. + * This indicates that the FM driver has a complete buffer to transmit the + * RDS/RBDS data to the Application. Application can free to switch between continuous or + * non-continuous RDS/RBDS group transmissions. + * + */ + public void FmTxEvContRDSGroupsComplete(); + /** + * The callback indicates that Radio has been Disabled. + * This indicates that the FM driver has disabled the radio. + * + */ + public void FmTxEvRadioDisabled(); + /** + * The callback indicates that Radio has been Enabled. + * This indicates that the FM driver has Enabled the radio. + * + */ + public void FmTxEvRadioEnabled(); + /** + * The callback indicates that Radio has been Reset. + * This indicates that the FM driver has reset the radio. + * + */ + public void FmTxEvRadioReset(); + }; diff --git a/qcom/fmradio/FmTransmitterCallbacksAdaptor.java b/qcom/fmradio/FmTransmitterCallbacksAdaptor.java new file mode 100644 index 0000000..8e30bd5 --- /dev/null +++ b/qcom/fmradio/FmTransmitterCallbacksAdaptor.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011-2012, 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; + /** + * @hide + * Class to be implemented for Tx events callbacks + * + */ + public class FmTransmitterCallbacksAdaptor implements FmTransmitterCallbacks + { + public void FmTxEvTuneStatusChange(int freq) {}; + public void FmTxEvRDSGroupsAvailable() {}; + public void FmTxEvRDSGroupsComplete() {}; + public void FmTxEvContRDSGroupsComplete() {}; + public void FmTxEvRadioDisabled() {}; + public void FmTxEvRadioEnabled() {}; + public void FmTxEvRadioReset() {}; + }; + diff --git a/qcom/fmradio/FmTxEventListner.java b/qcom/fmradio/FmTxEventListner.java new file mode 100644 index 0000000..998ef30 --- /dev/null +++ b/qcom/fmradio/FmTxEventListner.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2011,2012, 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.util.Log; +import qcom.fmradio.FmTransceiver; + +class FmTxEventListner { + + + private final int EVENT_LISTEN = 1; + + private final int TUNE_EVENT = 1; /*Tune completion event*/ + private final int TXRDSDAT_EVENT = 16; /*RDS Group available event*/ + private final int TXRDSDONE_EVENT = 17; /*RDS group complete event */ + private final int RADIO_DISABLED = 18; + private final int READY_EVENT = 0; + private byte []buff = new byte[128]; + private Thread mThread; + private static final String TAG = "FMTxEventListner"; + + public void startListner (final int fd, final FmTransmitterCallbacks cb) { + /* start a thread and listen for messages */ + mThread = new Thread(){ + public void run(){ + + Log.d(TAG, "Starting Tx Event listener " + fd); + + while((!Thread.currentThread().isInterrupted())) { + try { + int index = 0; + int freq = 0; + Log.d(TAG, "getBufferNative called"); + int eventCount = FmReceiverJNI.getBufferNative + (fd, buff, EVENT_LISTEN); + Log.d(TAG, "Received event. Count: " + eventCount); + + for(index = 0; index < eventCount; index++) { + Log.d(TAG, "Received <" +buff[index]+ ">" ); + switch(buff[index]){ + case READY_EVENT: + Log.d(TAG, "Got RADIO_ENABLED"); + if(FmTransceiver.getFMPowerState() == + FmTransceiver.subPwrLevel_FMTx_Starting) { + /*Set the state as FMRxOn */ + FmTransceiver.setFMPowerState + (FmTransceiver.FMState_Tx_Turned_On); + Log.v(TAG, "TxEvtList: CURRENT-STATE:" + + "FMTxStarting ---> NEW-STATE : FMTxOn"); + cb.FmTxEvRadioEnabled(); + } + break; + case TUNE_EVENT: + Log.d(TAG, "Got TUNE_EVENT"); + freq = FmReceiverJNI.getFreqNative(fd); + if (freq > 0) + cb.FmTxEvTuneStatusChange(freq); + else + Log.e(TAG, "get frqency cmd failed"); + break; + case TXRDSDAT_EVENT: + Log.d(TAG, "Got TXRDSDAT_EVENT"); + cb.FmTxEvRDSGroupsAvailable(); + break; + case TXRDSDONE_EVENT: + Log.d(TAG, "Got TXRDSDONE_EVENT"); + cb.FmTxEvContRDSGroupsComplete(); + break; + case RADIO_DISABLED: + Log.d(TAG, "Got RADIO_DISABLED"); + if(FmTransceiver.getFMPowerState() == + FmTransceiver.subPwrLevel_FMTurning_Off) { + /*Set the state as FMOff */ + FmTransceiver.setFMPowerState + (FmTransceiver.FMState_Turned_Off); + Log.v(TAG, "TxEvtList:CURRENT-STATE :" + + "FMTurningOff ---> NEW-STATE: FMOff"); + FmTransceiver.release("/dev/radio0"); + cb.FmTxEvRadioDisabled(); + Thread.currentThread().interrupt(); + } else { + Log.d(TAG, "Unexpected RADIO_DISABLED recvd"); + cb.FmTxEvRadioReset(); + } + break; + default: + Log.d(TAG, "Unknown event"); + break; + }//switch + }//for + }catch (Exception ex) { + Log.d( TAG, "RunningThread InterruptedException"); + Thread.currentThread().interrupt(); + }//try + }//while + Log.d(TAG, "Came out of the while loop"); + } + }; + mThread.start(); + } + + public void stopListener(){ + Log.d(TAG, "Thread Stopped\n"); + //Thread stop is deprecate API + //Interrupt the thread and check for the thread status + // and return from the run() method to stop the thread + //properly + Log.d(TAG, "stopping the Listener\n"); + + if(mThread != null) { + mThread.interrupt(); + } + Log.d(TAG, "Thread Stopped\n"); + } +} |