summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorxinyu <ac.milan@miui.com>2010-10-12 18:57:14 +0800
committerSteve Kondik <shade@chemlab.org>2010-10-12 22:09:36 -0400
commit350dcf82f0c95d15ae286240d9792a6d90891f4e (patch)
tree8e270fe5ceb4476b147f6fe81fef14c838807411 /core
parente1237a907ec418a830ae369069aae6715d5dc844 (diff)
downloadframeworks_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.java188
-rw-r--r--core/java/android/hardware/fmradio/FmReceiver.java1684
-rw-r--r--core/java/android/hardware/fmradio/FmReceiverJNI.java176
-rw-r--r--core/java/android/hardware/fmradio/FmRxControls.java313
-rw-r--r--core/java/android/hardware/fmradio/FmRxEvCallbacks.java46
-rw-r--r--core/java/android/hardware/fmradio/FmRxEvCallbacksAdaptor.java52
-rw-r--r--core/java/android/hardware/fmradio/FmRxEventListner.java153
-rw-r--r--core/java/android/hardware/fmradio/FmRxRdsData.java204
-rw-r--r--core/java/android/hardware/fmradio/FmTransceiver.java446
-rw-r--r--core/java/android/hardware/fmradio/FmTransmitter.java584
-rw-r--r--core/jni/Android.mk5
-rw-r--r--core/jni/AndroidRuntime.cpp7
-rw-r--r--core/jni/android_hardware_fm.cpp427
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));
+}