/*
* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of The Linux Foundation nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package qcom.fmradio;
import android.os.SystemProperties;
import android.util.Log;
import java.io.File;
/** FmTransceiver
is the superclass of classes
* FmReceiver
and FmTransmitter
* @hide
*/
public class FmTransceiver
{
/* Primary FM States :
* FM will be in one of the 4 states at any point of time
* '0' - FMState_Turned_Off
* '1' - FMState_Rx_Turned_On
* '2' - FMState_Tx_Turned_On
* '3' - FMState_Srch_InProg
*/
public static final int FMState_Turned_Off = 0;
public static final int FMState_Rx_Turned_On = 1;
public static final int FMState_Tx_Turned_On = 2;
public static final int FMState_Srch_InProg = 3;
/* Intermediate FM power levels */
public static final int subPwrLevel_FMRx_Starting = 4;
public static final int subPwrLevel_FMTx_Starting = 5;
public static final int subPwrLevel_FMTurning_Off = 6;
/* Intermediate FM search levels :
* These are the sub-levels of FM Search operations : seek/scan/auto-preset.
* Used internally for distinguishing between the various search operations.
*/
public static final int subSrchLevel_NoSearch = -1;
public static final int subSrchLevel_SeekInPrg = 0;
public static final int subSrchLevel_ScanInProg = 1;
public static final int subSrchLevel_SrchListInProg = 2;
public static final int subSrchLevel_SrchComplete = 3;
public static final int subSrchLevel_SrchAbort = 4;
/* Holds the current state of the FM device */
public static int FMState = FMState_Turned_Off;
/**
* FMConfigure FM Radio band setting for US/Europe
*/
public static final int FM_US_BAND = 0;
/**
* FMConfigure FM Radio band setting for US/Europe
*/
public static final int FM_EU_BAND = 1;
/**
* FMConfigure FM Radio band setting for Japan
*/
public static final int FM_JAPAN_STANDARD_BAND = 2;
/**
* FMConfigure FM Radio band setting for Japan-Wideband
*/
public static final int FM_JAPAN_WIDE_BAND = 3;
/**
* FMConfigure FM Radio band setting for "User defined" band
*/
public static final int FM_USER_DEFINED_BAND = 4;
/**
* FM channel spacing settings = 200KHz
*/
public static final int FM_CHSPACE_200_KHZ =0;
/**
* FM channel spacing settings = 100KHz
*/
public static final int FM_CHSPACE_100_KHZ =1;
/**
* FM channel spacing settings = 50KHz
*/
public static final int FM_CHSPACE_50_KHZ =2;
/**
* FM de-emphasis/pre-emphasis settings = 75KHz
*/
public static final int FM_DE_EMP75 = 0;
/**
* FM de-emphasis/pre-emphasis settings = 50KHz
*/
public static final int FM_DE_EMP50 = 1;
/**
* RDS standard type: RBDS (North America)
*/
public static final int FM_RDS_STD_RBDS =0;
/**
* RDS standard type: RDS (Rest of the world)
*/
public static final int FM_RDS_STD_RDS =1;
/**
* RDS standard type: No RDS
*/
public static final int FM_RDS_STD_NONE =2;
protected static final int FM_RX =1;
protected static final int FM_TX =2;
private final int READY_EVENT = 0x01;
private final int TUNE_EVENT = 0x02;
private final int RDS_EVENT = 0x08;
private final int MUTE_EVENT = 0x04;
private final int SEEK_COMPLETE_EVENT = 0x03;
private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
private static final int V4L2_CID_PRIVATE_TAVARUA_ANTENNA = V4L2_CID_PRIVATE_BASE + 18;
private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK = V4L2_CID_PRIVATE_BASE + 6;
private static final int V4L2_CID_PRIVATE_TAVARUA_SET_NOTCH_FILTER = V4L2_CID_PRIVATE_BASE + 40;
private final String TAG = "FmTransceiver";
private final String V4L2_DEVICE = "/dev/radio0";
protected static int sFd;
protected FmRxControls mControl;
protected int mPowerMode;
protected FmRxEventListner mRxEvents;
protected FmRxRdsData mRdsData;
protected FmTxEventListner mTxEvents;
public static final int ERROR = -1;
/*==============================================================
FUNCTION: acquire
==============================================================*/
/**
* Allows access to the V4L2 FM device.
*
* This synchronous call allows a client to use the V4L2 FM
* device. This must be the first call issued by the client
* before any receiver interfaces can be used.
*
* This call also powers up the FM Module.
*
* @param device String that is path to radio device
*
* @return true if V4L2 FM device acquired, false if V4L2 FM
* device could not be acquired, possibly acquired by
* other client
* @see #release
*
*/
protected boolean acquire(String device){
boolean bStatus = true;
if (sFd <= 0) { // if previous open fails fd will be -ve.
sFd = FmReceiverJNI.acquireFdNative(V4L2_DEVICE);
if (sFd > 0) {
Log.d(TAG, "Opened "+ sFd);
bStatus = true;
}
else {
Log.d(TAG, "Fail to Open "+ sFd);
bStatus = false;
}
}
else {
Log.d(TAG, "Already Opened:" + sFd);
/*This should be case
* Where User try to opne the device
* secondtime.
* Case where Tx and Rx try to
* acquire the device
*/
bStatus = false;
}
return (bStatus);
}
/*==============================================================
FUNCTION: release
==============================================================*/
/**
* Releases access to the V4L2 FM device.
*
* 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. *
* 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. *
* This call also powers down the FM Module. *
* @param device String that is path to radio device * @return true if V4L2 FM device released, false if V4L2 FM * device could not be released * @see #acquire */ static boolean release(String device) { if (sFd!=0) { FmReceiverJNI.closeFdNative(sFd); sFd = 0; Log.d("FmTransceiver", "Turned off: " + sFd); } else { Log.d("FmTransceiver", "Error turning off"); } return true; } /*============================================================== FUNCTION: registerClient ==============================================================*/ /** * Registers a callback for FM receiver event notifications. *
* 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. *
* When calling this function, the client must pass a callback * function which will be used to deliver asynchronous events. * The argument callback must be a non-NULL value. If a NULL * value is passed to this function, the registration will * fail. *
* The client can choose which events will be sent from the * receiver driver by simply implementing functions for events * it wishes to receive. *
* * @param callback the 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. *
* This is a synchronous call used to unregister a client's * event callback. *
* @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. *
* 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. *
* When calling this function, the client must pass a callback * function which will be used to deliver asynchronous events. * The argument callback must be a non-NULL value. If a NULL * value is passed to this function, the registration will * fail. *
* The client can choose which events will be sent from the * receiver driver by simply implementing functions for events * it wishes to receive. *
* * @param callback the callback to handle the events events * from the FM Transmitter. * @return true if Callback registered, false if Callback * registration failed. * * @see #acquire * @see #unregisterTransmitClient * */ public boolean registerTransmitClient( FmTransmitterCallbacks callback){ boolean bReturnStatus = false; if (callback!=null) { mTxEvents.startListner(sFd, callback); bReturnStatus = true; } else { Log.d(TAG, "Null, do nothing"); } return bReturnStatus; } /*============================================================== FUNCTION: unregisterTransmitClient ==============================================================*/ /** * Unregisters Transmitter event notification callback. *
* This is a synchronous call used to unregister a Transmitter * client's event callback. *
* @return true always. * * @see #acquire * @see #release * @see #registerTransmitClient * */ public boolean unregisterTransmitClient () { mTxEvents.stopListener(); return true; } /*============================================================== FUNCTION: enable ==============================================================*/ /** * Initializes the FM device. *
* 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. *
* 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. *
* This call can only be issued by the owner of an FM * receiver. To issue this call, the client must first * successfully call #acquire. *
* @param configSettings the settings to be applied when * turning on the radio * @return true if Initialization succeeded, false if * Initialization failed. * @see #registerClient * @see #disable * */ public boolean enable (FmConfig configSettings, int device){ boolean status; //Acquire the deviceon Enable if( !acquire("/dev/radio0")){ return false; } if (new File("/etc/fm/SpurTableFile.txt").isFile()) { Log.d(TAG, "Send Spur roation table"); FmConfig.fmSpurConfig(sFd); } else { Log.d(TAG, "No existing file to do spur configuration"); } Log.d(TAG, "turning on " + device); mControl.fmOn(sFd, device); Log.d(TAG, "Calling fmConfigure"); status = FmConfig.fmConfigure (sFd, configSettings); if (!status) { Log.d(TAG, "fmConfigure failed"); FmReceiverJNI.closeFdNative(sFd); sFd = 0; } return status; } /*============================================================== FUNCTION: disable ==============================================================*/ /** * Disables the FM Device. *
* 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. *
* @return true if disabling succeeded, false if disabling * failed. *
* @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). *
* 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. *
* @param configSettings Contains settings for the FM radio * (FM band, De-emphasis, channel * spacing, RDS/RBDS mode) *
* @return true if configure succeeded, false if * configure failed. */ public boolean configure(FmConfig configSettings){ boolean status=true; int lowerFreq = configSettings.getLowerLimit(); Log.d(TAG, "fmConfigure"); status = FmConfig.fmConfigure (sFd, configSettings); status = setStation (lowerFreq); return status; } /*============================================================== FUNCTION: setStation ==============================================================*/ /** * Tunes the FM device to the specified FM frequency. *
* 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. *
* Once tuning to the specified frequency is completed, the * event callback FmRxEvRadioTuneStatus will be called. * * @param frequencyKHz Frequency (in kHz) to be tuned * (Example: 96500 = 96.5Mhz) * @return true if setStation call was placed successfully, * false if setStation failed. */ public boolean setStation (int frequencyKHz) { int ret; mControl.setFreq(frequencyKHz); ret = mControl.setStation(sFd); if(ret < 0 ) { return false; } else { return true; } } /*============================================================== FUNCTION: SetNotchFilter ==============================================================*/ /** * Sets the desired notch filter for WAN avoidance. *
* This method sets the required Notch filter based on the current * WAN band frequency to achieve the FM-WAN concurrency. * Application should listen to Data call events and call the function * on every data call connection set-u, to achieve the FM-WAN concurrency. * */ public void setNotchFilter(boolean value) { FmReceiverJNI.setNotchFilterNative(sFd, V4L2_CID_PRIVATE_TAVARUA_SET_NOTCH_FILTER, value); } /*============================================================== FUNCTION: SetAnalogMode ==============================================================*/ /** * Enable/Disable the Analog lowpower mode. *
* This method enables/disables the analog lowpower mode. * */ public boolean setAnalogMode(boolean value) { int re = mControl.setAudioPath(sFd, value); re = FmReceiverJNI.setAnalogModeNative(value); if (re == 1) return true; return false; } /*============================================================== FUNCTION: getInternalAntenna ==============================================================*/ /** * Returns true if internal FM antenna is available * *
* This method returns true is internal FM antenna is * available, false otherwise * *
* @return true/false */ public boolean getInternalAntenna() { return ((FmReceiverJNI.getControlNative(sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA) == 1) || SystemProperties.getBoolean("hw.fm.internal_antenna", false)); } /*============================================================== FUNCTION: setInternalAntenna ==============================================================*/ /** * Returns true if successful, false otherwise * *
* This method sets internal antenna type to true/false * * @param intAntenna true is Internal antenna is present * *
* @return true/false */ public boolean setInternalAntenna(boolean intAnt) { int iAntenna ; if (intAnt) iAntenna = 1; else iAntenna = 0; int re = FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna); if (re == 0) return true; return false; } /*============================================================== FUNCTION: setFMPowerState ==============================================================*/ /** * Sets the FM power state * *
* This method sets the FM power state. * *
*/ static void setFMPowerState(int state) { FMState = state; } /*============================================================== FUNCTION: getFMPowerState ==============================================================*/ /** * Returns : * * FMOff - If the FM Radio is turned off * FMRxOn - If the FM Receiver is currently turned on * FMTxOn - If the FM Transmitter is currently turned on * FMReset - If the FM Radio is reset * * Gets the FM power state * *
* This method gets the FM power state. * *
*/ public static int getFMPowerState() { return FMState; } public static boolean setRDSGrpMask(int mask) { int re; re = FmReceiverJNI.setControlNative(sFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, mask); if (re == 0) return true; else return false; } }