diff options
author | xinyu <ac.milan@miui.com> | 2010-10-12 18:57:14 +0800 |
---|---|---|
committer | Steve Kondik <shade@chemlab.org> | 2010-10-12 22:09:36 -0400 |
commit | 350dcf82f0c95d15ae286240d9792a6d90891f4e (patch) | |
tree | 8e270fe5ceb4476b147f6fe81fef14c838807411 /core | |
parent | e1237a907ec418a830ae369069aae6715d5dc844 (diff) | |
download | frameworks_base-350dcf82f0c95d15ae286240d9792a6d90891f4e.zip frameworks_base-350dcf82f0c95d15ae286240d9792a6d90891f4e.tar.gz frameworks_base-350dcf82f0c95d15ae286240d9792a6d90891f4e.tar.bz2 |
support FM Radio audio routing in audio flinger
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/hardware/fmradio/FmConfig.java | 188 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmReceiver.java | 1684 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmReceiverJNI.java | 176 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmRxControls.java | 313 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmRxEvCallbacks.java | 46 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmRxEvCallbacksAdaptor.java | 52 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmRxEventListner.java | 153 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmRxRdsData.java | 204 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmTransceiver.java | 446 | ||||
-rw-r--r-- | core/java/android/hardware/fmradio/FmTransmitter.java | 584 | ||||
-rw-r--r-- | core/jni/Android.mk | 5 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 7 | ||||
-rw-r--r-- | core/jni/android_hardware_fm.cpp | 427 |
13 files changed, 4285 insertions, 0 deletions
diff --git a/core/java/android/hardware/fmradio/FmConfig.java b/core/java/android/hardware/fmradio/FmConfig.java new file mode 100644 index 0000000..c96e64c --- /dev/null +++ b/core/java/android/hardware/fmradio/FmConfig.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; + +import android.util.Log; + + +/** + * + * Class to be used when changing radio settings + * @hide + */ +public class FmConfig { + + + /** + * FMConfigure FM Radio band setting for US/Europe + */ + private static final int FM_US_BAND =0; + /** + * FMConfigure FM Radio band setting for US/Europe + */ + private static final int FM_EU_BAND =1; + /** + * FMConfigure FM Radio band setting for Japan + */ + private static final int FM_JAPAN_WIDE_BAND =2; + /** + * FMConfigure FM Radio band setting for Japan-Wideband + */ + private static final int FM_JAPAN_STANDARD_BAND =3; + /** + * FMConfigure FM Radio band setting for "User defined" band + */ + private static final int FM_USER_DEFINED_BAND =4; + + private static final int V4L2_CID_PRIVATE_BASE =0x8000000; + private static final int V4L2_CID_PRIVATE_TAVARUA_REGION =V4L2_CID_PRIVATE_BASE + 7; + private static final int V4L2_CID_PRIVATE_TAVARUA_EMPHASIS =V4L2_CID_PRIVATE_BASE + 12; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDS_STD =V4L2_CID_PRIVATE_BASE + 13; + private static final int V4L2_CID_PRIVATE_TAVARUA_SPACING =V4L2_CID_PRIVATE_BASE + 14; + + private static final String TAG = "FmConfig"; + + + + private int mRadioBand; + /** + * FM pre-emphasis/de-emphasis + * + * Possible Values: + * + * FmTransceiver.FM_DE_EMP75, + * FmTransceiver.FM_DE_EMP50 + */ + private int mEmphasis; + /** + * Channel spacing + * + * Possible Values: + * + * FmTransceiver.FM_CHSPACE_200_KHZ, + * FmTransceiver.FM_CHSPACE_100_KHZ, + * FmTransceiver.FM_CHSPACE_50_KHZ + */ + private int mChSpacing; + + /** + * RDS standard type + * + * Possible Values: + * + * FmTransceiver.FM_RDS_STD_RBDS, + * FmTransceiver.FM_RDS_STD_RDS, + * FmTransceiver.FM_RDS_STD_NONE + */ + private int mRdsStd; + + /** + * FM Frequency Band Lower Limit in KHz + */ + private int mBandLowerLimit; + /** + * FM Frequency Band Upper Limit in KHz + */ + private int mBandUpperLimit; + + public int getRadioBand(){ + return mRadioBand; + } + + public void setRadioBand (int band){ + mRadioBand = band; + } + + public int getEmphasis(){ + return mEmphasis; + } + + public void setEmphasis (int emp){ + mEmphasis = emp; + } + + public int getChSpacing (){ + return mChSpacing; + } + + public void setChSpacing(int spacing) { + mChSpacing = spacing; + } + + public int getRdsStd () { + return mRdsStd; + } + + public void setRdsStd (int rdsStandard) { + mRdsStd = rdsStandard; + } + + public int getLowerLimit(){ + return mBandLowerLimit; + } + + public void setLowerLimit(int lowLimit){ + mBandLowerLimit = lowLimit; + } + + public int getUpperLimit(){ + return mBandUpperLimit; + } + + public void setUpperLimit(int upLimit){ + mBandUpperLimit = upLimit; + } + + /* + * fmConfigure() + * This method call v4l2 private controls to set regional settings for the + * FM core + */ + protected static boolean fmConfigure (int fd, FmConfig configSettings) { + + int re; + + Log.d (TAG, "In fmConfigure"); + + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_EMPHASIS, configSettings.getEmphasis()); + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_RDS_STD, configSettings.getRdsStd() ); + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SPACING, configSettings.getChSpacing() ); + re = FmReceiverJNI.setBandNative (fd, configSettings.getLowerLimit(), configSettings.getUpperLimit() ); + + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_REGION, FM_USER_DEFINED_BAND ); + + // setControlNative for V4L2_CID_PRIVATE_TAVARUA_REGION triggers the + // config change. + if (re < 0) + return false; + + return true; + } + +} diff --git a/core/java/android/hardware/fmradio/FmReceiver.java b/core/java/android/hardware/fmradio/FmReceiver.java new file mode 100644 index 0000000..047a713 --- /dev/null +++ b/core/java/android/hardware/fmradio/FmReceiver.java @@ -0,0 +1,1684 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; + +import android.util.Log; + +/** + * This class contains all interfaces and types needed to + * Control the FM receiver. + * @hide + */ +public class FmReceiver extends FmTransceiver +{ + + 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 = 1 second + * + * @see #searchStations(int, int, int) + * @see #searchStations(int, int, int, int, int) + */ + public static final int FM_RX_DWELL_PERIOD_1S=0; + /** + * 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=1; + /** + * 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=2; + /** + * 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=3; + /** + * 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=4; + /** + * 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=5; + /** + * 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=6; + + + /** + * 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 =-141; + public static final int FM_RX_SIGNAL_STRENGTH_WEAK =-126; + public static final int FM_RX_SIGNAL_STRENGTH_STRONG =-111; + public static final int FM_RX_SIGNAL_STRENGTH_VERY_STRONG=-96; + + /** + * 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_CID_PRIVATE_TAVARUA_ANTENNA = V4L2_CID_PRIVATE_BASE + 18; + + 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; + + + + + /** + * 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){ + mControl = new FmRxControls(); + mRxEvents = new FmRxEventListner(); + acquire(devicePath); + registerClient(callback); + mRdsData = new FmRxRdsData(sFd); + } + + + /*============================================================== + 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; + + /* Enable the Transceiver common for both + receiver and transmitter + */ + status = super.enable(configSettings, FmTransceiver.FM_RX); + + /* Do Receiver Specific Enable Stuff here.*/ + + return true; + } + + /*============================================================== + 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; + status = super.disable(); + + return true; + } + + /*============================================================== + 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){ + boolean bStatus = true; + + 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_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 + "direction: " + direction); + mControl.searchStations(sFd, mode, dwellPeriod, direction, 0, 0); + } + return true; + } + + /*============================================================== + 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; + + 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); + mControl.searchStations(sFd, mode, dwellPeriod, direction, pty, pi); + } + return true; + } + + /*============================================================== + 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 or cancellation 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 same events will be generated. However, the + * search list generated may only contain a partial list. + * <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){ + + boolean bStatus = true; + int re=0; + + 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) + { + if ( (mode == FM_RX_SRCHLIST_MODE_STRONGEST) || (mode == FM_RX_SRCHLIST_MODE_WEAKEST) ) + re = mControl.searchStationList(sFd, mode, 0, direction, pty); + else + re = mControl.searchStationList(sFd, mode, maximumStations, direction, pty); + } + + if (re == 0) + return true; + + return false; + } + + + + /*============================================================== + 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 () { + mControl.cancelSearch(sFd); + return true; + } + + /*============================================================== + 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) { + 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 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) { + + boolean bStatus = true; + int re; + + if ( (threshold != FM_RX_SIGNAL_STRENGTH_VERY_WEAK) && + (threshold != FM_RX_SIGNAL_STRENGTH_WEAK) && + (threshold != FM_RX_SIGNAL_STRENGTH_VERY_STRONG) && + (threshold != FM_RX_SIGNAL_STRENGTH_STRONG) ) { + + bStatus = false; + Log.d (TAG, "Invalid threshol: " + threshold ); + + } + + if (bStatus) { + re=FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH, threshold); + + 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) + */ + public int getTunedFrequency () { + + 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[64]; + int piLower = 0; + int piHigher = 0; + + FmReceiverJNI.getBufferNative(sFd, buff, 3); + + FmRxRdsData rdsData = new FmRxRdsData(sFd); + + String rdsStr = new String(buff); + + + /* byte is signed ;( + * knock down signed bits + */ + piLower = buff[3] & 0xFF; + piHigher = buff[2] & 0xFF; + + Log.d (TAG, "lowerByte " + piLower); + Log.d (TAG, "higherByte " + piHigher); + + int pi = ((piHigher << 8) | piLower); + + Log.d (TAG, "pi " + pi); + + + rdsData.setPrgmId (pi); + rdsData.setPrgmType ( (int)( buff[1] & 0x1F)); + + int numOfPs = (int)(buff[0] & 0x0F); + + try + { + rdsStr = rdsStr.substring(5, (int )((numOfPs*8) + 5) ); + rdsData.setPrgmServices (rdsStr); + + } catch (StringIndexOutOfBoundsException x) + { + Log.d (TAG, "Number of PS names " + numOfPs); + } + + return rdsData; + + } + + /*============================================================== + 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[120]; + int piLower = 0; + int piHigher = 0; + FmReceiverJNI.getBufferNative(sFd, buff, 2); + + FmRxRdsData rdsData = new FmRxRdsData(sFd); + + String rdsStr = new String(buff); + + /* byte is signed ;( + * knock down signed bit + */ + piLower = buff[3] & 0xFF; + piHigher = buff[2] & 0xFF; + + Log.d (TAG, "lowerByte " + piLower); + Log.d (TAG, "higherByte " + piHigher); + + int pi = ((piHigher << 8) | piLower); + + Log.d (TAG, "pi " + pi); + + + rdsData.setPrgmId (pi); + rdsData.setPrgmType ( (int)( buff[1] & 0x1F)); + + try + { + rdsStr = rdsStr.substring(5, (int) buff[0]+ 5); + rdsData.setRadioText (rdsStr); + + } catch (StringIndexOutOfBoundsException x) + { + Log.d (TAG, "StringIndexOutOfBoundsException ..."); + } + + return rdsData; + + } + + /*============================================================== + 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[40]; + 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 the currently set signal + * threshold. + * + * <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 () { + + return FmReceiverJNI.getControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH); + } + + + /*============================================================== + 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) + { + + // 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; + + } + + /*============================================================== + 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){ + + // 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) { + + // 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[] 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); + + rssi = rssi + 120; + + if (rssi > 100) + return 100; + + return rssi; + } + + /*============================================================== + FUNCTION: getInternalAntenna + ==============================================================*/ + /** + * Returns true if internal FM antenna is available + * + * <p> + * This method returns true is internal FM antenna is + * available, false otherwise + * + * <p> + * @return true/false + */ + public boolean getInternalAntenna() + { + + int re = FmReceiverJNI.getControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA); + + if (re == 1) + return true; + + return false; + } + + /*============================================================== + FUNCTION: setInternalAntenna + ==============================================================*/ + /** + * Returns true if successful, false otherwise + * + * <p> + * This method sets internal antenna type to true/false + * + * @param intAntenna true is Internal antenna is present + * + * <p> + * @return true/false + */ + public boolean setInternalAntenna(boolean intAnt) + { + + int iAntenna ; + + if (intAnt) + iAntenna = 1; + else + iAntenna = 0; + + + int re = FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna); + + if (re == 0) + return true; + + return false; + } + + /*============================================================== + FUNCTION: 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; + + } + + +} diff --git a/core/java/android/hardware/fmradio/FmReceiverJNI.java b/core/java/android/hardware/fmradio/FmReceiverJNI.java new file mode 100644 index 0000000..3707785 --- /dev/null +++ b/core/java/android/hardware/fmradio/FmReceiverJNI.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; + + +class FmReceiverJNI { + /** + * General success + */ + static final int FM_JNI_SUCCESS = 0; + + /** + * General failure + */ + static final int FM_JNI_FAILURE = -1; + + /** + * native method: Open device + * @return The file descriptor of the device + * + */ + static native int acquireFdNative(String path); + + + /** + * native method: + * @param fd + * @param control + * @param field + * @return + */ + static native int audioControlNative(int fd, int control, int field); + + /** + * native method: cancels search + * @param fd file descriptor of device + * @return May return + * {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int cancelSearchNative(int fd); + + /** + * native method: release control of device + * @param fd file descriptor of device + * @return May return + * {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int closeFdNative(int fd); + + /** + * native method: get frequency + * @param fd file descriptor of device + * @return Returns frequency in int form + */ + static native int getFreqNative(int fd); + + /** + * native method: set frequency + * @param fd file descriptor of device + * @param freq freq to be set in int form + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + * + */ + static native int setFreqNative(int fd, int freq); + + /** + * native method: get v4l2 control + * @param fd file descriptor of device + * @param id v4l2 id to be retrieved + * @return Returns current value of the + * v4l2 control + */ + static native int getControlNative (int fd, int id); + + /** + * native method: set v4l2 control + * @param fd file descriptor of device + * @param id v4l2 control to be set + * @param value value to be set + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setControlNative (int fd, int id, int value); + + /** + * native method: start search + * @param fd file descriptor of device + * @param dir search direction + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int startSearchNative (int fd, int dir); + + /** + * native method: get buffer + * @param fd file descriptor of device + * @param buff[] buffer + * @param index index of the buffer to be retrieved + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int getBufferNative (int fd, byte buff[], int index); + + /** + * native method: get RSSI value of the + * received signal + * @param fd file descriptor of device + * @return Returns signal strength in int form + * Signal value range from -120 to 10 + */ + static native int getRSSINative (int fd); + + /** + * native method: set FM band + * @param fd file descriptor of device + * @param low lower band + * @param high higher band + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setBandNative (int fd, int low, int high); + + /** + * native method: get lower band + * @param fd file descriptor of device + * @return Returns lower band in int form + */ + static native int getLowerBandNative (int fd); + + /** + * native method: force Mono/Stereo mode + * @param fd file descriptor of device + * @param val force mono/stereo indicator + * @return {@link #FM_JNI_SUCCESS} + * {@link #FM_JNI_FAILURE} + */ + static native int setMonoStereoNative (int fd, int val); + + /** + * native method: get Raw RDS data + * @param fd file descriptor of device + * @param buff[] buffer + * @param count number of bytes to be read + * @return Returns number of bytes read + */ + static native int getRawRdsNative (int fd, byte buff[], int count); +} diff --git a/core/java/android/hardware/fmradio/FmRxControls.java b/core/java/android/hardware/fmradio/FmRxControls.java new file mode 100644 index 0000000..b71aa57 --- /dev/null +++ b/core/java/android/hardware/fmradio/FmRxControls.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; + +import android.util.Log; + + +class FmRxControls +{ + + private boolean mStateStereo; + private boolean mStateMute; + private int mFreq; + + static final int SEEK_FORWARD = 0; + static final int SEEK_BACKWARD = 1; + static final int SCAN_FORWARD = 2; + static final int SCAN_BACKWARD = 3; + private int mSrchMode; + private int mScanTime; + private int mSrchDir; + private int mSrchListMode; + private int mPrgmType; + private int mPrgmId; + private static final String TAG = "FmRxControls"; + + + /* V4l2 Controls */ + private static final int V4L2_CID_PRIVATE_BASE = 0x8000000; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCHMODE = V4L2_CID_PRIVATE_BASE + 1; + private static final int V4L2_CID_PRIVATE_TAVARUA_SCANDWELL = V4L2_CID_PRIVATE_BASE + 2; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCHON = V4L2_CID_PRIVATE_BASE + 3; + private static final int V4L2_CID_PRIVATE_TAVARUA_STATE = V4L2_CID_PRIVATE_BASE + 4; + private static final int V4L2_CID_PRIVATE_TAVARUA_TRANSMIT_MODE = V4L2_CID_PRIVATE_BASE + 5; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK = V4L2_CID_PRIVATE_BASE + 6;; + private static final int V4L2_CID_PRIVATE_TAVARUA_REGION = V4L2_CID_PRIVATE_BASE + 7; + private static final int V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH = V4L2_CID_PRIVATE_BASE + 8; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY = V4L2_CID_PRIVATE_BASE + 9; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_PI = V4L2_CID_PRIVATE_BASE + 10; + private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT = V4L2_CID_PRIVATE_BASE + 11; + private static final int V4L2_CID_PRIVATE_TAVARUA_EMPHASIS = V4L2_CID_PRIVATE_BASE + 12; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDS_STD = V4L2_CID_PRIVATE_BASE + 13; + private static final int V4L2_CID_PRIVATE_TAVARUA_SPACING = V4L2_CID_PRIVATE_BASE + 14; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSON = V4L2_CID_PRIVATE_BASE + 15; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC = V4L2_CID_PRIVATE_BASE + 16; + private static final int V4L2_CID_PRIVATE_TAVARUA_LP_MODE = V4L2_CID_PRIVATE_BASE + 17; + + private static final int V4L2_CTRL_CLASS_USER = 0x980000; + private static final int V4L2_CID_BASE = V4L2_CTRL_CLASS_USER | 0x900; + + private static final int V4L2_CID_AUDIO_MUTE = V4L2_CID_BASE + 9; + + + + /* + * Turn on FM Rx/Tx. + * Rx = 1 and Tx = 2 + */ + public void fmOn(int fd, int device) { + FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_STATE, 1 ); + } + + /* + * Turn off FM Rx/Tx + */ + public void fmOff(int fd){ + FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_STATE, 2 ); + } + + /* + * set mute control + */ + public void muteControl(int fd, boolean on) { + if (on) + { + int err = FmReceiverJNI.setControlNative(fd, V4L2_CID_AUDIO_MUTE, 3 ); + } else + { + int err = FmReceiverJNI.setControlNative(fd, V4L2_CID_AUDIO_MUTE, 4 ); + } + } + + /* + * Tune FM core to specified freq. + */ + public void setStation(int fd) { + Log.d(TAG, "** Tune Using: "+fd); + int ret = FmReceiverJNI.setFreqNative(fd, mFreq); + Log.d(TAG, "** Returned: "+ret); + } + + /* + * Get currently tuned freq + */ + public int getTunedFrequency(int fd) { + int frequency = FmReceiverJNI.getFreqNative(fd); + Log.d(TAG, "getTunedFrequency: "+frequency); + return frequency; + } + + public int getFreq (){ + return mFreq; + } + + public void setFreq (int f){ + mFreq = f; + } + + /* + * Start search list for auto presets + */ + public int searchStationList (int fd, int mode, int preset_num, + int dir, int pty ) + { + int re; + + + /* set search mode. */ + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode); + if (re != 0) { + return re; + } + + /* set number of stations to be returned in the list */ + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT, preset_num); + if (re != 0) { + return re; + } + + // RDS search list? + if (pty > 0 ){ + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty); + } + if (re != 0) { + return re; + } + + /* This triigers the search and once completed the FM core generates + * searchListComplete event */ + re = FmReceiverJNI.startSearchNative (fd, dir ); + if (re != 0) { + return re; + } + else { + return 0; + } + + } + + /* Read search list from buffer */ + public int[] stationList (int fd) + { + int freq = 0; + int i=0; + int station_num; + float real_freq = 0; + int [] stationList; + byte [] sList = new byte[100]; + int tmpFreqByte1=0; + int tmpFreqByte2=0; + float lowBand; + + + lowBand = (float) (FmReceiverJNI.getLowerBandNative(fd) / 1000.00); + Log.d(TAG, "lowBand: " + lowBand); + FmReceiverJNI.getBufferNative(fd, sList, 0); + + station_num = (int)sList[0]; + stationList = new int[station_num+1]; + Log.d(TAG, "station_num: " + station_num); + + for (i=0;i<station_num;i++) { + freq = 0; + Log.d(TAG, " Byte1 = " + sList[i*2+1]); + Log.d(TAG, " Byte2 = " + sList[i*2+2]); + tmpFreqByte1 = sList[i*2+1] & 0xFF; + tmpFreqByte2 = sList[i*2+2] & 0xFF; + Log.d(TAG, " tmpFreqByte1 = " + tmpFreqByte1); + Log.d(TAG, " tmpFreqByte2 = " + tmpFreqByte2); + freq = (tmpFreqByte1 & 0x03) << 8; + freq |= tmpFreqByte2; + Log.d(TAG, " freq: " + freq); + real_freq = (float)(freq * 0.05) + lowBand;//tuner.rangelow / FREQ_MUL; + Log.d(TAG, " real_freq: " + real_freq); + stationList[i] = (int)(real_freq*1000); + Log.d(TAG, " stationList: " + stationList[i]); + } + + try { + // mark end of list + stationList[station_num] = 0; + } + catch (ArrayIndexOutOfBoundsException e) { + Log.d(TAG, "ArrayIndexOutOfBoundsException !!"); + } + + return stationList; + + } + + + /* configure various search parameters and start search */ + public void searchStations (int fd, int mode, int dwell, + int dir, int pty, int pi){ + int re = 0; + + + Log.d(TAG, "Mode is " + mode + " Dwell is " + dwell); + Log.d(TAG, "dir is " + dir + " PTY is " + pty); + Log.d(TAG, "pi is " + pi + " id " + V4L2_CID_PRIVATE_TAVARUA_SRCHMODE); + + + + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode); + + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, dwell); + + if (pty != 0) + { + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty); + } + + if (pi != 0) + { + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, pi); + } + + re = FmReceiverJNI.startSearchNative (fd, dir ); + + } + + /* force mono/stereo mode */ + public int stereoControl(int fd, boolean stereo) { + + if (stereo){ + return FmReceiverJNI.setMonoStereoNative (fd, 1); + } + else { + return FmReceiverJNI.setMonoStereoNative (fd, 0); + } + + + } + + + public void searchRdsStations(int mode,int dwelling, + int direction, int RdsSrchPty, int RdsSrchPI){ + } + + /* public void searchStationList(int listMode,int direction, + int listMax,int pgmType) { + } + */ + + /* cancel search in progress */ + public void cancelSearch (int fd){ + FmReceiverJNI.cancelSearchNative(fd); + } + + /* Set LPM. This disables all FM core interrupts */ + public int setLowPwrMode (int fd, boolean lpmOn){ + + int re=0; + + if (lpmOn){ + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE, 1); + } + else { + re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE, 0); + } + + return re; + + } + + /* get current powermode of the FM core. 1 for LPM and 0 Normal mode */ + public int getPwrMode (int fd) { + + int re=0; + + re = FmReceiverJNI.getControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE); + + return re; + + } + +} diff --git a/core/java/android/hardware/fmradio/FmRxEvCallbacks.java b/core/java/android/hardware/fmradio/FmRxEvCallbacks.java new file mode 100644 index 0000000..d2b6ffc --- /dev/null +++ b/core/java/android/hardware/fmradio/FmRxEvCallbacks.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; +interface FmRxEvCallbacks { + + public void FmRxEvEnableReceiver(); + public void FmRxEvDisableReceiver(); + public void FmRxEvRadioTuneStatus(int freq); + public void FmRxEvRdsLockStatus(boolean rdsAvail); + public void FmRxEvStereoStatus(boolean stereo); + public void FmRxEvServiceAvailable(boolean service); + public void FmRxEvSearchInProgress(); + public void FmRxEvSearchComplete(int freq); + public void FmRxEvSearchListComplete(); + public void FmRxEvRdsGroupData(); + public void FmRxEvRdsPsInfo(); + public void FmRxEvRdsRtInfo(); + public void FmRxEvRdsAfInfo(); + +} diff --git a/core/java/android/hardware/fmradio/FmRxEvCallbacksAdaptor.java b/core/java/android/hardware/fmradio/FmRxEvCallbacksAdaptor.java new file mode 100644 index 0000000..11ddded --- /dev/null +++ b/core/java/android/hardware/fmradio/FmRxEvCallbacksAdaptor.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; + +/** + * + * Class to be implemented for event callbacks + * @hide + */ + +public class FmRxEvCallbacksAdaptor implements FmRxEvCallbacks { + public void FmRxEvEnableReceiver() {}; + public void FmRxEvDisableReceiver() {}; + public void FmRxEvRadioTuneStatus(int freq) {}; + public void FmRxEvRdsLockStatus(boolean rdsAvail) {}; + public void FmRxEvStereoStatus(boolean stereo) {}; + public void FmRxEvServiceAvailable(boolean service) {}; + public void FmRxEvSearchInProgress() {}; + public void FmRxEvSearchComplete(int freq) {}; + public void FmRxEvSearchListComplete() {}; + public void FmRxEvRdsGroupData() {}; + public void FmRxEvRdsPsInfo() {}; + public void FmRxEvRdsRtInfo() {}; + public void FmRxEvRdsAfInfo() {}; +} + diff --git a/core/java/android/hardware/fmradio/FmRxEventListner.java b/core/java/android/hardware/fmradio/FmRxEventListner.java new file mode 100644 index 0000000..7453fae --- /dev/null +++ b/core/java/android/hardware/fmradio/FmRxEventListner.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; + +import android.util.Log; + + +class FmRxEventListner { + + + private final int EVENT_LISTEN = 1; + + private enum FmRxEvents { + READY_EVENT, + TUNE_EVENT, + SEEK_COMPLETE_EVENT, + SCAN_NEXT_EVENT, + RAW_RDS_EVENT, + RT_EVENT, + PS_EVENT, + ERROR_EVENT, + BELOW_TH_EVENT, + ABOVE_TH_EVENT, + STEREO_EVENT, + MONO_EVENT, + RDS_AVAL_EVENT, + RDS_NOT_AVAL_EVENT, + TAVARUA_EVT_NEW_SRCH_LIST, + TAVARUA_EVT_NEW_AF_LIST + } + + private Thread mThread; + private static final String TAG = "FMRadio"; + + public void startListner (final int fd, final FmRxEvCallbacks cb) { + /* start a thread and listen for messages */ + mThread = new Thread(){ + public void run(){ + + Log.d(TAG, "Starting listener " + fd); + + while (true) { + + byte []buff = new byte[128]; + int i = FmReceiverJNI.getBufferNative (fd, buff, EVENT_LISTEN); + Log.d(TAG, "Received <" +buff[0]+ "> event. Int: " + i); + + switch(buff[0]){ + + case 0: + Log.d(TAG, "Got READY_EVENT"); + cb.FmRxEvEnableReceiver(); + break; + case 1: + Log.d(TAG, "Got TUNE_EVENT"); + cb.FmRxEvRadioTuneStatus(FmReceiverJNI.getFreqNative(fd)); + break; + case 2: + Log.d(TAG, "Got SEEK_COMPLETE_EVENT"); + cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd)); + break; + case 3: + Log.d(TAG, "Got SCAN_NEXT_EVENT"); + cb.FmRxEvSearchInProgress(); + break; + case 4: + Log.d(TAG, "Got RAW_RDS_EVENT"); + cb.FmRxEvRdsGroupData(); + break; + case 5: + Log.d(TAG, "Got RT_EVENT"); + cb.FmRxEvRdsRtInfo(); + break; + case 6: + Log.d(TAG, "Got PS_EVENT"); + cb.FmRxEvRdsPsInfo(); + break; + case 7: + Log.d(TAG, "Got ERROR_EVENT"); + break; + case 8: + Log.d(TAG, "Got BELOW_TH_EVENT"); + cb.FmRxEvServiceAvailable (false); + break; + case 9: + Log.d(TAG, "Got ABOVE_TH_EVENT"); + cb.FmRxEvServiceAvailable(true); + break; + case 10: + Log.d(TAG, "Got STEREO_EVENT"); + cb.FmRxEvStereoStatus (true); + break; + case 11: + Log.d(TAG, "Got MONO_EVENT"); + cb.FmRxEvStereoStatus (false); + break; + case 12: + Log.d(TAG, "Got RDS_AVAL_EVENT"); + cb.FmRxEvRdsLockStatus (true); + break; + case 13: + Log.d(TAG, "Got RDS_NOT_AVAL_EVENT"); + cb.FmRxEvRdsLockStatus (false); + break; + case 14: + Log.d(TAG, "Got NEW_SRCH_LIST"); + cb.FmRxEvSearchListComplete (); + break; + case 15: + Log.d(TAG, "Got NEW_AF_LIST"); + cb.FmRxEvRdsAfInfo(); + break; + default: + Log.d(TAG, "Unknown event"); + break; + } + } + } + }; + mThread.start(); + } + + public void stopListener(){ + mThread.stop(); + } + +} diff --git a/core/java/android/hardware/fmradio/FmRxRdsData.java b/core/java/android/hardware/fmradio/FmRxRdsData.java new file mode 100644 index 0000000..210cee0 --- /dev/null +++ b/core/java/android/hardware/fmradio/FmRxRdsData.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; + +import android.util.Log; + +/** @hide */ +public class FmRxRdsData { + + + private String mRadioText; + private String mPrgmServices; + private int mPrgmId; + private int mPrgmType; + private int mFd; + + /* V4L2 controls */ + private static final int V4L2_CID_PRIVATE_BASE = 0x8000000; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK = V4L2_CID_PRIVATE_BASE + 6; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSON = V4L2_CID_PRIVATE_BASE + 15; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC = V4L2_CID_PRIVATE_BASE + 16; + private static final int V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF = V4L2_CID_PRIVATE_BASE + 19; + private static final int V4L2_CID_PRIVATE_TAVARUA_PSALL = V4L2_CID_PRIVATE_BASE + 20; + + + private static final int RDS_GROUP_RT = 0x1; + private static final int RDS_GROUP_PS = 1 << 1; + private static final int RDS_GROUP_AF = 1 << 2; + private static final int RDS_AF_AUTO = 1 << 3; + private static final int RDS_PS_ALL = 1 << 4; + private static final String LOGTAG="FmRxRdsData"; + + + public FmRxRdsData (int fd) + { + mFd = fd; + } + + /* turn on/off RDS processing */ + public int rdsOn (boolean on) + { + + int ret; + + Log.d(LOGTAG, "In rdsOn: RDS is " + on); + + if (on) { + ret = FmReceiverJNI.setControlNative (mFd, V4L2_CID_PRIVATE_TAVARUA_RDSON, 1); + } + else { + ret = FmReceiverJNI.setControlNative (mFd, V4L2_CID_PRIVATE_TAVARUA_RDSON, 0); + } + + + return ret; + + + } + + /* process raw RDS group filtering */ + public int rdsGrpOptions (int grpMask, int buffSize, boolean rdsFilter) + { + + int rdsFilt; + int re; + + byte rds_group_mask = (byte)FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC); + + rds_group_mask &= 0xFE; + + + if (rdsFilter) + rdsFilt = 1; + else + rdsFilt = 0; + + rds_group_mask |= rdsFilt; + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, rds_group_mask); + + if (re != 0) + return re; + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF, buffSize); + + if (re != 0) + return re; + + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, grpMask); + + return re; + + + } + + /* configure RT/PS/AF RDS processing */ + public int rdsOptions (int rdsMask) + { + + int re=0; + + byte rds_group_mask = (byte)FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC); + byte rdsFilt = 0; + int psAllVal=rdsMask & RDS_PS_ALL; + + Log.d(LOGTAG, "In rdsOptions: rdsMask: " + rdsMask); + + + rds_group_mask &= 0xC7; + + + rds_group_mask |= ((rdsMask & 0x07) << 3); + + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, rds_group_mask); + + re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_PSALL, psAllVal >> 4 ); + + return re; + + } + + /* Enable auto seek to alternate frequency */ + public int enableAFjump(boolean AFenable) + { + + Log.d(LOGTAG, "In enableAFjump: AFenable: " + AFenable); + + int rds_group_mask = FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC); + + Log.d(LOGTAG, "In enableAFjump: rds_group_mask: " + rds_group_mask); + + if (AFenable) { + FmReceiverJNI.setControlNative(mFd ,V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, + rds_group_mask | RDS_AF_AUTO); + } + else { + FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, + rds_group_mask & ~RDS_GROUP_AF); + } + return 1; + } + + + public String getRadioText () { + return mRadioText; + } + + public void setRadioText (String x) { + + mRadioText = x; + } + + + public String getPrgmServices () { + return mPrgmServices; + } + public void setPrgmServices (String x) { + mPrgmServices = x; + } + + + public int getPrgmId () { + return mPrgmId; + } + public void setPrgmId (int x) { + mPrgmId = x; + } + + public int getPrgmType () { + return mPrgmType; + } + public void setPrgmType (int x) { + mPrgmType = x; + } + +} diff --git a/core/java/android/hardware/fmradio/FmTransceiver.java b/core/java/android/hardware/fmradio/FmTransceiver.java new file mode 100644 index 0000000..f8f6743 --- /dev/null +++ b/core/java/android/hardware/fmradio/FmTransceiver.java @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; + +import android.util.Log; + +/** <code>FmTransceiver</code> is the superclass of classes + * <code>FmReceiver</code> and <code>FmTransmitter</code> + * @hide + */ +public class FmTransceiver +{ + + /** + * FMConfigure FM Radio band setting for US/Europe + */ + public static final int FM_US_BAND =0; + /** + * FMConfigure FM Radio band setting for US/Europe + */ + public static final int FM_EU_BAND =1; + /** + * FMConfigure FM Radio band setting for Japan + */ + public static final int FM_JAPAN_WIDE_BAND =2; + /** + * FMConfigure FM Radio band setting for Japan-Wideband + */ + public static final int FM_JAPAN_STANDARD_BAND =3; + /** + * FMConfigure FM Radio band setting for "User defined" band + */ + public static final int FM_USER_DEFINED_BAND =4; + + /** + * FM channel spacing settings = 200KHz + */ + public static final int FM_CHSPACE_200_KHZ =0; + /** + * FM channel spacing settings = 100KHz + */ + public static final int FM_CHSPACE_100_KHZ =1; + /** + * FM channel spacing settings = 50KHz + */ + public static final int FM_CHSPACE_50_KHZ =2; + + /** + * FM de-emphasis/pre-emphasis settings = 75KHz + */ + public static final int FM_DE_EMP75 = 0; + /** + * FM de-emphasis/pre-emphasis settings = 50KHz + */ + public static final int FM_DE_EMP50 = 1; + + /** + * RDS standard type: RBDS (North America) + */ + public static final int FM_RDS_STD_RBDS =0; + /** + * RDS standard type: RDS (Rest of the world) + */ + public static final int FM_RDS_STD_RDS =1; + /** + * RDS standard type: No RDS + */ + public static final int FM_RDS_STD_NONE =2; + + protected static final int FM_RX =1; + protected static final int FM_TX =2; + + private final int READY_EVENT = 0x01; + private final int TUNE_EVENT = 0x02; + private final int RDS_EVENT = 0x08; + private final int MUTE_EVENT = 0x04; + private final int SEEK_COMPLETE_EVENT = 0x03; + + private final String TAG = "FmTransceiver"; + + protected static int sFd; + protected FmRxControls mControl; + protected int mPowerMode; + protected FmRxEventListner mRxEvents; + protected FmRxRdsData mRdsData; + + /*============================================================== + FUNCTION: acquire + ==============================================================*/ + /** + * Allows access to the V4L2 FM device. + * + * This synchronous call allows a client to use the V4L2 FM + * device. This must be the first call issued by the client + * before any receiver interfaces can be used. + * + * This call also powers up the FM Module. + * + * @param device String that is path to radio device + * + * @return true if V4L2 FM device acquired, false if V4L2 FM + * device could not be acquired, possibly acquired by + * other client + * @see #release + * + */ + protected boolean acquire(String device){ + boolean bStatus; + if (sFd == 0) + { + sFd = FmReceiverJNI.acquireFdNative("/dev/radio0"); + Log.d(TAG, "** Opened "+ sFd); + } else + { + Log.d(TAG, "Already opened"); + } + if(sFd != 0) + { + bStatus = true; + } + else + { + bStatus = false; + } + return (bStatus); + } + + /*============================================================== + FUNCTION: release + ==============================================================*/ + /** + * Releases access to the V4L2 FM device. + * <p> + * This synchronous call allows a client to release control of + * V4L2 FM device. This function should be called when the FM + * device is no longer needed. This should be the last call + * issued by the FM client. Once called, the client must call + * #acquire to re-aquire the V4L2 device control before the + * FM device can be used again. + * <p> + * Before the client can release control of the FM receiver + * interface, it must disable the FM receiver, if the client + * enabled it, and unregister any registered callback. If the + * client has ownership of the receiver, it will automatically + * be returned to the system. + * <p> + * This call also powers down the FM Module. + * <p> + * @param device String that is path to radio device + * @return true if V4L2 FM device released, false if V4L2 FM + * device could not be released + * @see #acquire + */ + protected boolean release(String device) { + if (sFd!=0) + { + FmReceiverJNI.closeFdNative(sFd); + sFd =0; + Log.d(TAG, "Turned off: " + sFd); + } else + { + Log.d(TAG, "Error turning off"); + } + return true; + } + + /*============================================================== + FUNCTION: registerClient + ==============================================================*/ + /** + * Registers a callback for FM receiver event notifications. + * <p> + * This is a synchronous call used to register for event + * notifications from the FM receiver driver. Since the FM + * driver performs some tasks asynchronously, this function + * allows the client to receive information asynchronously. + * <p> + * When calling this function, the client must pass a callback + * function which will be used to deliver asynchronous events. + * The argument callback must be a non-NULL value. If a NULL + * value is passed to this function, the registration will + * fail. + * <p> + * The client can choose which events will be sent from the + * receiver driver by simply implementing functions for events + * it wishes to receive. + * <p> + * + * @param callback the callback to handle the events events + * from the FM receiver. + * @return true if Callback registered, false if Callback + * registration failed. + * + * @see #acquire + * @see #unregisterClient + * + */ + public boolean registerClient(FmRxEvCallbacks callback){ + boolean bReturnStatus = false; + if (callback!=null) + { + mRxEvents.startListner(sFd, callback); + bReturnStatus = true; + } else + { + Log.d(TAG, "Null, do nothing"); + } + return bReturnStatus; + } + + /*============================================================== + FUNCTION: unregisterClient + ==============================================================*/ + /** + * Unregisters a client's event notification callback. + * <p> + * This is a synchronous call used to unregister a client's + * event callback. + * <p> + * @return true always. + * + * @see #acquire + * @see #release + * @see #registerClient + * + */ + public boolean unregisterClient () { + mRxEvents.stopListener(); + return true; + } + + + /*============================================================== + FUNCTION: registerTransmitClient + ==============================================================*/ + /** + * Registers a callback for FM Transmitter event + * notifications. + * <p> + * This is a synchronous call used to register for event + * notifications from the FM Transmitter driver. Since the FM + * driver performs some tasks asynchronously, this function + * allows the client to receive information asynchronously. + * <p> + * When calling this function, the client must pass a callback + * function which will be used to deliver asynchronous events. + * The argument callback must be a non-NULL value. If a NULL + * value is passed to this function, the registration will + * fail. + * <p> + * The client can choose which events will be sent from the + * receiver driver by simply implementing functions for events + * it wishes to receive. + * <p> + * + * @param callback the callback to handle the events events + * from the FM Transmitter. + * @return true if Callback registered, false if Callback + * registration failed. + * + * @see #acquire + * @see #unregisterTransmitClient + * + */ + public boolean registerTransmitClient(FmRxEvCallbacks callback){ + boolean bReturnStatus = false; + if (callback!=null) + { + //mRxEvents.startListner(sFd, callback); + bReturnStatus = true; + } else + { + Log.d(TAG, "Null, do nothing"); + } + return bReturnStatus; + } + + /*============================================================== + FUNCTION: unregisterTransmitClient + ==============================================================*/ + /** + * Unregisters Transmitter event notification callback. + * <p> + * This is a synchronous call used to unregister a Transmitter + * client's event callback. + * <p> + * @return true always. + * + * @see #acquire + * @see #release + * @see #registerTransmitClient + * + */ + public boolean unregisterTransmitClient () { + //mRxEvents.stopListener(); + return true; + } + + /*============================================================== + FUNCTION: enable + ==============================================================*/ + /** + * Initializes the FM device. + * <p> + * This is a synchronous call is used to initialize the FM + * tranceiver. If already initialized this function will + * intialize the tranceiver with default settings. Only after + * successfully calling this function can many of the FM device + * interfaces be used. + * <p> + * When enabling the receiver, the client must also provide + * the regional settings in which the receiver will operate. + * These settings (included in configSettings) are typically + * used for setting up the FM receiver for operating in a + * particular geographical region. These settings can be + * changed after the FM driver is enabled through the use of + * the function #configure. + * <p> + * This call can only be issued by the owner of an FM + * receiver. To issue this call, the client must first + * successfully call #acquire. + * <p> + * @param configSettings the settings to be applied when + * turning on the radio + * @return true if Initialization succeeded, false if + * Initialization failed. + * @see #registerClient + * @see #disable + * + */ + public boolean enable (FmConfig configSettings, int device){ + + + Log.d(TAG, "turning on %d" + device); + mControl.fmOn(sFd, device); + + Log.d(TAG, "Calling fmConfigure"); + return FmConfig.fmConfigure (sFd, configSettings); + + } + + /*============================================================== + FUNCTION: disable + ==============================================================*/ + /** + * Disables the FM Device. + * <p> + * This is a synchronous call used to disable the FM + * device. This function is expected to be used when the + * client no longer requires use of the FM device. Once + * called, most functionality offered by the FM device will be + * disabled until the client re-enables the device again via + * #enable. + * <p> + * @return true if disabling succeeded, false if disabling + * failed. + * <p> + * @see #enable + * @see #registerClient + */ + public boolean disable(){ + mControl.fmOff(sFd); + + return true; + } + + /*============================================================== + FUNCTION: configure + ==============================================================*/ + /** + * Reconfigures the device's regional settings + * (FM Band, De-Emphasis, Channel Spacing, RDS/RBDS mode). + * <p> + * This is a synchronous call used to reconfigure settings on + * the FM device. Included in the passed structure are + * settings which typically differ from one geographical + * region to another. + * <p> + * @param configSettings Contains settings for the FM radio + * (FM band, De-emphasis, channel + * spacing, RDS/RBDS mode) + * <p> + * @return true if configure succeeded, false if + * configure failed. + */ + public boolean configure(FmConfig configSettings){ + + Log.d(TAG, "fmConfigure"); + + return FmConfig.fmConfigure (sFd, configSettings); + + } + + /*============================================================== + FUNCTION: setStation + ==============================================================*/ + /** + * Tunes the FM device to the specified FM frequency. + * <p> + * This method tunes the FM device to a station specified by the + * provided frequency. Only valid frequencies within the band + * set by enable or configure can be tuned by this function. + * Attempting to tune to frequencies outside of the set band + * will result in an error. + * <p> + * Once tuning to the specified frequency is completed, the + * event callback FmRxEvRadioTuneStatus will be called. + * + * @param frequencyKHz Frequency (in kHz) to be tuned + * (Example: 96500 = 96.5Mhz) + * @return true if setStation call was placed successfully, + * false if setStation failed. + */ + public boolean setStation (int frequencyKHz) { + mControl.setFreq(frequencyKHz); + mControl.setStation(sFd); + + return true; + } +} diff --git a/core/java/android/hardware/fmradio/FmTransmitter.java b/core/java/android/hardware/fmradio/FmTransmitter.java new file mode 100644 index 0000000..f1cddfd --- /dev/null +++ b/core/java/android/hardware/fmradio/FmTransmitter.java @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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 android.hardware.fmradio; +/** + * This class contains all interfaces and types needed to control the FM transmitter. + * @hide + */ +public class FmTransmitter extends FmTransceiver +{ + /** + * RAW RDS Groups Transmit Control : PAUSE + * + * @see #RDS_GRPS_TX_RESUME + * @see #RDS_GRPS_TX_STOP + * @see #transmitRdsGroupControl + */ + public static final int RDS_GRPS_TX_PAUSE=0; + + /** + * RAW RDS Groups Transmit Control : RESUME + * + * @see #RDS_GRPS_TX_RESUME + * @see #RDS_GRPS_TX_STOP + * @see #transmitRdsGroupControl + */ + public static final int RDS_GRPS_TX_RESUME=1; + + /** + * RAW RDS Groups Transmit Control : STOP Stop will also clear + * the buffer in the driver. + * + * @see #RDS_GRPS_TX_RESUME + * @see #RDS_GRPS_TX_STOP + * @see #transmitRdsGroupControl + */ + public static final int RDS_GRPS_TX_STOP=2; + + /** + * Creates a transmitter object + */ + public FmTransmitter(){ + mControl = new FmRxControls(); + mRdsData = new FmRxRdsData(sFd); + mRxEvents = new FmRxEventListner(); + } + + /** + * Constructor for the transmitter class that takes path to + * radio and event callback adapter + */ + public FmTransmitter(String path, FmRxEvCallbacksAdaptor callbacks){ + //TODO: Replace this prototype with the correct "Adaptor" when implemented. + // public FmTransmitter(String path, FMTransmitterCallbacksAdaptor adaptor){ + acquire(path); + registerTransmitClient(callbacks); + mControl = new FmRxControls(); + mRdsData = new FmRxRdsData(sFd); + mRxEvents = new FmRxEventListner(); + } + + /*============================================================== + FUNCTION: enable + ==============================================================*/ + /** + * Enables the FM device in Transmit 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 application must also + * provide the regional settings in which the transmitter will + * operate. These settings (included in argument + * configSettings) are typically used for setting up the FM + * Transmitter for operating in a particular geographical + * region. These settings can be changed after the FM driver + * is enabled through the use of the function {@link + * #configure}. + * <p> + * This command can only be issued by the owner of an FM + * receiver. To issue this command, the application 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 #registerTransmitClient + * @see #disable + * + */ + public boolean enable (FmConfig configSettings){ + boolean status; + + /* Enable the Transceiver common for both + receiver and transmitter + */ + status = super.enable(configSettings, FmTransceiver.FM_TX); + + /* Do transmitter Specific Enable Stuff here.*/ + + return true; + } + + /*============================================================== + FUNCTION: disable + ==============================================================*/ + /** + * Disables the FM Transmitter Device. + * <p> + * This is a synchronous command used to disable the FM + * device. This function is expected to be used when the + * application no longer requires use of the FM device. Once + * called, most functionality offered by the FM device will be + * disabled until the application re-enables the device again + * via {@link #enable}. + * + * <p> + * @return true if disabling succeeded, false if disabling + * failed. + * + * @see #enable + * @see #registerTransmitClient + */ + public boolean disable(){ + boolean status; + status = super.disable(); + return true; + } + + /*============================================================== + FUNCTION: getPSFeatures + ==============================================================*/ + /** + * This function returns the features supported by the FM + * driver when using {@link #setPSInfo}. + * <p> + * This function is used to get the features the FM driver + * supports when transmitting Program Service information. + * Included in the returned features is the number of Program + * Service (PS) characters which can be transmitted using + * {@link #setPSInfo}. If the driver supports continuous + * transmission of Program Service Information, this function + * will return a value greater than 0 for + * FmPSFeatures.maxPSCharacters. Although the RDS/RBDS + * standard defines each Program Service (PS) string as eight + * characters in length, the FM driver may have the ability to + * accept a string that is greater than eight character. This + * extended string will thenbe broken up into multiple strings + * of length eight and transmitted continuously. + * <p> + * When transmitting more than one string, the application may + * want to control the timing of how long each string is + * transmitted. Included in the features returned from this + * function is the maximum Program Service string repeat count + * (FmPSFeatures.maxPSStringRepeatCount). When using the + * function {@link #setPSInfo}, the application can specify how + * many times each string is repeated before the next string is + * transmitted. + * + * @return the Program service maximum characters and repeat + * count + * + * @see #setPSInfo + * + */ + public FmPSFeatures getPSFeatures(){ + FmPSFeatures psFeatures = new FmPSFeatures(); + psFeatures.maxPSCharacters = 0; + psFeatures.maxPSStringRepeatCount = 0; + return psFeatures; + } + + /*============================================================== + FUNCTION: setPSInfo + ==============================================================*/ + /** + * Continuously transmit RDS/RBDS Program Service information + * over an already tuned station. + * <p> + * This is a function used to continuously transmit Program + * Service information over an already tuned station. While + * Program Service information can be transmitted using {@link + * #transmitRdsGroups} and 0A/0B groups, this function makes + * the same output possible with limited input needed from the + * application. + * <p> + * Included in the Program Service information is an RDS/RBDS + * program type (PTY), and one or more Program Service + * strings. The program type (PTY) is used to describe the + * content being transmitted and follows the RDS/RBDS program + * types described in the RDS/RBDS specifications. + * <p> + * Program Service information also includes an eight + * character string. This string can be used to display any + * information, but is typically used to display information + * about the audio being transmitted. Although the RDS/RBDS + * standard defines a Program Service (PS) string as eight + * characters in length, the FM driver may have the ability to + * accept a string that is greater than eight characters. This + * extended string will then be broken up into multiple eight + * character strings which will be transmitted continuously. + * All strings passed to this function must be terminated by a + * null character (0x00). + * <p> + * When transmitting more than one string, the application may + * want to control the timing of how long each string is + * transmitted. To control this timing and to ensure that the FM + * receiver receives each string, the application can specify + * how many times each string is repeated before the next string + * is transmitted. This command can only be issued by the owner + * of an FM transmitter. + * + * <p> + * Use {@link #setPSRTProgramType} to update the ProgramType to + * be used as part of the PS Information. + * + * Note: psStr should contain strings each of 8 characters or + * less. If the string is greater than 8 characters, the + * string will be truncated. + * + * @param psStr the program service strings to transmit + * @param pty the program type to use in the program Service + * information. + * @param repeatCount the number of times each 8 char string is + * repeated before next string + * + * @return true if PS information was successfully sent to the + * driver, false if PS information could not be sent + * to the driver. + * + * @see #getPSFeatures + * @see #setPSRTProgramType + * @see #stopPSInfo + */ + public boolean setPSInfo(String[] psStr, int pty, long repeatCount){ + boolean bStatus = false; + + return bStatus; + } + + /*============================================================== + FUNCTION: stopPSInfo + ==============================================================*/ + /** + * Stop an active Program Service transmission. + * + * <p> + * This is a function used to stop an active Program Service transmission + * started by {@link #setPSInfo}. + * + * @return true if Stop PS information was successfully sent to + * the driver, false if Stop PS information could not + * be sent to the driver. + * + * @see #getPSFeatures + * @see #setPSInfo + * + */ + public boolean stopPSInfo(){ + boolean bStatus = false; + + return bStatus; + } + + /*============================================================== + FUNCTION: setPSInfo + ==============================================================*/ + /** + * Continuously transmit RDS/RBDS RadioText information over an + * already tuned station. + * + * <p> + * This is a function used to continuously transmit RadioText + * information over an already tuned station. While RadioText + * information can be transmitted using + * {@link #transmitRdsGroups} and 2A/2B groups, this function + * makes the same output possible with limited input needed from + * the application. + * <p> + * Included in the RadioText information is an RDS/RBDS program type (PTY), + * and a single string of up to 64 characters. The program type (PTY) is used + * to describe the content being transmitted and follows the RDS/RBDS program + * types described in the RDS/RBDS specifications. + * <p> + * RadioText information also includes a string that consists of up to 64 + * characters. This string can be used to display any information, but is + * typically used to display information about the audio being transmitted. + * This RadioText string is expected to be at 64 characters in length, or less + * than 64 characters and terminated by a return carriage (0x0D). All strings + * passed to this function must be terminated by a null character (0x00). + * <p> + * Use {@link #setPSRTProgramType} to update the ProgramType to + * be used as part of the RT Information. + * + * Note: rtStr should contain a maximum of 64 characters. + * If the string is greater than 64 characters, the string + * will be truncated to 64 characters. + * + * @param rtStr the Radio Text string to transmit + * + * @return true if RT information String was successfully sent + * to the driver, false if RT information string + * could not be sent to the driver. + * + * @see #setPSRTProgramType + * @see #stopRTInfo + */ + public boolean setRTInfo(String rtStr){ + boolean bStatus = false; + + return bStatus; + } + + /*============================================================== + FUNCTION: stopRTInfo + ==============================================================*/ + /** + * Stop an active Radio Text information transmission. + * + * <p> + * This is a function used to stop an active Radio Text + * transmission started by {@link #setRTInfo}. + * + * @return true if Stop RT information was successfully sent to + * the driver, false if Stop RT information could not + * be sent to the driver. + * + * @see #setRTInfo + * + */ + public boolean stopRTInfo(){ + boolean bStatus = false; + + return bStatus; + } + + /*============================================================== + FUNCTION: setPSRTProgramType + ==============================================================*/ + /** + * Set the Program Type to be used for Continuously transmit + * RDS/RBDS Program Service information and RDS/RBDS RadioText + * information. + * <p> + * This is a function to set the Program Type to be used while + * transmitting Program Service and Radio Text Information. + * <p> + * Included in the Program Service information is an RDS/RBDS program type (PTY), and + * one or more Program Service strings. The program type (PTY) + * is used to describe the content being transmitted and follows + * the RDS/RBDS program types described in the RDS/RBDS + * specifications. + * <p> + * Included in the RadioText information is an RDS/RBDS program type (PTY), + * and a single string of up to 64 characters. The program type (PTY) is used + * to describe the content being transmitted and follows the RDS/RBDS program + * types described in the RDS/RBDS specifications. + * + * Note: If the PS or RT transmission is currently active, the + * PTY change will take effect when the current transmission is + * complete. Typically setPSRTProgramType should be called + * before {@link #setPSInfo} or {@link #setRTInfo} is started. + * + * @param pty the program type to use in the program Service + * information and Radio Text information. + * + * @return true if the driver was updated to use the new + * Program Type, false if the driver could not be + * updated. + * + * @see #setPSInfo + * @see #setRTInfo + * + */ + public boolean setPSRTProgramType(int pty){ + boolean bStatus = false; + + return bStatus; + } + + + /*============================================================== + FUNCTION: getRdsGroupBufSize + ==============================================================*/ + /** + * Get the maximum number of RDS/RBDS groups which can be passed + * to the FM driver. + * <p> + * This is a function used to determine the maximum RDS/RBDS + * buffer size for use when calling {@link #transmitRdsGroups} + * + * @return the maximum number of RDS/RBDS groups which can be + * passed to the FM driver at any one time. + * + */ + public int getRdsGroupBufSize(){ + return 0; + } + + + /*============================================================== + FUNCTION: transmitRdsGroups + ==============================================================*/ + /** + * This function will transmit RDS/RBDS groups over an already tuned station. + * <p> + * This function accepts a buffer (rdsGroups) containing one or + * more RDS groups. When sending this buffer, the application + * must also indicate how many groups should be taken from this + * buffer (numGroupsToTransmit). It may be possible that the FM + * driver can not accept the number of group contained in the + * buffer and will indicate how many group were actually + * accepted through the return value. + * + * <p> + * The FM driver will indicate to the application when it is + * ready to accept more data via both the + * "onRDSGroupsAvailable()" and "onRDSGroupsComplete()" events + * callbacks. The "onRDSGroupsAvailable()" callback will + * indicate to the application that the FM driver can accept + * additional groups even thoughall groups may not have been + * passed to the FM transmitter. The onRDSGroupsComplete() + * callback will indicate when the FM driver has a complete + * buffer to transmit RDS data. In many cases all data passed to + * the FM driver will be passed to the FM hardware and only a + * onRDSGroupsComplete() event will be generated by the + * FM driver. + * <p> If the application attempts to send more groups than the + * FM driver can handle, the application must wait until it + * receives a onRDSGroupsAvailable or a onRDSGroupsComplete + * event before attempting to transmit more groups. Failure to + * do so may result in no group being consumed by the FM driver. + * <p> It is important to note that switching between continuous + * and non-continuous transmission of RDS groups can only happen + * when no RDS/RBDS group transmission is underway. If an + * RDS/RBDS group transmission is already underway, the + * application must wait for a onRDSGroupsComplete. If the application + * wishes to switch from continuous to non-continuous (or + * vice-versa) without waiting for the current transmission to + * complete, the application can clear all remaining groups + * using the {@link #transmitRdsGroupControl} command. + * <p> + * Once completed, this command will generate a + * onRDSGroupsComplete event to all registered applications. + * + * @param rdsGroups The RDS/RBDS groups buffer to transmit. + * @param numGroupsToTransmit The number of groups in the buffer + * to transmit. + * + * @return The number of groups the FM driver actually accepted. + * A value >0 indicates the command was successfully + * accepted and a return value of "-1" indicates error. + * + * @see #transmitRdsGroupControl + */ + + public int transmitRdsGroups(byte[] rdsGroups, long numGroupsToTransmit){ + return -1; + } + + /*============================================================== + FUNCTION: transmitRdsGroupControl + ==============================================================*/ + /** + * Pause/Resume RDS/RBDS group transmission, or stop and clear + * all RDS groups. + * <p> + * This is a function used to used to pause/resume RDS/RBDS + * group transmission, or stop and clear all RDS groups. This + * function can be used with to control continuous and + * non-continuous RDS/RBDS group transmissions. + * <p> + * @param ctrlCmd The Tx RDS group control. + * + * @return true if RDS Group Control command was + * successfully sent to the driver, false if RDS + * Group Control command could not be sent to the + * driver. + * + * @see #transmitRdsGroups + */ + public boolean transmitRdsGroupControl(int ctrlCmd){ + boolean bStatus = false; + + return bStatus; + } + + /*============================================================== + FUNCTION: isAntennaAvailable + ==============================================================*/ + /** + * Read if an internal Antenna is available for the FM + * device. + * <p> + * + * This method is available to find that if an internal + * Antenna is present or not + * + * + * @return true if an internal Antenna is available, false if + * if an internal antenna is not available and an + * external Antenna has to be used. + * + */ + boolean isAntennaAvailable() + { + return true; + } + + + /** + * An object that contains the PS Features as configured using + * {@link #setPSInfo}. + * + * @see #setPSInfo + * @see #getPSFeatures + */ + public class FmPSFeatures + { + public int maxPSCharacters; + public int maxPSStringRepeatCount; + }; + + /** + * The interface that provides the applications to get callback + * for asynchronous events. + * An Adapter that implements this interface needs to be used to + * register to receive the callbacks using {@link + * #registerTransmitClient} + * + * @see #registerTransmitClient + */ + public interface TransmitterCallbacks + { + /** + * The callback indicates that the transmitter is tuned to a + * new frequency Typically received after setStation. + */ + public void onTuneFrequencyChange(int freq); + + /** + * The callback to indicate to the application that the FM + * driver can accept additional groups even though all groups + * may not have been passed to the FM transmitter. + */ + public void onRDSGroupsAvailable(); + /** + * The callback will indicate when the FM driver has a complete + * buffer to transmit RDS data. + */ + public void onRDSGroupsComplete(); + }; +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index bd0f307..b752ecf 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -132,6 +132,11 @@ LOCAL_SRC_FILES:= \ android_backup_FileBackupHelperBase.cpp \ android_backup_BackupHelperDispatcher.cpp +ifeq ($(BOARD_HAVE_FM_RADIO),true) + LOCAL_SRC_FILES += android_hardware_fm.cpp + LOCAL_CFLAGS += -DHAVE_FM_RADIO +endif + LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ $(LOCAL_PATH)/android/graphics \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 682f78e..9f45ba1 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -88,6 +88,10 @@ extern int register_android_message_digest_sha1(JNIEnv *env); extern int register_android_util_FloatMath(JNIEnv* env); +#ifdef HAVE_FM_RADIO +extern int register_android_hardware_fm_fmradio(JNIEnv* env); +#endif + namespace android { /* @@ -1270,6 +1274,9 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_MemoryFile), REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_android_hardware_Camera), +#ifdef HAVE_FM_RADIO + REG_JNI(register_android_hardware_fm_fmradio), +#endif REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_media_AudioRecord), REG_JNI(register_android_media_AudioSystem), diff --git a/core/jni/android_hardware_fm.cpp b/core/jni/android_hardware_fm.cpp new file mode 100644 index 0000000..579d745 --- /dev/null +++ b/core/jni/android_hardware_fm.cpp @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. 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 Code Aurora 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. + */ + +#define LOGI printf +#define LOG_TAG "fmradio" + +#include "jni.h" +#include "nativehelper/JNIHelp.h" +#include "utils/Log.h" +#include "utils/misc.h" +#include "android_runtime/AndroidRuntime.h" +#include <cutils/properties.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/videodev2.h> +#include <math.h> + +#define FM_JNI_SUCCESS 0L +#define FM_JNI_FAILURE -1L +#define SEARCH_DOWN 0 +#define SEARCH_UP 1 +#define TUNE_MULT 16000 +enum search_dir_t { + SEEK_UP, + SEEK_DN, + SCAN_UP, + SCAN_DN +}; +enum BCM_FM_CMD +{ + BCM4325_I2C_FM_RDS_SYSTEM = 0x00, /*0x00 FM enable, RDS enable*/ + BCM4325_I2C_FM_CTRL, /*0x01 Band select, mono/stereo blend, mono/stearo select*/ + BCM4325_I2C_RDS_CTRL0, /*0x02 RDS/RDBS, flush FIFO*/ + BCM4325_I2C_RDS_CTRL1, /*0x03 Not used*/ + BCM4325_I2C_FM_AUDIO_PAUSE, /*0x04 Pause level and time constant*/ + BCM4325_I2C_FM_AUDIO_CTRL0, /*0x05 Mute, volume, de-emphasis, route parameters, BW select*/ + BCM4325_I2C_FM_AUDIO_CTRL1, /*0x06 Mute, volume, de-emphasis, route parameters, BW select*/ + BCM4325_I2C_FM_SEARCH_CTRL0, /*0x07 Search parameters such as stop level, up/down*/ + BCM4325_I2C_FM_SEARCH_CTRL1, /*0x08 Not used*/ + BCM4325_I2C_FM_SEARCH_TUNE_MODE, /*0x09 Search/tune mode and stop*/ + BCM4325_I2C_FM_FREQ0, /*0x0a Set and get frequency*/ + BCM4325_I2C_FM_FREQ1, /*0x0b Set and get frequency*/ + BCM4325_I2C_FM_AF_FREQ0, /*0x0c Set alternate jump frequency*/ + BCM4325_I2C_FM_AF_FREQ1, /*0x0d Set alternate jump frequency*/ + BCM4325_I2C_FM_CARRIER, /*0x0e IF frequency error*/ + BCM4325_I2C_FM_RSSI, /*0x0f Recived signal strength*/ + BCM4325_I2C_FM_RDS_MASK0, /*0x10 FM and RDS IRQ mask register*/ + BCM4325_I2C_FM_RDS_MASK1, /*0x11 FM and RDS IRQ mask register*/ + BCM4325_I2C_FM_RDS_FLAG0, /*0x12 FM and RDS flag register*/ + BCM4325_I2C_FM_RDS_FLAG1, /*0x13 FM and RDS flag register*/ + BCM4325_I2C_RDS_WLINE, /*0x14 FIFO water line set level*/ + BCM4325_I2C_RDS_BLKB_MATCH0, /*0x16 Block B match pattern*/ + BCM4325_I2C_RDS_BLKB_MATCH1, /*0x17 Block B match pattern*/ + BCM4325_I2C_RDS_BLKB_MASK0, /*0x18 Block B mask pattern*/ + BCM4325_I2C_RDS_BLKB_MASK1, /*0x19 Block B mask pattern*/ + BCM4325_I2C_RDS_PI_MATCH0, /*0x1a PI match pattern*/ + BCM4325_I2C_RDS_PI_MATCH1, /*0x1b PI match pattern*/ + BCM4325_I2C_RDS_PI_MASK0, /*0x1c PI mask pattern*/ + BCM4325_I2C_RDS_PI_MASK1, /*0x1d PI mask pattern*/ + BCM4325_I2C_FM_RDS_BOOT, /*0x1e FM_RDS_BOOT register*/ + BCM4325_I2C_FM_RDS_TEST, /*0x1f FM_RDS_TEST register*/ + BCM4325_I2C_SPARE0, /*0x20 Spare register #0*/ + BCM4325_I2C_SPARE1, /*0x21 Spare register #1*/ + /*0x21-0x26 Reserved*/ + BCM4325_I2C_FM_RDS_REV_ID = 0x28, /*0x28 Revision ID of the FM demodulation core*/ + BCM4325_I2C_SLAVE_CONFIGURATION, /*0x29 Enable/disable I2C slave. Configure I2C slave address*/ + /*0x2a-0x7f Reserved*/ + BCM4325_I2C_FM_PCM_ROUTE = 0x4d, /*0x4d Controls routing of FM audio output to either PM or Bluetooth SCO*/ + + BCM4325_I2C_RDS_DATA = 0x80, /*0x80 Read RDS tuples(3 bytes each)*/ + + BCM4325_I2C_FM_BEST_TUNE = 0x90, /*0x90 Best tune mode enable/disable for AF jump*/ + /*0x91-0xfb Reserved*/ + BCM4325_I2C_FM_SEARCH_METHOD = 0xfc, /*0xfc Select search methods: normal, preset, RSSI monitoring*/ + BCM4325_I2C_FM_SEARCH_STEPS, /*0xfd Adjust search steps in units of 1kHz to 100kHz*/ + BCM4325_I2C_FM_MAX_PRESET, /*0xfe Sets the maximum number of preset channels found for FM scan command*/ + BCM4325_I2C_FM_PRESET_STATION, /*0xff Read the number of preset stations returned after a FM scan command*/ +}; + + +/*! @brief Size of writes to BCM4325: 1 byte for opcode/register and 1 bytes for data */ +#define BCM4325_WRITE_CMD_SIZE 2 + +/* Defines for read/write sizes to the BCM4325 */ +#define BCM4325_REG_SIZE 1 +#define BCM4325_RDS_SIZE 3 +#define BCM4325_MAX_READ_SIZE 3 + +/* Defines for the FM_RDS_SYSTEM register */ +#define BCM4325_FM_RDS_SYSTEM_OFF 0x00 +#define BCM4325_FM_RDS_SYSTEM_FM 0x01 +#define BCM4325_FM_RDS_SYSTEM_RDS 0x02 + +#define BCM4325_FM_CTRL_BAND_EUROPE_US 0x00 +#define BCM4325_FM_CTRL_BAND_JAPAN 0x01 +#define BCM4325_FM_CTRL_AUTO 0x02 +#define BCM4325_FM_CTRL_MANUAL 0x00 +#define BCM4325_FM_CTRL_STEREO 0x04 +#define BCM4325_FM_CTRL_MONO 0x00 +#define BCM4325_FM_CTRL_SWITCH 0x08 +#define BCM4325_FM_CTRL_BLEND 0x00 + +#define BCM4325_FM_AUDIO_CTRL0_RF_MUTE_ENABLE 0x01 +#define BCM4325_FM_AUDIO_CTRL0_RF_MUTE_DISABLE 0x00 +#define BCM4325_FM_AUDIO_CTRL0_MANUAL_MUTE_ON 0x02 +#define BCM4325_FM_AUDIO_CTRL0_MANUAL_MUTE_OFF 0x00 +#define BCM4325_FM_AUDIO_CTRL0_DAC_OUT_LEFT_ON 0x04 +#define BCM4325_FM_AUDIO_CTRL0_DAC_OUT_LEFT_OFF 0x00 +#define BCM4325_FM_AUDIO_CTRL0_DAC_OUT_RIGHT_ON 0x08 +#define BCM4325_FM_AUDIO_CTRL0_DAC_OUT_RIGHT_OFF 0x00 +#define BCM4325_FM_AUDIO_CTRL0_ROUTE_DAC_ENABLE 0x10 +#define BCM4325_FM_AUDIO_CTRL0_ROUTE_DAC_DISABLE 0x00 +#define BCM4325_FM_AUDIO_CTRL0_ROUTE_I2S_ENABLE 0x20 +#define BCM4325_FM_AUDIO_CTRL0_ROUTE_I2S_DISABLE 0x00 +#define BCM4325_FM_AUDIO_CTRL0_DEMPH_75US 0x40 +#define BCM4325_FM_AUDIO_CTRL0_DEMPH_50US 0x00 +/* Defines for the SEARCH_CTRL0 register */ +/*Bit 7: Search up/down*/ +#define BCM4325_FM_SEARCH_CTRL0_UP 0x80 +#define BCM4325_FM_SEARCH_CTRL0_DOWN 0x00 + +/* Defines for FM_SEARCH_TUNE_MODE register */ +#define BCM4325_FM_TERMINATE_SEARCH_TUNE_MODE 0x00 +#define BCM4325_FM_PRE_SET_MODE 0x01 +#define BCM4325_FM_AUTO_SEARCH_MODE 0x02 +#define BCM4325_FM_AF_JUMP_MODE 0x03 + +#define BCM4325_FM_FLAG_SEARCH_TUNE_FINISHED 0x01 +#define BCM4325_FM_FLAG_SEARCH_TUNE_FAIL 0x02 +#define BCM4325_FM_FLAG_RSSI_LOW 0x04 +#define BCM4325_FM_FLAG_CARRIER_ERROR_HIGH 0x08 +#define BCM4325_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10 +#define BCM4325_FLAG_STEREO_DETECTION 0x20 +#define BCM4325_FLAG_STEREO_ACTIVE 0x40 + +#define BCM4325_RDS_FLAG_FIFO_WLINE 0x02 +#define BCM4325_RDS_FLAG_B_BLOCK_MATCH 0x08 +#define BCM4325_RDS_FLAG_SYNC_LOST 0x10 +#define BCM4325_RDS_FLAG_PI_MATCH 0x20 + +#define BCM4325_SEARCH_NORMAL 0x00 +#define BCM4325_SEARCH_PRESET 0x01 +#define BCM4325_SEARCH_RSSI 0x02 + +#define BCM4325_FREQ_64MHZ 64000 + +#define BCM4325_SEARCH_RSSI_60DB 94 + +int hci_w(int reg, int val) +{ + int returnval = 0; + + char s1[100] = "hcitool cmd 0x3f 0x15 "; + char stemp[10] = ""; + char starget[100] = ""; + char *pstarget = starget; + + sprintf(stemp, "0x%x ", reg); + pstarget = strcat(s1, stemp); + + sprintf(stemp, "0x%x ", 0); + pstarget = strcat(pstarget, stemp); + + sprintf(stemp, "0x%x ", val); + pstarget = strcat(pstarget, stemp); + returnval = system(pstarget); + return returnval; +} + +int hci_r(int reg) +{ + int returnval = 0; + + char s1[100] = "hcitool cmd 0x3f 0x15 "; + char stemp[10] = ""; + char starget[100] = ""; + char *pstarget = starget; + + sprintf(stemp, "0x%x ", reg); + pstarget=strcat(s1, stemp); + + sprintf(stemp, "0x%x ", 1); + pstarget=strcat(pstarget, stemp); + + sprintf(stemp, "0x%x ", 1); + pstarget = strcat(pstarget, stemp); + returnval = system(pstarget); + returnval /= 0x100; + LOGD("hci_r 0x%x \n", returnval); + + return returnval; +} + +using namespace android; + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_acquireFdNative +(JNIEnv* env, jobject thiz, jstring path) +{ + int fd; + int i; + char value = 0; + int init_success = 0; + LOGD("Radio starting\n"); + + hci_w(BCM4325_I2C_FM_RDS_SYSTEM, BCM4325_FM_RDS_SYSTEM_FM); + + /* Write the POWER register again. If this fails, then we're screwed. */ + if (hci_w(BCM4325_I2C_FM_RDS_SYSTEM,BCM4325_FM_RDS_SYSTEM_FM) < 0){ + return FM_JNI_FAILURE; + } + + /* Write the band setting, mno/stereo blend setting */ + if(hci_w(BCM4325_I2C_FM_CTRL, BCM4325_FM_CTRL_MANUAL |BCM4325_FM_CTRL_STEREO) < 0){ + return FM_JNI_FAILURE; + } + + if (hci_w(BCM4325_I2C_FM_AUDIO_CTRL0, + BCM4325_FM_AUDIO_CTRL0_DAC_OUT_LEFT_ON | BCM4325_FM_AUDIO_CTRL0_DAC_OUT_RIGHT_ON | + BCM4325_FM_AUDIO_CTRL0_ROUTE_DAC_ENABLE | BCM4325_FM_AUDIO_CTRL0_DEMPH_75US) < 0) { + return FM_JNI_FAILURE; + } + + return FM_JNI_SUCCESS; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_closeFdNative + (JNIEnv * env, jobject thiz, jint fd) +{ + LOGD("Radio close\n"); + + if (hci_w(BCM4325_I2C_FM_RDS_SYSTEM,BCM4325_FM_RDS_SYSTEM_OFF) < 0){ + return FM_JNI_FAILURE; + } + return FM_JNI_SUCCESS; +} + +/******************************************************************** + * Current JNI + *******************************************************************/ + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_getFreqNative + (JNIEnv * env, jobject thiz, jint fd) +{ + int retval; + int freq = 103900; + + retval = hci_r(BCM4325_I2C_FM_FREQ1); + freq = retval << 8; + retval = hci_r(BCM4325_I2C_FM_FREQ0); + freq += (retval + BCM4325_FREQ_64MHZ); + + return freq; +} + +/*native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_setFreqNative + (JNIEnv * env, jobject thiz, jint fd, jint freq) +{ + /* Adjust frequency to be an offset from 64MHz */ + freq -= BCM4325_FREQ_64MHZ; + + /* Write the FREQ0 register */ + hci_w(BCM4325_I2C_FM_FREQ0, freq & 0xFF); + + /* Write the FREQ1 register */ + hci_w(BCM4325_I2C_FM_FREQ1, freq >> 8); + + /* Write the TUNER_MODE register to PRESET to actually start tuning */ + if ( hci_w(BCM4325_I2C_FM_SEARCH_TUNE_MODE, BCM4325_FM_PRE_SET_MODE) < 0){ + LOGE("fail \n"); + } + + return 0; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_setControlNative + (JNIEnv * env, jobject thiz, jint fd, jint id, jint value) +{ + if (value == 1) { + LOGD("Radio ON \n"); + } + if (value == 2) { + LOGD("Radio OFF\n"); + if (hci_w(BCM4325_I2C_FM_RDS_SYSTEM,BCM4325_FM_RDS_SYSTEM_OFF) < 0){ + return FM_JNI_FAILURE; + } + } + if (value == 3) { + LOGD("MUTE off \n"); + } + if (value == 4) { + LOGD("MUTE on \n"); + } + + return FM_JNI_SUCCESS; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_getControlNative + (JNIEnv * env, jobject thiz, jint fd, jint id) +{ + return FM_JNI_SUCCESS; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_startSearchNative + (JNIEnv * env, jobject thiz, jint fd, jint dir) +{ + return FM_JNI_SUCCESS; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_cancelSearchNative + (JNIEnv * env, jobject thiz, jint fd) +{ + return FM_JNI_SUCCESS; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_getRSSINative + (JNIEnv * env, jobject thiz, jint fd) +{ + return FM_JNI_SUCCESS; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_setBandNative + (JNIEnv * env, jobject thiz, jint fd, jint low, jint high) +{ + return FM_JNI_SUCCESS; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_getLowerBandNative + (JNIEnv * env, jobject thiz, jint fd) +{ + return FM_JNI_SUCCESS; +} + +static jint android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative + (JNIEnv * env, jobject thiz, jint fd, jint val) +{ + return FM_JNI_SUCCESS; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_getBufferNative + (JNIEnv * env, jobject thiz, jint fd, jbooleanArray buff, jint index) +{ + return index; +} + +/* native interface */ +static jint android_hardware_fmradio_FmReceiverJNI_getRawRdsNative + (JNIEnv * env, jobject thiz, jint fd, jbooleanArray buff, jint count) +{ + return FM_JNI_SUCCESS; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "acquireFdNative", "(Ljava/lang/String;)I", + (void*)android_hardware_fmradio_FmReceiverJNI_acquireFdNative}, + { "closeFdNative", "(I)I", + (void*)android_hardware_fmradio_FmReceiverJNI_closeFdNative}, + { "getFreqNative", "(I)I", + (void*)android_hardware_fmradio_FmReceiverJNI_getFreqNative}, + { "setFreqNative", "(II)I", + (void*)android_hardware_fmradio_FmReceiverJNI_setFreqNative}, + { "getControlNative", "(II)I", + (void*)android_hardware_fmradio_FmReceiverJNI_getControlNative}, + { "setControlNative", "(III)I", + (void*)android_hardware_fmradio_FmReceiverJNI_setControlNative}, + { "startSearchNative", "(II)I", + (void*)android_hardware_fmradio_FmReceiverJNI_startSearchNative}, + { "cancelSearchNative", "(I)I", + (void*)android_hardware_fmradio_FmReceiverJNI_cancelSearchNative}, + { "getRSSINative", "(I)I", + (void*)android_hardware_fmradio_FmReceiverJNI_getRSSINative}, + { "setBandNative", "(III)I", + (void*)android_hardware_fmradio_FmReceiverJNI_setBandNative}, + { "getLowerBandNative", "(I)I", + (void*)android_hardware_fmradio_FmReceiverJNI_getLowerBandNative}, + { "getBufferNative", "(I[BI)I", + (void*)android_hardware_fmradio_FmReceiverJNI_getBufferNative}, + { "setMonoStereoNative", "(II)I", + (void*)android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative}, + { "getRawRdsNative", "(I[BI)I", + (void*)android_hardware_fmradio_FmReceiverJNI_getRawRdsNative}, +}; + +int register_android_hardware_fm_fmradio(JNIEnv* env) +{ + return jniRegisterNativeMethods(env, "android/hardware/fmradio/FmReceiverJNI", gMethods, NELEM(gMethods)); +} |