/* * Copyright (c) 2009,2012-2014, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of The Linux Foundation nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package qcom.fmradio; import android.util.Log; import android.os.SystemProperties; /** * This class contains all interfaces and types needed to * Control the FM receiver. * @hide */ public class FmReceiver extends FmTransceiver { public static int mSearchState = subSrchLevel_NoSearch; 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 V4L2_CTRL_CLASS_USER = 0x00980000; private static final int V4L2_CID_PRIVATE_IRIS_GET_SPUR_TBL = (V4L2_CTRL_CLASS_USER + 0x92E); private static final int TAVARUA_BUF_SRCH_LIST=0; private static final int TAVARUA_BUF_EVENTS=1; private static final int TAVARUA_BUF_RT_RDS=2; private static final int TAVARUA_BUF_PS_RDS=3; private static final int TAVARUA_BUF_RAW_RDS=4; private static final int TAVARUA_BUF_AF_LIST=5; private static final int TAVARUA_BUF_MAX=6; 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; /** * Search Algo type */ private static final int SEARCH_MPXDCC = 0; private static final int SEARCH_SINR_INT = 1; /** * 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. *

* @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. *

* 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. *

* 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. *

* The client can choose which events will be sent from the * receiver driver by simply implementing functions for events * it wishes to receive. *

* @param callback the callbacks 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 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. *

* @return true Always returns true. *

* @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. *

* 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. *

* 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}. *

* 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}. *

* @param configSettings the settings to be applied when * turning on the radio * @return true if Initialization succeeded, false if * Initialization failed. *

* @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; }else if ((state == FMState_Tx_Turned_On) || (state == subPwrLevel_FMTx_Starting)) { Log.v(TAG, "FM Tx is turned on or in the process of turning on."); return status; } setFMPowerState(subPwrLevel_FMRx_Starting); Log.v(TAG, "enable: CURRENT-STATE : FMOff ---> NEW-STATE : FMRxStarting"); status = super.enable(configSettings, FmTransceiver.FM_RX); if( status == true ) { /* 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. *

* 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}. *

* @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. *

* 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}. *

* @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. *

* 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. *

* @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. *

* 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. *

* @return none */ static void setSearchState(int state) { mSearchState = state; switch(mSearchState) { case subSrchLevel_SeekInPrg: case subSrchLevel_ScanInProg: case subSrchLevel_SrchListInProg: setFMPowerState(FMState_Srch_InProg); break; case subSrchLevel_SrchComplete: /* Update the state of the FM device */ mSearchState = subSrchLevel_NoSearch; setFMPowerState(FMState_Rx_Turned_On); break; case subSrchLevel_SrchAbort: break; default: mSearchState = subSrchLevel_NoSearch; break; } } /*============================================================== FUNCTION: searchStations ==============================================================*/ /** * Initiates basic seek and scan operations. *

* This command is used to invoke a basic seek/scan of the FM * radio band. *

*

*

* 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. *

* Since seek always results in a frequency being tuned, each * seek operation will also return a single * FmRxEvRadioTuneStatus event to the client/application * layer. *

* 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. *

* 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. *

* Once issuing a search command, several commands from the client * may be disallowed until the search is completed or cancelled. *

* 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': *

*

* Valid Values for argument 'dwellPeriod' : *

*

* Valid Values for argument 'direction' : *

*

* *

* @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. *

* @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. * *

* 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. * *

*

* *

* 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. * *

* 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. * *

{@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. * *

* 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. * *

* 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. * *

* Once issuing a search command, several commands from the client may be * disallowed until the search is completed or canceled. * *

* 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': *

*

* Valid Values for argument 'dwellPeriod' : *

*

* Valid Values for argument 'direction' : *

*

* @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 *

* @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. *

This method will initate a search that will generate * frequency lists based on strong and weak stations found in * the FM band. *

*

*

* 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. *

* 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. *

* 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. *

* Once issuing a search command, several commands from the client may be * disallowed until the search is completed or cancelled. *

* 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. *

* Valid Values for argument 'mode': *

*

* Valid Values for argument 'direction' : *

*

* Valid Values for argument 'maximumStations' : 1-12 *

* @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) *

* @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). *

* This method should be used to cancel a previously initiated * search (e.g. Basic Seek/Scan, RDS Seek/Scans, Search list, * etc...). *

* 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. * *

* @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. *

* 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. *

* @param mode the mute Mode setting to apply *

* @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. * *

* 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. * *

* 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. *

* 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. *

* @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. * *

* 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. * *

* Once completed, this command will generate an asynchronous * FmRxEvStationParameters event to the registered client. * This event will contain the station parameters. * *

* @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. *

* 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. * *

* @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. * *

* 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. * *

* Typicaly this method needs to be called when * "FmRxEvRdsRtInfo" callback is invoked. * *

* @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, count, avail_tag_num = 0; 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); avail_tag_num = (rt_plus[LEN_IND] - 2)/3; if (avail_tag_num > 2) { avail_tag_num = 2; } count = 1; for (i = 0; i < avail_tag_num; i++) { tag_code = rt_plus[2+3*i]; tag_start_pos = rt_plus[3+3*i]; tag_len = rt_plus[4+3*i]; if (((tag_len + tag_start_pos) <= rt_len) && (tag_code > 0)) { mRdsData.setTagValue(rt.substring(tag_start_pos, (tag_len + tag_start_pos)), count); mRdsData.setTagCode(tag_code, count); count++; } } } else { mRdsData.setTagNums(0); } } else { mRdsData.setTagNums(0); } return mRdsData; } public FmRxRdsData getERTInfo() { byte [] raw_ert = new byte[STD_BUF_SIZE]; byte [] ert_text; int i; String s = ""; String encoding_type = "UCS-2"; int bytes_read; 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; } public boolean IsSmdTransportLayer() { String transportLayer = SystemProperties.get("ro.qualcomm.bt.hci_transport"); if (transportLayer.equals("smd")) return true; else return false; } public boolean IsRomeChip() { String chip = SystemProperties.get("qcom.bluetooth.soc"); if (chip.equals("rome")) return true; else return false; } /*============================================================== FUNCTION: getAFInfo ==============================================================*/ /** * Returns the current RDS/RBDS Alternative Frequency * Information. * *

* 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. * *

* Typicaly this method needs to be called when * "FmRxEvRdsAfInfo" callback is invoked. * * @return the RDS data including the AF Information */ public int[] getAFInfo() { byte [] buff = new byte[STD_BUF_SIZE]; int [] AfList = new int [50]; int lowerBand, i; int tunedFreq, PI, size_AFLIST; FmReceiverJNI.getBufferNative(sFd, buff, TAVARUA_BUF_AF_LIST); if (IsSmdTransportLayer() || IsRomeChip()) { Log.d(TAG, "SMD transport layer or Rome chip"); tunedFreq = (buff[0] & 0xFF) | ((buff[1] & 0xFF) << 8) | ((buff[2] & 0xFF) << 16) | ((buff[3] & 0xFF) << 24) ; Log.d(TAG, "tunedFreq = " +tunedFreq); PI = (buff[4] & 0xFF) | ((buff[5] & 0xFF) << 8); Log.d(TAG, "PI: " + PI); size_AFLIST = buff[6] & 0xFF; Log.d(TAG, "size_AFLIST : " +size_AFLIST); for (i = 0;i < size_AFLIST;i++) { AfList[i] = (buff[6 + i * 4 + 1] & 0xFF) | ((buff[6 + i * 4 + 2] & 0xFF) << 8) | ((buff[6 + i * 4 + 3] & 0xFF) << 16) | ((buff[6 + i * 4 + 4] & 0xFF) << 24) ; Log.d(TAG, "AF: " + AfList[i]); } } else { if ((buff[4] <= 0) || (buff[4] > 25)) return null; lowerBand = FmReceiverJNI.getLowerBandNative(sFd); Log.d (TAG, "Low band " + lowerBand); Log.d (TAG, "AF_buff 0: " + (buff[0] & 0xff)); Log.d (TAG, "AF_buff 1: " + (buff[1] & 0xff)); Log.d (TAG, "AF_buff 2: " + (buff[2] & 0xff)); Log.d (TAG, "AF_buff 3: " + (buff[3] & 0xff)); Log.d (TAG, "AF_buff 4: " + (buff[4] & 0xff)); for (i=0; i * 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. * *

* 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. * *

* @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. *

* This is an synchronous method that will read the power mode * of the FM device and driver. *

* @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. * *

* 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. * *

* 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. * *

* @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 *

* 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. * *

* 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. * *

* Once completed, this command will generate an asynchronous * FmRxEvGetSignalThreshold event to the registered client. * This event will contain the current signal threshold * level. * *

* @return the signal threshold */ public int getSignalThreshold () { int state = getFMState(); /* Check current state of FM device */ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) { Log.d(TAG, "getSignalThreshold: Device currently busy in executing another command."); return ERROR; } int threshold = FM_RX_SIGNAL_STRENGTH_VERY_WEAK, signalStrength; int rmssiThreshold = FmReceiverJNI.getControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH); Log.d(TAG, "Signal Threshhold: "+rmssiThreshold ); if ( (FM_RX_RSSI_LEVEL_VERY_WEAK < rmssiThreshold) && (rmssiThreshold <= FM_RX_RSSI_LEVEL_WEAK) ) { signalStrength = FM_RX_RSSI_LEVEL_WEAK; } else if ( (FM_RX_RSSI_LEVEL_WEAK < rmssiThreshold) && (rmssiThreshold <= FM_RX_RSSI_LEVEL_STRONG)) { signalStrength = FM_RX_RSSI_LEVEL_STRONG; } else if ((FM_RX_RSSI_LEVEL_STRONG < rmssiThreshold)) { signalStrength = FM_RX_RSSI_LEVEL_VERY_STRONG; } else { signalStrength = FM_RX_RSSI_LEVEL_VERY_WEAK; } switch(signalStrength) { case FM_RX_RSSI_LEVEL_VERY_WEAK: threshold = FM_RX_SIGNAL_STRENGTH_VERY_WEAK; break; case FM_RX_RSSI_LEVEL_WEAK: threshold = FM_RX_SIGNAL_STRENGTH_WEAK; break; case FM_RX_RSSI_LEVEL_STRONG: threshold = FM_RX_SIGNAL_STRENGTH_STRONG; break; case FM_RX_RSSI_LEVEL_VERY_STRONG: threshold = FM_RX_SIGNAL_STRENGTH_VERY_STRONG; break; default: /* Should never reach here */ break; } return threshold; } public int getAFJumpRmssiTh() { int state = getFMState(); /* Check current state of FM device */ if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getAFJumpThreshold: Device currently busy in executing another command."); return ERROR; } return mControl.getAFJumpRmssiTh(sFd); } public boolean setAFJumpRmssiTh(int th) { int state = getFMState(); /* Check current state of FM device */ if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setAFJumpThreshold: Device currently busy in executing another command."); return false; } return mControl.setAFJumpRmssiTh(sFd, th); } public int getAFJumpRmssiSamples() { int state = getFMState(); /* Check current state of FM device */ if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getAFJumpRmssiSamples: Device currently busy in executing another command."); return ERROR; } return mControl.getAFJumpRmssiSamples(sFd); } public boolean setAFJumpRmssiSamples(int samples) { int state = getFMState(); /* Check current state of FM device */ if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setAFJumpRmssiSamples: Device currently busy in executing another command."); return false; } return mControl.setAFJumpRmssiSamples(sFd, samples); } public int getGdChRmssiTh() { int state = getFMState(); /* Check current state of FM device */ if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getGdChRmssiTh: Device currently busy in executing another command."); return ERROR; } return mControl.getGdChRmssiTh(sFd); } public boolean setGdChRmssiTh(int th) { int state = getFMState(); /* Check current state of FM device */ if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setGdChRmssiTh: Device currently busy in executing another command."); return false; } return mControl.setGdChRmssiTh(sFd, th); } public int getSearchAlgoType() { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getSearchAlgoType: Device currently busy in executing another command."); return Integer.MAX_VALUE; } return mControl.getSearchAlgoType(sFd); } public boolean setSearchAlgoType(int searchType) { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setSearchAlgoType: Device currently busy in executing another command."); return false; } if((searchType != SEARCH_MPXDCC) && (searchType != SEARCH_SINR_INT)) { Log.d(TAG, "Search Algo is invalid"); return false; }else { return mControl.setSearchAlgoType(sFd, searchType); } } public int getSinrFirstStage() { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getSinrFirstStage: Device currently busy in executing another command."); return Integer.MAX_VALUE; } return mControl.getSinrFirstStage(sFd); } public boolean setSinrFirstStage(int sinr) { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setSinrFirstStage: Device currently busy in executing another command."); return false; } return mControl.setSinrFirstStage(sFd, sinr); } public int getRmssiFirstStage() { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getRmssiFirstStage: Device currently busy in executing another command."); return Integer.MAX_VALUE; } return mControl.getRmssiFirstStage(sFd); } public boolean setRmssiFirstStage(int rmssi) { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setRmssiFirstStage: Device currently busy in executing another command."); return false; } return mControl.setRmssiFirstStage(sFd, rmssi); } public int getCFOMeanTh() { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getCF0Th12: Device currently busy in executing another command."); return Integer.MAX_VALUE; } return mControl.getCFOMeanTh(sFd); } public boolean setCFOMeanTh(int th) { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setRmssiFirstStage: Device currently busy in executing another command."); return false; } return mControl.setCFOMeanTh(sFd, th); } public boolean setPSRxRepeatCount(int count) { int state = getFMState(); /* Check current state of FM device */ if (state == FMState_Turned_Off){ Log.d(TAG, "setRxRepeatcount failed"); return false; } return mControl.setPSRxRepeatCount(sFd, count); } public byte getBlendSinr() { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getBlendSinr: Device currently busy in executing another command."); return Byte.MAX_VALUE; } return mControl.getBlendSinr(sFd); } public boolean setBlendSinr(byte sinrHi) { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setBlendSinr: Device currently busy in executing another command."); return false; } return mControl.setBlendSinr(sFd, sinrHi); } public byte getBlendRmssi() { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "getBlendRmssi: Device currently busy in executing another command."); return Byte.MAX_VALUE; } return mControl.getBlendRmssi(sFd); } public boolean setBlendRmssi(byte rmssiHi) { int state = getFMState(); if ((state == FMState_Turned_Off) || (state == FMState_Srch_InProg)) { Log.d(TAG, "setBlendRmssi: Device currently busy in executing another command."); return false; } return mControl.setBlendRmssi(sFd, rmssiHi); } /*============================================================== FUNCTION: setRdsGroupOptions ==============================================================*/ /** * * This function enables or disables various RDS/RBDS * group filtering and buffering features. * *

* Included in these features are the RDS group enable mask, RDS/RBDS group * change filter, and the RDS/RBDS group buffer size. *

* This is a function used to set or unset various Rx RDS/RBDS group filtering * and buffering options in the FM driver. *

* 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. * *

* 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. * *

* @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. * *

* Included in these features is the ability for the FM driver * to return Program Service, RadioText, and Alternative * Frequency information. * *

* 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. * *

* 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. * *

* 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. * *

* 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 * *

* 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. * *

* @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. * *

* This method retreives the results of the {@link * #searchStationList}. This method should be called when the * FmRxEvSearchListComplete is invoked. * *

* @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 * *

* This method returns the signal strength of the currently * tuned station. * *

* @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 * *

* This method returns the Estimated Interference Over Carrier of the currently * tuned station. * *

* @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 * *

* This method returns the IntDet of the currently * tuned station. * *

* @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 * *

* This method returns the MPX_DCC of the currently * tuned station. * *

* @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 * *

* This method sets the hi-low injection. * *

*/ public void setHiLoInj(int inj) { int re = mControl.setHiLoInj(sFd, inj); } /*============================================================== FUNCTION: getRmssiDelta ==============================================================*/ /** * Gets the value of currently set RMSSI Delta * *

* This method gets the currently set RMSSI Delta value. * *

*/ 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 * *

* This method sets the RMSSI Delta. * *

*/ public void setRmssiDel(int delta) { int re = mControl.setRmssiDel(sFd, delta); } /*============================================================== FUNCTION: getRawRDS ==============================================================*/ /** * Returns array of Raw RDS data * *

* 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 * *

* @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 * *

* This method sets the On channel threshold value. * *

*/ 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 * *

* This method gets the currently set On channel threshold value. * *

*/ public int getOnChannelThreshold() { return mControl.getOnChannelThreshold(sFd); } /*============================================================== FUNCTION: setOffChannelThreshold ==============================================================*/ /** * Sets the Off channel threshold value * *

* This method sets the Off channel threshold value. * *

*/ 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 * *

* This method gets the currently set Off channel threshold value. * *

*/ public int getOffChannelThreshold() { return mControl.getOffChannelThreshold(sFd); } /*=============================================================== FUNCTION: getSINR ==============================================================*/ /** * Gets the SINR value of currently tuned station * *

* This method gets the SINR value for currently tuned station. * *

*/ 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 * *

* This method sets the SINR threshold value. * *

*/ 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 * *

* This method gets the currently set SINR threshold value. * *

*/ public int getSINRThreshold() { return mControl.getSINRThreshold(sFd); } /*============================================================== FUNCTION: setRssiThreshold ==============================================================*/ /** * Sets the RSSI threshold value * *

* This method sets the RSSI threshold value. * *

*/ public boolean setRssiThreshold(int data) { int re = mControl.setRssiThreshold(sFd, data); if (re < 0) return false; else return true; } /*============================================================== FUNCTION: getRssiThreshold ==============================================================*/ /** * Gets the Rssi threshold value * *

* This method gets the currently set Rssi threshold value. * *

*/ public int getRssiThreshold() { return mControl.getRssiThreshold(sFd); } /*============================================================== FUNCTION: setAfJumpRssiThreshold ==============================================================*/ /** * Sets the Af jump RSSI threshold value * *

* This method sets the AF jump RSSI threshold value. * *

*/ public boolean setAfJumpRssiThreshold(int data) { int re = mControl.setAfJumpRssiThreshold(sFd, data); if (re < 0) return false; else return true; } /*============================================================== FUNCTION: getAfJumpRssiThreshold ==============================================================*/ /** * Gets the Af jump RSSI threshold value * *

* This method gets the currently set AF jump RSSI threshold value. * *

*/ public int getAfJumpRssiThreshold() { return mControl.getAfJumpRssiThreshold(sFd); } /*============================================================== FUNCTION: setRdsFifoCnt ==============================================================*/ /** * Sets the RDS FIFO count value * *

* This method sets the RDS FIFO count value. * *

*/ public boolean setRdsFifoCnt(int data) { int re = mControl.setRdsFifoCnt(sFd, data); if (re < 0) return false; else return true; } /*============================================================== FUNCTION: getRdsFifoCnt ==============================================================*/ /** * Gets the RDS FIFO count value * *

* This method gets the currently set RDS FIFO count value. * *

*/ public int getRdsFifoCnt() { return mControl.getRdsFifoCnt(sFd); } /*============================================================== FUNCTION: setSINRsamples ==============================================================*/ /** * Sets the SINR samples * *

* This method sets the number of SINR samples to calculate the SINR value. * *

*/ 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 * *

* This method gets the number of currently set SINR samples. * *

*/ public int getSINRsamples() { return mControl.getSINRsamples(sFd); } public int updateSpurFreq(int freq, int rmssi, boolean enable) { return mControl.updateSpurTable(sFd, freq, rmssi, enable); } public int configureSpurTable() { return mControl.configureSpurTable(sFd); } public static int getSpurConfiguration(int freq) { int retval; retval = FmReceiverJNI.setControlNative(sFd, V4L2_CID_PRIVATE_IRIS_GET_SPUR_TBL, freq); if (retval !=0) Log.d(TAG, "Failed/No Spurs for " +freq); return retval; } public static void getSpurTableData() { int freq; byte no_of_spurs; int rotation_value; byte lsbOfLen; byte filterCoe; byte isEnbale; byte [] buff = new byte[STD_BUF_SIZE]; int i = 0; FmReceiverJNI.getBufferNative(sFd, buff, 13); freq = buff[0] & 0xFF; freq |= ((buff[1] & 0xFF) << 8); freq |= ((buff[2] & 0xFF) << 16); Log.d (TAG, "freq = " +freq); no_of_spurs = buff[3]; Log.d (TAG, "no_of_spurs = " + no_of_spurs); for(i = 0; i < FmConfig.no_Of_Spurs_For_Entry; i++) { rotation_value = buff[(i * 4) + 4] & 0xFF; rotation_value |= ((buff[(i * 4) + 5] & 0xFF) << 8); rotation_value |= ((buff[(i * 4) + 6] & 0x0F) << 12); Log.d (TAG, "rotation_value = " +rotation_value); lsbOfLen = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 4) & 0x01); Log.d (TAG, "lsbOfLen = "+lsbOfLen); filterCoe = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 5) & 0x03); Log.d (TAG, "filterCoe = " +filterCoe); isEnbale = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 7) & 0x01); Log.d (TAG, "spur level: " +buff[(i * 4) + 7]); } return; } }