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/fmradio/FmReceiver.java | |
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/fmradio/FmReceiver.java')
-rw-r--r-- | qcom/fmradio/FmReceiver.java | 2342 |
1 files changed, 2342 insertions, 0 deletions
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); + } +} |