FM: Migrate FM Framework code base to new git
Change-Id: I4769b2381fc62d75e67c428071c320b8f63cce0e
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..1fb20d5
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,15 @@
+ifeq ($(call is-vendor-board-platform,QCOM),true)
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JNI_SHARED_LIBRARIES := libqcomfm_jni
+
+LOCAL_MODULE:= qcom.fmradio
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(LOCAL_PATH)/jni/Android.mk
+endif # is-vendor-board-platform
diff --git a/jni/Android.mk b/jni/Android.mk
new file mode 100644
index 0000000..594332f
--- /dev/null
+++ b/jni/Android.mk
@@ -0,0 +1,25 @@
+ifeq ($(call is-vendor-board-platform,QCOM),true)
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+android_hardware_fm.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libnativehelper \
+ libcutils
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_CFLAGS += -include bionic/libc/kernel/arch-arm/asm/posix_types.h
+LOCAL_CFLAGS += -include bionic/libc/kernel/arch-arm/asm/byteorder.h
+LOCAL_CFLAGS += -include bionic/libc/kernel/common/linux/types.h
+LOCAL_CFLAGS += -include bionic/libc/kernel/common/linux/posix_types.h
+LOCAL_CFLAGS += -include bionic/libc/kernel/common/linux/socket.h
+
+LOCAL_MODULE := libqcomfm_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+endif # is-vendor-board-platform
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
new file mode 100644
index 0000000..7068b83
--- /dev/null
+++ b/jni/android_hardware_fm.cpp
@@ -0,0 +1,818 @@
+/*
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "fmradio"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+#include <cutils/properties.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <media/tavarua.h>
+#include <linux/videodev2.h>
+#include <math.h>
+
+#define RADIO "/dev/radio0"
+#define FM_JNI_SUCCESS 0L
+#define FM_JNI_FAILURE -1L
+#define SEARCH_DOWN 0
+#define SEARCH_UP 1
+#define TUNE_MULT 16000
+#define HIGH_BAND 2
+#define LOW_BAND 1
+#define CAL_DATA_SIZE 23
+#define V4L2_CTRL_CLASS_USER 0x00980000
+#define V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION (V4L2_CTRL_CLASS_USER + 0x92A)
+#define V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD (V4L2_CTRL_CLASS_USER + 0x92B)
+#define V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD (V4L2_CTRL_CLASS_USER + 0x92C)
+#define TX_RT_LENGTH 63
+#define WAIT_TIMEOUT 200000 /* 200*1000us */
+#define TX_RT_DELIMITER 0x0d
+#define PS_LEN 9
+#define STD_BUF_SIZE 256
+enum search_dir_t {
+ SEEK_UP,
+ SEEK_DN,
+ SCAN_UP,
+ SCAN_DN
+};
+
+
+using namespace android;
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_acquireFdNative
+ (JNIEnv* env, jobject thiz, jstring path)
+{
+ int fd;
+ int i, retval=0, err;
+ char value[PROPERTY_VALUE_MAX] = {'\0'};
+ char versionStr[40] = {'\0'};
+ int init_success = 0;
+ jboolean isCopy;
+ v4l2_capability cap;
+ const char* radio_path = env->GetStringUTFChars(path, &isCopy);
+ if(radio_path == NULL){
+ return FM_JNI_FAILURE;
+ }
+ fd = open(radio_path, O_RDONLY, O_NONBLOCK);
+ if(isCopy == JNI_TRUE){
+ env->ReleaseStringUTFChars(path, radio_path);
+ }
+ if(fd < 0){
+ return FM_JNI_FAILURE;
+ }
+ //Read the driver verions
+ err = ioctl(fd, VIDIOC_QUERYCAP, &cap);
+
+ ALOGD("VIDIOC_QUERYCAP returns :%d: version: %d \n", err , cap.version );
+
+ if( err >= 0 ) {
+ ALOGD("Driver Version(Same as ChipId): %x \n", cap.version );
+ /*Conver the integer to string */
+ sprintf(versionStr, "%d", cap.version );
+ property_set("hw.fm.version", versionStr);
+ } else {
+ return FM_JNI_FAILURE;
+ }
+ /*Set the mode for soc downloader*/
+ property_set("hw.fm.mode", "normal");
+ /* Need to clear the hw.fm.init firstly */
+ property_set("hw.fm.init", "0");
+ property_set("ctl.start", "fm_dl");
+ sched_yield();
+ for(i=0; i<45; i++) {
+ property_get("hw.fm.init", value, NULL);
+ if (strcmp(value, "1") == 0) {
+ init_success = 1;
+ break;
+ } else {
+ usleep(WAIT_TIMEOUT);
+ }
+ }
+ ALOGE("init_success:%d after %f seconds \n", init_success, 0.2*i);
+ if(!init_success) {
+ property_set("ctl.stop", "fm_dl");
+ // close the fd(power down)
+
+ close(fd);
+ return FM_JNI_FAILURE;
+ }
+ return fd;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_closeFdNative
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ int i = 0;
+ int cleanup_success = 0;
+ char value = 0, retval =0;
+
+ property_set("ctl.stop", "fm_dl");
+ close(fd);
+ return FM_JNI_SUCCESS;
+}
+
+/********************************************************************
+ * Current JNI
+ *******************************************************************/
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getFreqNative
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ int err;
+ struct v4l2_frequency freq;
+ freq.type = V4L2_TUNER_RADIO;
+ err = ioctl(fd, VIDIOC_G_FREQUENCY, &freq);
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ return ((freq.frequency*1000)/TUNE_MULT);
+}
+
+/*native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setFreqNative
+ (JNIEnv * env, jobject thiz, jint fd, jint freq)
+{
+ int err;
+ double tune;
+ struct v4l2_frequency freq_struct;
+ freq_struct.type = V4L2_TUNER_RADIO;
+ freq_struct.frequency = (freq*TUNE_MULT/1000);
+ err = ioctl(fd, VIDIOC_S_FREQUENCY, &freq_struct);
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ return FM_JNI_SUCCESS;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setControlNative
+ (JNIEnv * env, jobject thiz, jint fd, jint id, jint value)
+{
+ struct v4l2_control control;
+ int i;
+ int err;
+ ALOGE("id(%x) value: %x\n", id, value);
+ control.value = value;
+
+ control.id = id;
+ for(i=0;i<3;i++) {
+ err = ioctl(fd,VIDIOC_S_CTRL,&control);
+ if(err >= 0){
+ return FM_JNI_SUCCESS;
+ }
+ }
+ ALOGE("setControl native returned with err %d", err);
+ return FM_JNI_FAILURE;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_SetCalibrationNative
+ (JNIEnv * env, jobject thiz, jint fd, jbyteArray buff)
+{
+
+ struct v4l2_ext_control ext_ctl;
+ char tmp[CAL_DATA_SIZE] = {0x00};
+ int err;
+ FILE* cal_file;
+
+ cal_file = fopen("/data/app/Riva_fm_cal", "r" );
+ if(cal_file != NULL) {
+ ext_ctl.id = V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION;
+ if (fread(&tmp[0],1,CAL_DATA_SIZE,cal_file) < CAL_DATA_SIZE)
+ {
+ ALOGE("File read failed");
+ return FM_JNI_FAILURE;
+ }
+ ext_ctl.string = tmp;
+ ext_ctl.size = CAL_DATA_SIZE;
+ struct v4l2_ext_controls v4l2_ctls;
+
+ v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER,
+ v4l2_ctls.count = 1,
+ v4l2_ctls.controls = &ext_ctl;
+ err = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls );
+ if(err >= 0){
+ return FM_JNI_SUCCESS;
+ }
+ }else {
+ return FM_JNI_SUCCESS;
+ }
+ return FM_JNI_SUCCESS;
+}
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getControlNative
+ (JNIEnv * env, jobject thiz, jint fd, jint id)
+{
+ struct v4l2_control control;
+ int err;
+ ALOGE("id(%x)\n", id);
+
+ control.id = id;
+ err = ioctl(fd,VIDIOC_G_CTRL,&control);
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ return control.value;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_startSearchNative
+ (JNIEnv * env, jobject thiz, jint fd, jint dir)
+{
+ ALOGE("startSearchNative: Issuing the VIDIOC_S_HW_FREQ_SEEK");
+ struct v4l2_hw_freq_seek hw_seek;
+ int err;
+ hw_seek.seek_upward = dir;
+ hw_seek.type = V4L2_TUNER_RADIO;
+ err = ioctl(fd,VIDIOC_S_HW_FREQ_SEEK,&hw_seek);
+ if(err < 0){
+ ALOGE("startSearchNative: ioctl failed!!! with error %d\n", err);
+ return FM_JNI_FAILURE;
+ } else
+ ALOGE("startSearchNative: ioctl succedded!!!");
+ return FM_JNI_SUCCESS;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_cancelSearchNative
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ struct v4l2_control control;
+ int err;
+ control.id=V4L2_CID_PRIVATE_TAVARUA_SRCHON;
+ control.value=0;
+ err = ioctl(fd,VIDIOC_S_CTRL,&control);
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ return FM_JNI_SUCCESS;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getRSSINative
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ struct v4l2_tuner tuner;
+ int err;
+
+ tuner.index = 0;
+ tuner.signal = 0;
+ err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ return tuner.signal;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setBandNative
+ (JNIEnv * env, jobject thiz, jint fd, jint low, jint high)
+{
+ struct v4l2_tuner tuner;
+ int err;
+
+ tuner.index = 0;
+ tuner.signal = 0;
+ tuner.rangelow = low * (TUNE_MULT/1000);
+ tuner.rangehigh = high * (TUNE_MULT/1000);
+ err = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ return FM_JNI_SUCCESS;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getLowerBandNative
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ struct v4l2_tuner tuner;
+ int err;
+ tuner.index = 0;
+
+ err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+ if(err < 0){
+ ALOGE("low_band value: <%x> \n", tuner.rangelow);
+ return FM_JNI_FAILURE;
+ }
+ return ((tuner.rangelow * 1000)/ TUNE_MULT);
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getUpperBandNative
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ struct v4l2_tuner tuner;
+ int err;
+ tuner.index = 0;
+
+ err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+ if(err < 0){
+ ALOGE("high_band value: <%x> \n", tuner.rangehigh);
+ return FM_JNI_FAILURE;
+ }
+ return ((tuner.rangehigh * 1000) / TUNE_MULT);
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative
+ (JNIEnv * env, jobject thiz, jint fd, jint val)
+{
+
+ struct v4l2_tuner tuner;
+ int err;
+
+ tuner.index = 0;
+ err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+
+ if(err < 0)
+ return FM_JNI_FAILURE;
+
+ tuner.audmode = val;
+ err = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+
+ if(err < 0)
+ return FM_JNI_FAILURE;
+
+ return FM_JNI_SUCCESS;
+
+}
+
+
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getBufferNative
+ (JNIEnv * env, jobject thiz, jint fd, jbooleanArray buff, jint index)
+{
+ int err;
+ jboolean isCopy;
+ struct v4l2_requestbuffers reqbuf;
+ struct v4l2_buffer v4l2_buf;
+ memset(&reqbuf, 0, sizeof (reqbuf));
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_PRIVATE;
+ reqbuf.type = V4L2_BUF_TYPE_PRIVATE;
+ reqbuf.memory = V4L2_MEMORY_USERPTR;
+ jboolean *bool_buffer = env->GetBooleanArrayElements(buff,&isCopy);
+ memset(&v4l2_buf, 0, sizeof (v4l2_buf));
+ v4l2_buf.index = index;
+ v4l2_buf.type = type;
+ v4l2_buf.length = STD_BUF_SIZE;
+ v4l2_buf.m.userptr = (unsigned long)bool_buffer;
+ err = ioctl(fd,VIDIOC_DQBUF,&v4l2_buf);
+ if(err < 0){
+ /* free up the memory in failure case*/
+ env->ReleaseBooleanArrayElements(buff, bool_buffer, 0);
+ return FM_JNI_FAILURE;
+ }
+
+ /* Always copy buffer and free up the memory */
+ env->ReleaseBooleanArrayElements(buff, bool_buffer, 0);
+
+ return v4l2_buf.bytesused;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getRawRdsNative
+ (JNIEnv * env, jobject thiz, jint fd, jbooleanArray buff, jint count)
+{
+
+ return (read (fd, buff, count));
+
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setNotchFilterNative(JNIEnv * env, jobject thiz,jint fd, jint id, jboolean aValue)
+{
+ char value[PROPERTY_VALUE_MAX] = {'\0'};
+ int init_success = 0,i;
+ char notch[20] = {0x00};
+ struct v4l2_control control;
+ int err;
+ /*Enable/Disable the WAN avoidance*/
+ property_set("hw.fm.init", "0");
+ if (aValue)
+ property_set("hw.fm.mode", "wa_enable");
+ else
+ property_set("hw.fm.mode", "wa_disable");
+
+ property_set("ctl.start", "fm_dl");
+ sched_yield();
+ for(i=0; i<10; i++) {
+ property_get("hw.fm.init", value, NULL);
+ if (strcmp(value, "1") == 0) {
+ init_success = 1;
+ break;
+ } else {
+ usleep(WAIT_TIMEOUT);
+ }
+ }
+ ALOGE("init_success:%d after %f seconds \n", init_success, 0.2*i);
+
+ property_get("notch.value", notch, NULL);
+ ALOGE("Notch = %s",notch);
+ if (!strncmp("HIGH",notch,strlen("HIGH")))
+ control.value = HIGH_BAND;
+ else if(!strncmp("LOW",notch,strlen("LOW")))
+ control.value = LOW_BAND;
+ else
+ control.value = 0;
+
+ ALOGE("Notch value : %d", control.value);
+ control.id = id;
+ err = ioctl(fd, VIDIOC_S_CTRL,&control );
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ return FM_JNI_SUCCESS;
+}
+
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setAnalogModeNative(JNIEnv * env, jobject thiz, jboolean aValue)
+{
+ int i=0;
+ char value[PROPERTY_VALUE_MAX] = {'\0'};
+ char firmwareVersion[80];
+
+ /*Enable/Disable Analog Mode FM*/
+ property_set("hw.fm.init", "0");
+ if (aValue) {
+ property_set("hw.fm.isAnalog", "true");
+ } else {
+ property_set("hw.fm.isAnalog", "false");
+ }
+ property_set("hw.fm.mode","config_dac");
+ property_set("ctl.start", "fm_dl");
+ sched_yield();
+ for(i=0; i<10; i++) {
+ property_get("hw.fm.init", value, NULL);
+ if (strcmp(value, "1") == 0) {
+ return 1;
+ } else {
+ usleep(WAIT_TIMEOUT);
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+/*
+ * Interfaces added for Tx
+*/
+
+/*native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setPTYNative
+ (JNIEnv * env, jobject thiz, jint fd, jint pty)
+{
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPTYNative\n");
+ struct v4l2_control control;
+
+ control.id = V4L2_CID_RDS_TX_PTY;
+ control.value = pty & MASK_PTY;
+
+ int err;
+ err = ioctl(fd, VIDIOC_S_CTRL,&control );
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_setPINative
+ (JNIEnv * env, jobject thiz, jint fd, jint pi)
+{
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPINative\n");
+
+ struct v4l2_control control;
+
+ control.id = V4L2_CID_RDS_TX_PI;
+ control.value = pi & MASK_PI;
+
+ int err;
+ err = ioctl(fd, VIDIOC_S_CTRL,&control );
+ if(err < 0){
+ ALOGE("->pty native failed");
+ return FM_JNI_FAILURE;
+ }
+
+ return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_startRTNative
+ (JNIEnv * env, jobject thiz, jint fd, jstring radio_text, jint count )
+{
+ ALOGD("->android_hardware_fmradio_FmReceiverJNI_startRTNative\n");
+
+ struct v4l2_ext_control ext_ctl;
+ struct v4l2_ext_controls v4l2_ctls;
+
+ int err = 0;
+ jboolean isCopy = false;
+ char* rt_string1 = NULL;
+ char* rt_string = (char*)env->GetStringUTFChars(radio_text, &isCopy);
+ if(rt_string == NULL ){
+ ALOGE("RT string is not valid \n");
+ return FM_JNI_FAILURE;
+ }
+
+ rt_string1 = (char*) malloc(TX_RT_LENGTH + 1);
+ if (rt_string1 == NULL) {
+ ALOGE("out of memory \n");
+ env->ReleaseStringUTFChars(radio_text, rt_string);
+ return FM_JNI_FAILURE;
+ }
+ memset (rt_string1, 0, TX_RT_LENGTH + 1);
+ memcpy(rt_string1, rt_string, count);
+
+ if(count < TX_RT_LENGTH)
+ rt_string1[count] = TX_RT_DELIMITER;
+
+ ext_ctl.id = V4L2_CID_RDS_TX_RADIO_TEXT;
+ ext_ctl.string = rt_string1;
+ ext_ctl.size = strlen(rt_string1) + 1;
+
+ /* form the ctrls data struct */
+ v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_FM_TX,
+ v4l2_ctls.count = 1,
+ v4l2_ctls.controls = &ext_ctl;
+
+
+ err = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls );
+ env->ReleaseStringUTFChars(radio_text, rt_string);
+ if (rt_string1 != NULL) {
+ free(rt_string1);
+ rt_string1 = NULL;
+ }
+ if(err < 0){
+ ALOGE("VIDIOC_S_EXT_CTRLS for start RT returned : %d\n", err);
+ return FM_JNI_FAILURE;
+ }
+
+ ALOGD("->android_hardware_fmradio_FmReceiverJNI_startRTNative is SUCCESS\n");
+ return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_stopRTNative
+ (JNIEnv * env, jobject thiz, jint fd )
+{
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopRTNative\n");
+ int err;
+ struct v4l2_control control;
+ control.id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT;
+
+ err = ioctl(fd, VIDIOC_S_CTRL , &control);
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopRTNative is SUCCESS\n");
+ return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_startPSNative
+ (JNIEnv * env, jobject thiz, jint fd, jstring buff, jint count )
+{
+ ALOGD("->android_hardware_fmradio_FmReceiverJNI_startPSNative\n");
+
+ struct v4l2_ext_control ext_ctl;
+ struct v4l2_ext_controls v4l2_ctls;
+ int l;
+ int err = 0;
+ jboolean isCopy = false;
+ char *ps_copy = NULL;
+ const char *ps_string = NULL;
+
+ ps_string = env->GetStringUTFChars(buff, &isCopy);
+ if (ps_string != NULL) {
+ l = strlen(ps_string);
+ if ((l > 0) && ((l + 1) == PS_LEN)) {
+ ps_copy = (char *)malloc(sizeof(char) * PS_LEN);
+ if (ps_copy != NULL) {
+ memset(ps_copy, '\0', PS_LEN);
+ memcpy(ps_copy, ps_string, (PS_LEN - 1));
+ } else {
+ env->ReleaseStringUTFChars(buff, ps_string);
+ return FM_JNI_FAILURE;
+ }
+ } else {
+ env->ReleaseStringUTFChars(buff, ps_string);
+ return FM_JNI_FAILURE;
+ }
+ } else {
+ return FM_JNI_FAILURE;
+ }
+
+ env->ReleaseStringUTFChars(buff, ps_string);
+
+ ext_ctl.id = V4L2_CID_RDS_TX_PS_NAME;
+ ext_ctl.string = ps_copy;
+ ext_ctl.size = PS_LEN;
+
+ /* form the ctrls data struct */
+ v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_FM_TX,
+ v4l2_ctls.count = 1,
+ v4l2_ctls.controls = &ext_ctl;
+
+ err = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls);
+ if (err < 0) {
+ ALOGE("VIDIOC_S_EXT_CTRLS for Start PS returned : %d\n", err);
+ free(ps_copy);
+ return FM_JNI_FAILURE;
+ }
+
+ ALOGD("->android_hardware_fmradio_FmReceiverJNI_startPSNative is SUCCESS\n");
+ free(ps_copy);
+
+ return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_stopPSNative
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopPSNative\n");
+ struct v4l2_control control;
+ control.id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME;
+
+ int err;
+ err = ioctl(fd, VIDIOC_S_CTRL , &control);
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopPSNative is SUCCESS\n");
+ return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_configureSpurTable
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ ALOGD("->android_hardware_fmradio_FmReceiverJNI_configureSpurTable\n");
+ int retval = 0;
+ struct v4l2_control control;
+
+ control.id = V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE;
+ retval = ioctl(fd, VIDIOC_S_CTRL, &control);
+ if (retval < 0) {
+ ALOGE("configureSpurTable: Failed to Write the SPUR Table\n");
+ return FM_JNI_FAILURE;
+ } else
+ ALOGD("configureSpurTable: SPUR Table Configuration successful\n");
+
+ return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative
+ (JNIEnv * env, jobject thiz, jint fd, jint repCount)
+{
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative\n");
+
+ struct v4l2_control control;
+
+ control.id = V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT;
+ control.value = repCount & MASK_TXREPCOUNT;
+
+ int err;
+ err = ioctl(fd, VIDIOC_S_CTRL,&control );
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative is SUCCESS\n");
+ return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative
+ (JNIEnv * env, jobject thiz, jint fd, jint powLevel)
+{
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative\n");
+
+ struct v4l2_control control;
+
+ control.id = V4L2_CID_TUNE_POWER_LEVEL;
+ control.value = powLevel;
+
+ int err;
+ err = ioctl(fd, VIDIOC_S_CTRL,&control );
+ if(err < 0){
+ return FM_JNI_FAILURE;
+ }
+
+ ALOGE("->android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative is SUCCESS\n");
+ 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},
+ { "getUpperBandNative", "(I)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_getUpperBandNative},
+ { "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},
+ { "setNotchFilterNative", "(IIZ)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_setNotchFilterNative},
+ { "startRTNative", "(ILjava/lang/String;I)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_startRTNative},
+ { "stopRTNative", "(I)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_stopRTNative},
+ { "startPSNative", "(ILjava/lang/String;I)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_startPSNative},
+ { "stopPSNative", "(I)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_stopPSNative},
+ { "setPTYNative", "(II)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_setPTYNative},
+ { "setPINative", "(II)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_setPINative},
+ { "setPSRepeatCountNative", "(II)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative},
+ { "setTxPowerLevelNative", "(II)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative},
+ { "setAnalogModeNative", "(Z)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_setAnalogModeNative},
+ { "SetCalibrationNative", "(I)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_SetCalibrationNative},
+ { "configureSpurTable", "(I)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_configureSpurTable},
+
+};
+
+int register_android_hardware_fm_fmradio(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "qcom/fmradio/FmReceiverJNI", gMethods, NELEM(gMethods));
+}
+
+jint JNI_OnLoad(JavaVM *jvm, void *reserved)
+{
+ JNIEnv *e;
+ int status;
+ ALOGE("FM : loading QCOMM FM-JNI\n");
+
+ if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) {
+ ALOGE("JNI version mismatch error");
+ return JNI_ERR;
+ }
+
+ if ((status = register_android_hardware_fm_fmradio(e)) < 0) {
+ ALOGE("jni adapter service registration failure, status: %d", status);
+ return JNI_ERR;
+ }
+ return JNI_VERSION_1_6;
+}
diff --git a/qcom/fmradio/FmConfig.java b/qcom/fmradio/FmConfig.java
new file mode 100644
index 0000000..3044cc2
--- /dev/null
+++ b/qcom/fmradio/FmConfig.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+import android.util.Log;
+import android.os.SystemProperties;
+
+
+/**
+ *
+ * Class to be used when changing radio settings
+ * @hide
+ */
+public class FmConfig {
+
+ /* V4l2 Controls */
+ 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 int V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM = V4L2_CID_PRIVATE_BASE + 0x2B;
+
+ 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 (final int fd, final FmConfig configSettings) {
+
+ int re;
+
+ Log.v (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() );
+
+ boolean fmSrchAlg = SystemProperties.getBoolean("persist.fm.new.srch.algorithm",false);
+ if (fmSrchAlg) {
+ Log.v (TAG, "fmConfigure() : FM Srch Alg : NEW ");
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, 1);
+ }
+ else {
+ Log.v (TAG, "fmConfigure() : FM Srch Alg : OLD ");
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, 0);
+ }
+ if (re < 0)
+ return false;
+
+ re = FmReceiverJNI.setBandNative (fd, configSettings.getLowerLimit(), configSettings.getUpperLimit());
+ if (re < 0)
+ return false;
+
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_REGION, configSettings.mRadioBand);
+ /* setControlNative for V4L2_CID_PRIVATE_TAVARUA_REGION triggers the config change*/
+ if (re < 0)
+ return false;
+
+ return true;
+ }
+
+}
diff --git a/qcom/fmradio/FmReceiver.java b/qcom/fmradio/FmReceiver.java
new file mode 100644
index 0000000..969656b
--- /dev/null
+++ b/qcom/fmradio/FmReceiver.java
@@ -0,0 +1,2342 @@
+/*
+ * Copyright (c) 2009,2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+import android.util.Log;
+
+/**
+ * This class contains all interfaces and types needed to
+ * Control the FM receiver.
+ * @hide
+ */
+public class FmReceiver extends FmTransceiver
+{
+
+ public static int mSearchState = 0;
+
+ static final int STD_BUF_SIZE = 256;
+ static final int GRP_3A = 64;
+ private static final String TAG = "FMRadio";
+
+ /**
+ * Search (seek/scan/searchlist) by decrementing the frequency
+ *
+ * @see #FM_RX_SEARCHDIR_UP
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ * @see #searchStationList
+ */
+ public static final int FM_RX_SEARCHDIR_DOWN=0;
+ /**
+ * Search (seek/scan/searchlist) by inrementing the frequency
+ *
+ * @see #FM_RX_SEARCHDIR_DOWN
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ * @see #searchStationList
+ */
+ public static final int FM_RX_SEARCHDIR_UP=1;
+
+ /**
+ * Scan dwell (Preview) duration = 0 seconds
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_DWELL_PERIOD_0S=0;
+ /**
+ * Scan dwell (Preview) duration = 1 second
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_DWELL_PERIOD_1S=1;
+ /**
+ * Scan dwell (Preview) duration = 2 seconds
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_DWELL_PERIOD_2S=2;
+ /**
+ * Scan dwell (Preview) duration = 3 seconds
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_DWELL_PERIOD_3S=3;
+ /**
+ * Scan dwell (Preview) duration = 4 seconds
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_DWELL_PERIOD_4S=4;
+ /**
+ * Scan dwell (Preview) duration = 5 seconds
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_DWELL_PERIOD_5S=5;
+ /**
+ * Scan dwell (Preview) duration = 6 seconds
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_DWELL_PERIOD_6S=6;
+ /**
+ * Scan dwell (Preview) duration = 7 second
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_DWELL_PERIOD_7S=7;
+
+
+ /**
+ * Basic Seek Mode Option
+ *
+ * @see #searchStations(int, int, int)
+ */
+ public static final int FM_RX_SRCH_MODE_SEEK =0;
+ /**
+ * Basic Scan Mode Option
+ *
+ * @see #searchStations(int, int, int)
+ */
+ public static final int FM_RX_SRCH_MODE_SCAN =1;
+
+ /**
+ * Search list mode Options to search for Strong stations
+ *
+ * @see #searchStationList
+ */
+ public static final int FM_RX_SRCHLIST_MODE_STRONG =2;
+ /**
+ * Search list mode Options to search for Weak stations
+ *
+ * @see #searchStationList
+ */
+ public static final int FM_RX_SRCHLIST_MODE_WEAK =3;
+
+ /**
+ * Seek by Program Type
+ *
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_SRCHRDS_MODE_SEEK_PTY =4;
+ /**
+ * Scan by Program Type
+ *
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_SRCHRDS_MODE_SCAN_PTY =5;
+ /**
+ * Seek by Program identification
+ *
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_SRCHRDS_MODE_SEEK_PI =6;
+ /**
+ * Seek Alternate Frequency for the same station
+ *
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_SRCHRDS_MODE_SEEK_AF =7;
+ /**
+ * Search list mode Options to search for Strongest stations
+ *
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_SRCHLIST_MODE_STRONGEST =8;
+ /**
+ * Search list mode Options to search for Weakest stations
+ *
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public static final int FM_RX_SRCHLIST_MODE_WEAKEST =9;
+
+ /**
+ * Maximum number of stations the SearchStationList can
+ * support
+ *
+ * @see #searchStationList
+ */
+ public static final int FM_RX_SRCHLIST_MAX_STATIONS =12;
+
+ /**
+ * Argument option for setMuteMode to unmute FM
+ *
+ * @see #setMuteMode
+ */
+ public static final int FM_RX_UNMUTE =0;
+ /**
+ * Argument option for setMuteMode to Mute FM
+ *
+ * @see #setMuteMode
+ */
+ public static final int FM_RX_MUTE =1;
+
+ /**
+ * Argument option for setStereoMode to set FM to Stereo
+ * Mode.
+ *
+ * @see #setStereoMode
+ */
+ public static final int FM_RX_AUDIO_MODE_STEREO =0;
+ /**
+ * Argument option for setStereoMode to set FM to "Force
+ * Mono" Mode.
+ *
+ * @see #setStereoMode
+ */
+ public static final int FM_RX_AUDIO_MODE_MONO =1;
+
+ /**
+ * Signal Strength
+ *
+ * @see #setSignalThreshold
+ * @see #getSignalThreshold
+ */
+ public static final int FM_RX_SIGNAL_STRENGTH_VERY_WEAK =0;
+ public static final int FM_RX_SIGNAL_STRENGTH_WEAK =1;
+ public static final int FM_RX_SIGNAL_STRENGTH_STRONG =2;
+ public static final int FM_RX_SIGNAL_STRENGTH_VERY_STRONG=3;
+
+ /**
+ * Power settings
+ *
+ * @see #setPowerMode
+ * @see #getPowerMode
+ */
+ public static final int FM_RX_NORMAL_POWER_MODE =0;
+ public static final int FM_RX_LOW_POWER_MODE =1;
+
+
+
+ /**
+ * RDS Processing Options
+ *
+ * @see #registerRdsGroupProcessing
+ * @see #getPSInfo
+ * @see #getRTInfo
+ * @see #getAFInfo
+ */
+ public static final int FM_RX_RDS_GRP_RT_EBL =1;
+ public static final int FM_RX_RDS_GRP_PS_EBL =2;
+ public static final int FM_RX_RDS_GRP_AF_EBL =4;
+ public static final int FM_RX_RDS_GRP_PS_SIMPLE_EBL =16;
+
+
+ private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH = V4L2_CID_PRIVATE_BASE + 8;
+
+
+ private static final int TAVARUA_BUF_SRCH_LIST=0;
+ private static final int TAVARUA_BUF_EVENTS=1;
+ private static final int TAVARUA_BUF_RT_RDS=2;
+ private static final int TAVARUA_BUF_PS_RDS=3;
+ private static final int TAVARUA_BUF_RAW_RDS=4;
+ private static final int TAVARUA_BUF_AF_LIST=5;
+ private static final int TAVARUA_BUF_MAX=6;
+
+ private FmRxEvCallbacksAdaptor mCallback;
+ /**
+ * Internal Constants for Signal thresholds
+ *
+ * @see #setSignalThreshold
+ * @see #getSignalThreshold
+ */
+ private static final int FM_RX_RSSI_LEVEL_VERY_WEAK = -105;
+ private static final int FM_RX_RSSI_LEVEL_WEAK = -100;
+ private static final int FM_RX_RSSI_LEVEL_STRONG = -96;
+ private static final int FM_RX_RSSI_LEVEL_VERY_STRONG = -90;
+
+ /**
+ * BUF_TYPE
+ */
+ private static final int BUF_ERT = 12;
+ private static final int BUF_RTPLUS = 11;
+
+ private static final int LEN_IND = 0;
+ private static final int RT_OR_ERT_IND = 1;
+ private static final int ENCODE_TYPE_IND = 1;
+ private static final int ERT_DIR_IND = 2;
+ /**
+ * Constructor for the receiver Object
+ */
+ public FmReceiver(){
+ mControl = new FmRxControls();
+ mRdsData = new FmRxRdsData (sFd);
+ mRxEvents = new FmRxEventListner();
+ }
+
+ /**
+ * Constructor for the receiver Object that takes path to
+ * radio and event callbacks.
+ * <p>
+ * @param devicePath FM Device path String.
+ * @param callback the callbacks to handle the events
+ * events from the FM receiver.
+ *
+ */
+ public FmReceiver(String devicePath,
+ FmRxEvCallbacksAdaptor callback) throws InstantiationException {
+ mControl = new FmRxControls();
+ mRxEvents = new FmRxEventListner();
+
+ //registerClient(callback);
+ mCallback = callback;
+ }
+
+
+ /*==============================================================
+ FUNCTION: registerClient
+ ==============================================================*/
+ /**
+ * Registers a callback for FM receiver event
+ * notifications.
+ * <p>
+ * This is a synchronous command used to register for event
+ * notifications from the FM receiver driver. Since the FM
+ * driver performs some tasks asynchronously, this function
+ * allows the client to receive information asynchronously.
+ * <p>
+ * When calling this function, the client must pass a callback
+ * function which will be used to deliver asynchronous events.
+ * The argument callback must be a non-NULL value. If a NULL
+ * value is passed to this function, the registration will
+ * fail.
+ * <p>
+ * The client can choose which events will be sent from the
+ * receiver driver by simply implementing functions for events
+ * it wishes to receive.
+ * <p>
+ * @param callback the callbacks to handle the events
+ * events from the FM receiver.
+ * @return true if Callback registered, false if Callback
+ * registration failed.
+ * <p>
+ * @see #acquire
+ * @see #unregisterClient
+ *
+ */
+ public boolean registerClient(FmRxEvCallbacks callback){
+ boolean status;
+ status = super.registerClient(callback);
+ /* Do Receiver Specific Stuff here.*/
+
+ return status;
+ }
+
+ /*==============================================================
+ FUNCTION: unregisterClient
+ ==============================================================*/
+ /**
+ * UnRegisters a client's event notification callback.
+ *
+ * This is a synchronous command used to unregister a client's
+ * event callback.
+ * <p>
+ * @return true Always returns true.
+ * <p>
+ * @see #acquire
+ * @see #release
+ * @see #registerClient
+ *
+ */
+ public boolean unregisterClient () {
+ boolean status;
+
+ status = super.unregisterClient();
+
+ /* Do Receiver Specific Stuff here.*/
+ return status;
+ }
+
+ /*==============================================================
+ FUNCTION: enable
+ ==============================================================*/
+ /**
+ * Enables the FM device in Receiver Mode.
+ * <p>
+ * This is a synchronous method used to initialize the FM
+ * receiver. If already initialized this function will
+ * intialize the receiver with default settings. Only after
+ * successfully calling this function can many of the FM device
+ * interfaces be used.
+ * <p>
+ * When enabling the receiver, the client must also provide
+ * the regional settings in which the receiver will operate.
+ * These settings (included in argument configSettings) are
+ * typically used for setting up the FM receiver for operating
+ * in a particular geographical region. These settings can be
+ * changed after the FM driver is enabled through the use of
+ * the function {@link #configure}.
+ * <p>
+ * This command can only be issued by the owner of an FM
+ * receiver. To issue this command, the client must first
+ * successfully call {@link #acquire}.
+ * <p>
+ * @param configSettings the settings to be applied when
+ * turning on the radio
+ * @return true if Initialization succeeded, false if
+ * Initialization failed.
+ * <p>
+ * @see #enable
+ * @see #registerClient
+ * @see #disable
+ *
+ */
+ public boolean enable (FmConfig configSettings){
+ boolean status = false;
+ /*
+ * Check for FM State.
+ * If FMRx already on, then return.
+ */
+ int state = getFMState();
+ if (state == FMState_Rx_Turned_On || state == FMState_Srch_InProg) {
+ Log.d(TAG, "enable: FM already turned On and running");
+ return status;
+ }
+ else if (state == subPwrLevel_FMTurning_Off) {
+ Log.v(TAG, "FM is in the process of turning off.Pls wait for sometime.");
+ return status;
+ }
+ else if (state == subPwrLevel_FMRx_Starting) {
+ Log.v(TAG, "FM is in the process of turning On.Pls wait for sometime.");
+ return status;
+ }
+
+ setFMPowerState(subPwrLevel_FMRx_Starting);
+ Log.v(TAG, "enable: CURRENT-STATE : FMOff ---> NEW-STATE : FMRxStarting");
+ status = super.enable(configSettings, FmTransceiver.FM_RX);
+
+ if( status == true ) {
+ /* Do Receiver Specific Enable Stuff here.*/
+ status = registerClient(mCallback);
+ mRdsData = new FmRxRdsData(sFd);
+ }
+ else {
+ status = false;
+ Log.e(TAG, "enable: Error while turning FM On");
+ Log.e(TAG, "enable: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMOff");
+ setFMPowerState(FMState_Turned_Off);
+ }
+ return status;
+ }
+
+ /*==============================================================
+ FUNCTION: reset
+ ==============================================================*/
+ /**
+ * Reset the FM Device.
+ * <p>
+ * This is a synchronous command used to reset the state of FM
+ * device in case of unrecoverable error. This function is
+ * expected to be used when the client receives unexpected
+ * notification of radio disabled. Once called, most
+ * functionality offered by the FM device will be disabled
+ * until the client re-enables the device again via
+ * {@link #enable}.
+ * <p>
+ * @return true if reset succeeded, false if reset failed.
+ * @see #enable
+ * @see #disable
+ * @see #registerClient
+ */
+ public boolean reset(){
+ boolean status = false;
+ int state = getFMState();
+
+ if(state == FMState_Turned_Off) {
+ Log.d(TAG, "FM already turned Off.");
+ return false;
+ }
+
+ setFMPowerState(FMState_Turned_Off);
+ Log.v(TAG, "reset: NEW-STATE : FMState_Turned_Off");
+
+ status = unregisterClient();
+
+ release("/dev/radio0");
+
+ return status;
+ }
+
+ /*==============================================================
+ FUNCTION: disable
+ ==============================================================*/
+ /**
+ * Disables the FM Device.
+ * <p>
+ * This is a synchronous command used to disable the FM
+ * device. This function is expected to be used when the
+ * client no longer requires use of the FM device. Once
+ * called, most functionality offered by the FM device will be
+ * disabled until the client re-enables the device again via
+ * {@link #enable}.
+ * <p>
+ * @return true if disabling succeeded, false if disabling
+ * failed.
+ * @see #enable
+ * @see #registerClient
+ */
+ public boolean disable(){
+ boolean status = false;
+ /*
+ * Check for FM State. If search is in progress, then cancel the search prior
+ * to disabling FM.
+ */
+ int state = getFMState();
+ switch(state) {
+ case FMState_Turned_Off:
+ Log.d(TAG, "FM already tuned Off.");
+ return false;
+ case FMState_Srch_InProg:
+ Log.v(TAG, "disable: Cancelling the on going search operation prior to disabling FM");
+ setSearchState(subSrchLevel_SrchAbort);
+ cancelSearch();
+ Log.v(TAG, "disable: Wait for the state to change from : Search ---> FMRxOn");
+ try {
+ /*
+ * The delay of 50ms here is very important.
+ * This delay is useful for the cleanup purpose
+ * when HS is abruptly plugged out when search
+ * is in progress.
+ */
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ break;
+ case subPwrLevel_FMRx_Starting:
+ /*
+ * If, FM is in the process of turning On, then wait for
+ * the turn on operation to complete before turning off.
+ */
+ Log.d(TAG, "disable: FM not yet turned On...");
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ /* Check for the state of FM device */
+ state = getFMState();
+ if(state == subPwrLevel_FMRx_Starting) {
+ Log.e(TAG, "disable: FM in bad state");
+ return status;
+ }
+ break;
+ case subPwrLevel_FMTurning_Off:
+ /*
+ * If, FM is in the process of turning Off, then wait for
+ * the turn off operation to complete.
+ */
+ Log.v(TAG, "disable: FM is getting turned Off.");
+ return status;
+ }
+
+ setFMPowerState(subPwrLevel_FMTurning_Off);
+ Log.v(TAG, "disable: CURRENT-STATE : FMRxOn ---> NEW-STATE : FMTurningOff");
+ super.disable();
+
+ return true;
+ }
+
+ /*==============================================================
+ FUNCTION: getSearchState
+ ==============================================================*/
+ /**
+ * Gets the current state of the search operation.
+ * <p>
+ * This function is expected to be used when searchStations()
+ * function wants to know whether any seek/scan/auto-select
+ * operation is already in-progress.
+ * If a seek command is issued when one is already in-progress,
+ * we cancel the on-going seek command and start a new search
+ * operation.
+ * <p>
+ * @return current state of FM Search operation:
+ * SRCH_COMPLETE
+ * SRCH_INPROGRESS
+ * SRCH_ABORTED
+ */
+ static int getSearchState()
+ {
+ return mSearchState;
+ }
+
+ /*==============================================================
+ FUNCTION: setSearchState
+ ==============================================================*/
+ /**
+ * Sets the current state of the search operation.
+ * <p>
+ * This function is used to set the current state of the
+ * search operation. If a seek command is issued when one
+ * is already in-progress, we cancel the on-going seek command,
+ * set the state of search operation to SRCH_ABORTED
+ * and start a new search.
+ * <p>
+ * @return none
+ */
+ static void setSearchState(int state)
+ {
+ mSearchState = state;
+ switch(mSearchState) {
+ case subSrchLevel_SeekInPrg:
+ case subSrchLevel_ScanInProg:
+ case subSrchLevel_SrchListInProg:
+ setFMPowerState(FMState_Srch_InProg);
+ break;
+ case subSrchLevel_SrchComplete:
+ /* Update the state of the FM device */
+ setFMPowerState(FMState_Rx_Turned_On);
+ break;
+ }
+ }
+
+ /*==============================================================
+ FUNCTION: searchStations
+ ==============================================================*/
+ /**
+ * Initiates basic seek and scan operations.
+ * <p>
+ * This command is used to invoke a basic seek/scan of the FM
+ * radio band.
+ * <p>
+ * <ul>
+ * This API is used to:
+ * <li> Invoke basic seek operations ({@link
+ * #FM_RX_SRCH_MODE_SEEK})
+ * <li> Invoke basic scan operations ({@link
+ * #FM_RX_SRCH_MODE_SCAN})
+ * </ul>
+ * <p>
+ * The most basic operation performed by this function
+ * is a {@link #FM_RX_SRCH_MODE_SEEK} command. The seek
+ * process is handled incrementing or decrementing the
+ * frequency in pre-defined channel steps (defined by the
+ * channel spacing) and measuring the resulting signal level.
+ * Once a station is successfully tuned and found to meet or
+ * exceed this signal level, the seek operation will be
+ * completed and a FmRxEvSearchComplete event will be returned
+ * to the client. If no stations are found to match the search
+ * criteria, the frequency will be returned to the originally
+ * tuned station.
+ * <p>
+ * Since seek always results in a frequency being tuned, each
+ * seek operation will also return a single
+ * FmRxEvRadioTuneStatus event to the client/application
+ * layer.
+ * <p>
+ * Much like {@link #FM_RX_SRCH_MODE_SEEK}, a {@link
+ * #FM_RX_SRCH_MODE_SCAN} command can be likened to many back
+ * to back seeks with a dwell period after each successful
+ * seek. Once issued, a scan will either increment or
+ * decrement frequencies by the defined channel spacing until
+ * a station is found to meet or exceed the set search
+ * threshold. Once this station is found, and is successfully
+ * tuned, an FmRxEvRadioTuneStatus event will be returned to
+ * the client and the station will remain tuned for the
+ * specific period of time indicated by argument dwellPeriod.
+ * After that time expires, an FmRxEvSearchInProgress event
+ * will be sent to the client and a new search will begin for
+ * the next station that meets the search threshold. After
+ * scanning the entire band, or after a cancel search has been
+ * initiated by the client, an FmRxEvRadioTuneStatus event
+ * will be sent to the client. Similar to a seek command, each
+ * scan will result in at least one station being tuned, even
+ * if this is the starting frequency.
+ * <p>
+ * Each time the driver initiates a search (seek or scan) the client
+ * will be notified via an FmRxEvSearchInProgress event.
+ * Similarly, each time a search completes, the client will be notified via an
+ * FmRxEvRadioTuneStatus event.
+ * <p>
+ * Once issuing a search command, several commands from the client
+ * may be disallowed until the search is completed or cancelled.
+ * <p>
+ * The search can be canceled at any time by using API
+ * cancelSearch (). Once cancelled, each search will tune to the
+ * last tuned station and generate both FmRxEvSearchComplete and
+ * FmRxEvRadioTuneStatus events.
+ * Valid Values for argument 'mode':
+ * <ul>
+ * <li>{@link #FM_RX_SRCH_MODE_SEEK}
+ * <li>{@link #FM_RX_SRCH_MODE_SCAN}
+ * </ul>
+ * <p>
+ * Valid Values for argument 'dwellPeriod' :
+ * <ul>
+ * <li>{@link #FM_RX_DWELL_PERIOD_1S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_2S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_3S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_4S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_5S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_6S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_7S}
+ * </ul>
+ * <p>
+ * Valid Values for argument 'direction' :
+ * <ul>
+ * <li>{@link #FM_RX_SEARCHDIR_DOWN}
+ * <li>{@link #FM_RX_SEARCHDIR_UP}
+ * </ul>
+ * <p>
+ *
+ * <p>
+ * @param mode the FM search mode.
+ * @param dwellPeriod the FM scan dwell time. Used only when
+ * mode={@link #FM_RX_SRCH_MODE_SCAN}
+ * @param direction the Search Direction.
+ * <p>
+ * @return true if Search Initiate succeeded, false if
+ * Search Initiate failed.
+ *
+ * @see #searchStations(int, int, int, int, int)
+ * @see #searchStationList
+ */
+ public boolean searchStations (int mode,
+ int dwellPeriod,
+ int direction){
+
+ int state = getFMState();
+ boolean bStatus = true;
+ int re;
+
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "searchStations: Device currently busy in executing another command.");
+ return false;
+ }
+
+ Log.d (TAG, "Basic search...");
+
+ /* Validate the arguments */
+ if ( (mode != FM_RX_SRCH_MODE_SEEK) &&
+ (mode != FM_RX_SRCH_MODE_SCAN))
+ {
+ Log.d (TAG, "Invalid search mode: " + mode );
+ bStatus = false;
+ }
+ if ( (dwellPeriod < FM_RX_DWELL_PERIOD_0S ) ||
+ (dwellPeriod > FM_RX_DWELL_PERIOD_7S))
+ {
+ Log.d (TAG, "Invalid dwelling time: " + dwellPeriod);
+ bStatus = false;
+ }
+ if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
+ (direction != FM_RX_SEARCHDIR_UP))
+ {
+ Log.d (TAG, "Invalid search direction: " + direction);
+ bStatus = false;
+ }
+
+ if (bStatus)
+ {
+ Log.d (TAG, "searchStations: mode " + mode + "direction: " + direction);
+
+ if (mode == FM_RX_SRCH_MODE_SEEK)
+ setSearchState(subSrchLevel_SeekInPrg);
+ else if (mode == FM_RX_SRCH_MODE_SCAN)
+ setSearchState(subSrchLevel_ScanInProg);
+ Log.v(TAG, "searchStations: CURRENT-STATE : FMRxOn ---> NEW-STATE : SearchInProg");
+
+ re = mControl.searchStations(sFd, mode, dwellPeriod, direction, 0, 0);
+ if (re != 0) {
+ Log.e(TAG, "search station failed");
+ if (getFMState() == FMState_Srch_InProg)
+ setSearchState(subSrchLevel_SrchComplete);
+ return false;
+ }
+ state = getFMState();
+ if (state == FMState_Turned_Off) {
+ Log.d(TAG, "searchStations: CURRENT-STATE : FMState_Off (unexpected)");
+ return false;
+ }
+ }
+ return bStatus;
+ }
+
+ /*==============================================================
+ FUNCTION: searchStations
+ ==============================================================*/
+ /**
+ * Initiates RDS based seek and scan operations.
+ *
+ * <p>
+ * This command allows the client to issue seeks and scans similar
+ * to commands found in basic searchStations(mode, scanTime,
+ * direction). However, each command has an additional RDS/RBDS
+ * component which must be satisfied before a station is
+ * successfully tuned. Please see searchStations(mode,
+ * scanTime, direction) for an understanding of how seeks and
+ * scans work.
+ *
+ * <p>
+ * <ul>
+ * This API is used to search stations using RDS:
+ * <li> Invokes seek based on program type ({@link
+ * #FM_RX_SRCHRDS_MODE_SEEK_PTY})
+ * <li> Invokes scan based on program type with specified dwell period
+ * ({@link #FM_RX_SRCHRDS_MODE_SCAN_PTY})
+ * <li> Invokes seek based on program identification ({@link
+ * #FM_RX_SRCHRDS_MODE_SEEK_PI})
+ * <li> Invokes seek for alternate frequency ({@link
+ * #FM_RX_SRCHRDS_MODE_SEEK_AF})
+ * </ul>
+ *
+ * <p>
+ * Much like {@link #FM_RX_SRCH_MODE_SEEK} in searchStations,
+ * {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY} allows the client to
+ * seek to stations which are broadcasting RDS/RBDS groups
+ * with a particular Program Type that matches the supplied
+ * Program Type (PTY). The behavior and events generated for a
+ * {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY} are very similar to
+ * that of {@link #FM_RX_SRCH_MODE_SEEK}, however only
+ * stations meeting the set search signal threshold and are
+ * also broadcasting the specified RDS Program Type (PTY) will
+ * be tuned. If no matching stations can be found, the
+ * original station will be re-tuned.
+ *
+ * <p>
+ * Just as {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}'s
+ * functionality matches {@link #FM_RX_SRCH_MODE_SEEK}, so
+ * does {@link #FM_RX_SRCHRDS_MODE_SCAN_PTY} match {@link
+ * #FM_RX_SRCH_MODE_SCAN}. The one of the differences between
+ * the two is that only stations meeting the set search
+ * threshold and are also broadcasting a RDS Program Type
+ * (PTY) matching tucRdsSrchPty are found and tuned. If no
+ * station is found to have the PTY as specified by argument
+ * "pty", then the original station will be re-tuned.
+ *
+ * <p> {@link #FM_RX_SRCHRDS_MODE_SEEK_PI} is used the same
+ * way as {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}, but only
+ * stations which meet the set search threshold and are also
+ * broadcasting the Program Identification matching the
+ * argument "pi" are tuned.
+ *
+ * <p>
+ * Lastly, {@link #FM_RX_SRCHRDS_MODE_SEEK_AF} functionality
+ * differs slightly compared to the other commands in this
+ * function. This command only seeks to stations which are
+ * known ahead of time to be Alternative Frequencies for the
+ * currently tune station. If no alternate frequencies are
+ * known, or if the Alternative Frequencies have weaker signal
+ * strength than the original frequency, the original
+ * frequency will be re-tuned.
+ *
+ * <p>
+ * Each time the driver initiates an RDS-based search, the client will be
+ * notified via a FmRxEvSearchInProgress event. Similarly, each
+ * time an RDS-based search completes, the client will be notified via a
+ * FmRxEvSearchComplete event.
+ *
+ * <p>
+ * Once issuing a search command, several commands from the client may be
+ * disallowed until the search is completed or canceled.
+ *
+ * <p>
+ * The search can be canceled at any time by using API
+ * cancelSearch (). Once canceled, each search will tune to the
+ * last tuned station and generate both
+ * FmRxEvSearchComplete and FmRxEvRadioTuneStatus events.
+ *
+ * Valid Values for argument 'mode':
+ * <ul>
+ * <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}
+ * <li>{@link #FM_RX_SRCHRDS_MODE_SCAN_PTY}
+ * <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_PI}
+ * <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_AF}
+ * </ul>
+ * <p>
+ * Valid Values for argument 'dwellPeriod' :
+ * <ul>
+ * <li>{@link #FM_RX_DWELL_PERIOD_1S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_2S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_3S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_4S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_5S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_6S}
+ * <li>{@link #FM_RX_DWELL_PERIOD_7S}
+ * </ul>
+ * <p>
+ * Valid Values for argument 'direction' :
+ * <ul>
+ * <li>{@link #FM_RX_SEARCHDIR_DOWN}
+ * <li>{@link #FM_RX_SEARCHDIR_UP}
+ * </ul>
+ * <p>
+ * @param mode the FM search mode.
+ * @param dwellPeriod the FM scan dwell time. Used only when
+ * mode={@link #FM_RX_SRCHRDS_MODE_SCAN_PTY}
+ * @param direction the Search Direction.
+ * @param pty the FM RDS search Program Type
+ * @param pi the FM RDS search Program Identification Code
+ * <p>
+ * @return true if Search Initiate succeeded, false if
+ * Search Initiate failed.
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStationList
+ */
+ public boolean searchStations (int mode,
+ int dwellPeriod,
+ int direction,
+ int pty,
+ int pi) {
+ boolean bStatus = true;
+ int state = getFMState();
+ int re;
+
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "searchStations: Device currently busy in executing another command.");
+ return false;
+ }
+
+ Log.d (TAG, "RDS search...");
+
+ /* Validate the arguments */
+ if ( (mode != FM_RX_SRCHRDS_MODE_SEEK_PTY)
+ && (mode != FM_RX_SRCHRDS_MODE_SCAN_PTY)
+ && (mode != FM_RX_SRCHRDS_MODE_SEEK_PI)
+ && (mode != FM_RX_SRCHRDS_MODE_SEEK_AF)
+ )
+ {
+ Log.d (TAG, "Invalid search mode: " + mode );
+ bStatus = false;
+ }
+ if ( (dwellPeriod < FM_RX_DWELL_PERIOD_1S) ||
+ (dwellPeriod > FM_RX_DWELL_PERIOD_7S))
+ {
+ Log.d (TAG, "Invalid dwelling time: " + dwellPeriod);
+ bStatus = false;
+ }
+ if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
+ (direction != FM_RX_SEARCHDIR_UP))
+ {
+ Log.d (TAG, "Invalid search direction: " + direction);
+ bStatus = false;
+ }
+
+ if (bStatus)
+ {
+ Log.d (TAG, "searchStations: mode " + mode);
+ Log.d (TAG, "searchStations: dwellPeriod " + dwellPeriod);
+ Log.d (TAG, "searchStations: direction " + direction);
+ Log.d (TAG, "searchStations: pty " + pty);
+ Log.d (TAG, "searchStations: pi " + pi);
+ setSearchState(subSrchLevel_ScanInProg);
+ re = mControl.searchStations(sFd, mode, dwellPeriod, direction, pty, pi);
+ if (re != 0) {
+ Log.e(TAG, "scan station failed");
+ if (getFMState() == FMState_Srch_InProg)
+ setSearchState(subSrchLevel_SrchComplete);
+ bStatus = false;
+ }
+ }
+ return bStatus;
+ }
+
+ /*==============================================================
+ FUNCTION: searchStationList
+ ==============================================================*/
+ /** Initiates station list search operations.
+ * <p> This method will initate a search that will generate
+ * frequency lists based on strong and weak stations found in
+ * the FM band.
+ * <p>
+ * <ul>
+ * This API is used to generate station lists which consist of:
+ * <li>strong stations (FM_RX_SRCHLIST_MODE_STRONG,FM_RX_SRCHLIST_MODE_STRONGEST)
+ * <li>weak stations (FM_RX_SRCHLIST_MODE_WEAK, FM_RX_SRCHLIST_MODE_WEAKEST)
+ * </ul>
+ * <p>
+ * The range of frequencies scanned depends on the currently set band.
+ * The driver searches for all valid stations in the band and when complete,
+ * returns a channel list based on the client's selection. The client can
+ * choose to search for a list of the strongest stations in the band, the
+ * weakest stations in the band, or the first N strong or weak
+ * stations. By setting the maximumStations argument, the
+ * client can constrain the number of frequencies returned in
+ * the list. If user specifies argument maximumStations to be
+ * 0, the search will generate the maximum number of stations
+ * possible.
+ * <p>
+ * Each time the driver initiates a list-based search, the client will be
+ * notified via an FmRxEvSearchInProgress event. Similarly, each
+ * time a list-based search completes, the client will be
+ * notified via an FmRxEvSearchListComplete event.
+ * <p>
+ * On completion of the search, the originally tuned station
+ * will be tuned and the following events will be generated:
+ * FmRxEvSearchListComplete - The search has completed.
+ * FmRxEvRadioTuneStatus - The original frequency has been
+ * re-tuned.
+ * <p>
+ * Once issuing a search command, several commands from the client may be
+ * disallowed until the search is completed or cancelled.
+ * <p>
+ * The search can be canceled at any time by using API
+ * cancelSearch (). A cancelled search is treated as a completed
+ * search and the following events will be generated:
+ * FmRxEvSearchComplete - The search has completed.
+ * FmRxEvRadioTuneStatus - The original frequency has been re-tuned.
+ * <p>
+ * Valid Values for argument 'mode':
+ * <ul>
+ * <li>{@link #FM_RX_SRCHLIST_MODE_STRONG}
+ * <li>{@link #FM_RX_SRCHLIST_MODE_WEAK}
+ * <li>{@link #FM_RX_SRCHLIST_MODE_STRONGEST}
+ * <li>{@link #FM_RX_SRCHLIST_MODE_WEAKEST}
+ * <li>FM_RX_SRCHLIST_MODE_PTY (Will be implemented in the
+ * future)
+ * </ul>
+ * <p>
+ * Valid Values for argument 'direction' :
+ * <ul>
+ * <li>{@link #FM_RX_SEARCHDIR_DOWN}
+ * <li>{@link #FM_RX_SEARCHDIR_UP}
+ * </ul>
+ * <p>
+ * Valid Values for argument 'maximumStations' : 1-12
+ * <p>
+ * @param mode the FM search mode.
+ * @param direction the Search Direction.
+ * @param maximumStations the maximum number of stations that
+ * can be returned from a search. This parameter is
+ * ignored and 12 stations are returned if the
+ * search mode is either FM_RX_SRCHLIST_MODE_STRONGEST or
+ * FM_RX_SRCHLIST_MODE_WEAKEST
+ *
+ * @param pty the FM RDS search Program Type (Not used
+ * currently)
+ * <p>
+ * @return true if Search Initiate succeeded, false if
+ * Search Initiate failed.
+ *
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int, int, int)
+ */
+ public boolean searchStationList (int mode,
+ int direction,
+ int maximumStations,
+ int pty){
+
+ int state = getFMState();
+ boolean bStatus = true;
+ int re = 0;
+
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "searchStationList: Device currently busy in executing another command.");
+ return false;
+ }
+
+ Log.d (TAG, "searchStations: mode " + mode);
+ Log.d (TAG, "searchStations: direction " + direction);
+ Log.d (TAG, "searchStations: maximumStations " + maximumStations);
+ Log.d (TAG, "searchStations: pty " + pty);
+
+ /* Validate the arguments */
+ if ( (mode != FM_RX_SRCHLIST_MODE_STRONG)
+ && (mode != FM_RX_SRCHLIST_MODE_WEAK )
+ && (mode != FM_RX_SRCHLIST_MODE_STRONGEST )
+ && (mode != FM_RX_SRCHLIST_MODE_WEAKEST )
+ )
+ {
+ bStatus = false;
+ }
+ if ( (maximumStations < 0) ||
+ (maximumStations > FM_RX_SRCHLIST_MAX_STATIONS))
+ {
+ bStatus = false;
+ }
+ if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
+ (direction != FM_RX_SEARCHDIR_UP))
+ {
+ bStatus = false;
+ }
+
+ if (bStatus)
+ {
+ setSearchState(subSrchLevel_SrchListInProg);
+ Log.v(TAG, "searchStationList: CURRENT-STATE : FMRxOn ---> NEW-STATE : SearchInProg");
+ if ((mode == FM_RX_SRCHLIST_MODE_STRONGEST) || (mode == FM_RX_SRCHLIST_MODE_WEAKEST)) {
+ mode = (mode == FM_RX_SRCHLIST_MODE_STRONGEST)?
+ FM_RX_SRCHLIST_MODE_STRONG: FM_RX_SRCHLIST_MODE_WEAK;
+ re = mControl.searchStationList(sFd, mode, 0, direction, pty);
+ }
+ else
+ re = mControl.searchStationList(sFd, mode, maximumStations, direction, pty);
+
+ if (re != 0) {
+ Log.e(TAG, "search station list failed");
+ if (getFMState() == FMState_Srch_InProg)
+ setSearchState(subSrchLevel_SrchComplete);
+ bStatus = false;
+ }
+ }
+
+ return bStatus;
+ }
+
+
+
+ /*==============================================================
+ FUNCTION: cancelSearch
+ ==============================================================*/
+ /**
+ * Cancels an ongoing search operation
+ * (seek, scan, searchlist, etc).
+ * <p>
+ * This method should be used to cancel a previously initiated
+ * search (e.g. Basic Seek/Scan, RDS Seek/Scans, Search list,
+ * etc...).
+ * <p>
+ * Once completed, this command will generate an
+ * FmRxEvSearchCancelledtr event to all registered clients.
+ * Following this event, the client may also receive search events related
+ * to the ongoing search now being complete.
+ *
+ * <p>
+ * @return true if Cancel Search initiate succeeded, false if
+ * Cancel Search initiate failed.
+ * @see #searchStations(int, int, int)
+ * @see #searchStations(int, int, int)
+ * @see #searchStationList
+ */
+ public boolean cancelSearch () {
+ boolean status = false;
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Srch_InProg) {
+ Log.v(TAG, "cancelSearch: Cancelling the on going search operation");
+ setSearchState(subSrchLevel_SrchAbort);
+ mControl.cancelSearch(sFd);
+ return true;
+ } else
+ Log.d(TAG, "cancelSearch: No on going search operation to cancel");
+ return status;
+ }
+
+ /*==============================================================
+ FUNCTION: setMuteMode
+ ==============================================================*/
+ /**
+ * Allows the muting and un-muting of the audio coming
+ * from the FM receiver.
+ * <p>
+ * This is a synchronous command used to mute or un-mute the
+ * FM audio. This command mutes the audio coming from the FM
+ * device. It is important to note that this only affects the
+ * FM audio and not any other audio system being used.
+ * <p>
+ * @param mode the mute Mode setting to apply
+ * <p>
+ * @return true if setMuteMode call was placed successfully,
+ * false if setMuteMode failed.
+ *
+ * @see #enable
+ * @see #registerClient
+ *
+ */
+ public boolean setMuteMode (int mode) {
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "setMuteMode: Device currently busy in executing another command.");
+ return false;
+ }
+ switch (mode)
+ {
+ case FM_RX_UNMUTE:
+ mControl.muteControl(sFd, false);
+ break;
+ case FM_RX_MUTE:
+ mControl.muteControl(sFd, true);
+ break;
+ default:
+ break;
+ }
+
+ return true;
+
+ }
+
+ /*==============================================================
+ FUNCTION: setStereoMode
+ ==============================================================*/
+ /**
+ * Sets the mono/stereo mode of the FM device.
+ *
+ * <p>
+ * This command allows the user to set the mono/stereo mode
+ * of the FM device. Using this function,
+ * the user can allow mono/stereo mixing or force the reception
+ * of mono audio only.
+ *
+ * @param stereoEnable true: Enable Stereo, false: Force Mono
+ *
+ * @return true if setStereoMode call was placed successfully,
+ * false if setStereoMode failed.
+ */
+ public boolean setStereoMode (boolean stereoEnable) {
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "setStereoMode: Device currently busy in executing another command.");
+ return false;
+ }
+ int re = mControl.stereoControl(sFd, stereoEnable);
+
+ if (re == 0)
+ return true;
+ return false;
+ }
+
+ /*==============================================================
+ FUNCTION: setSignalThreshold
+ ==============================================================*/
+ /**
+ * This function sets the threshold which the FM driver
+ * uses to determine which stations have service available.
+ *
+ * <p>
+ * This information is used to determine which stations are
+ * tuned during searches and Alternative Frequency jumps, as
+ * well as at what threshold FmRxEvServiceAvailable event
+ * callback are generated.
+ * <p>
+ * This is a command used to set the threshold used by the FM driver
+ * and/or hardware to determine which stations are "good" stations.
+ * Using this function, the client can allow very weak stations,
+ * relatively weak stations, relatively strong stations, or very.
+ * strong stations to be found during searches. Additionally,
+ * this threshold will be used to determine at what threshold a
+ * FmRxEvServiceAvailable event callback is generated.
+ * <p>
+ * @param threshold the new signal threshold.
+ * @return true if setSignalThreshold call was placed
+ * successfully, false if setSignalThreshold failed.
+ */
+ public boolean setSignalThreshold (int threshold) {
+
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "setSignalThreshold: Device currently busy in executing another command.");
+ return false;
+ }
+ boolean bStatus = true;
+ int re;
+ Log.d(TAG, "Signal Threshhold input: "+threshold );
+ int rssiLev = 0;
+
+ switch(threshold)
+ {
+ case FM_RX_SIGNAL_STRENGTH_VERY_WEAK:
+ rssiLev = FM_RX_RSSI_LEVEL_VERY_WEAK;
+ break;
+ case FM_RX_SIGNAL_STRENGTH_WEAK:
+ rssiLev = FM_RX_RSSI_LEVEL_WEAK;
+ break;
+ case FM_RX_SIGNAL_STRENGTH_STRONG:
+ rssiLev = FM_RX_RSSI_LEVEL_STRONG;
+ break;
+ case FM_RX_SIGNAL_STRENGTH_VERY_STRONG:
+ rssiLev = FM_RX_RSSI_LEVEL_VERY_STRONG;
+ break;
+ default:
+ /* Should never reach here */
+ bStatus = false;
+ Log.d (TAG, "Invalid threshold: " + threshold );
+ return bStatus;
+ }
+
+ if (bStatus) {
+ re=FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH, rssiLev);
+
+ if (re !=0)
+ bStatus = false;
+ }
+
+ return bStatus;
+ }
+
+ /*==============================================================
+ FUNCTION: getStationParameters
+ ==============================================================*
+ /**
+ * Returns various Paramaters related to the currently
+ * tuned station.
+ *
+ * <p>
+ * This is method retreives various parameters and statistics
+ * related to the currently tuned station. Included in these
+ * statistics are the currently tuned frequency, the RDS/RBDS
+ * sync status, the RSSI level, current mute settings and the
+ * stereo/mono status.
+ *
+ * <p>
+ * Once completed, this command will generate an asynchronous
+ * FmRxEvStationParameters event to the registered client.
+ * This event will contain the station parameters.
+ *
+ * <p>
+ * @return FmStationParameters: Object that contains
+ * all the station parameters
+ public FmStationParameters getStationParameters () {
+ return mStationParameters;
+ }
+
+ */
+
+ /*==============================================================
+ FUNCTION: getTunedFrequency
+ ==============================================================*/
+ /**
+ * Get the Frequency of the Tuned Station
+ *
+ * @return frequencyKHz: Tuned Station Frequency (in kHz)
+ * (Example: 96500 = 96.5Mhz)
+ * ERROR : If device is currently executing another command
+ */
+ public int getTunedFrequency () {
+
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "getTunedFrequency: Device currently busy in executing another command.");
+ return ERROR;
+ }
+
+ int frequency = FmReceiverJNI.getFreqNative(sFd);
+
+ Log.d(TAG, "getFrequency: "+frequency);
+
+ return frequency;
+ }
+
+ /*==============================================================
+ FUNCTION: getPSInfo
+ ==============================================================*/
+ /**
+ * Returns the current RDS/RBDS Program Service
+ * Information.
+ * <p>
+ * This is a command which returns the last complete RDS/RBDS
+ * Program Service information for the currently tuned station.
+ * To use this command, the client must first register for
+ * Program Service info by receiving either the
+ * FM_RX_RDS_GRP_PS_EBL or FM_RX_RDS_GRP_PS_SIMPLE_EBL event.
+ * Under normal operating mode, this information will
+ * automatically be sent to the client. However, if the client
+ * requires this information be sent again, this function can be
+ * used.
+ *
+ * Typicaly this method needs to be called when "FmRxEvRdsPsInfo"
+ * callback is invoked.
+ *
+ * <p>
+ * @return the RDS data including the Program Service
+ * Information
+ *
+ */
+ public FmRxRdsData getPSInfo() {
+
+ byte [] buff = new byte[STD_BUF_SIZE];
+ int piLower = 0;
+ int piHigher = 0;
+
+ FmReceiverJNI.getBufferNative(sFd, buff, 3);
+ /* byte is signed ;(
+ * knock down signed bits
+ */
+ piLower = buff[3] & 0xFF;
+ piHigher = buff[2] & 0xFF;
+ int pi = ((piHigher << 8) | piLower);
+ mRdsData.setPrgmId (pi);
+ mRdsData.setPrgmType ( (int)( buff[1] & 0x1F));
+ int numOfPs = (int)(buff[0] & 0x0F);
+ try
+ {
+
+ String rdsStr = new String(buff, 5, numOfPs*8 );
+ mRdsData.setPrgmServices (rdsStr);
+
+ } catch (StringIndexOutOfBoundsException x)
+ {
+ Log.d (TAG, "Number of PS names " + numOfPs);
+ }
+ return mRdsData;
+ }
+
+ /*==============================================================
+ FUNCTION: getRTInfo
+ ==============================================================*/
+ /**
+ * Returns the current RDS/RBDS RadioText Information.
+ *
+ * <p>
+ * This is a command which returns the last complete RadioText information
+ * for the currently tuned station. For this command to return meaningful
+ * information, the client must first register for RadioText events by registerring
+ * the FM_RX_RDS_GRP_RT_EBL callback function. Under normal operating mode, this information
+ * will automatically be sent to the client. However, if the client requires
+ * this information be sent again, this function can be used.
+ *
+ * <p>
+ * Typicaly this method needs to be called when
+ * "FmRxEvRdsRtInfo" callback is invoked.
+ *
+ * <p>
+ * @return the RDS data including the Radio Text Information
+ */
+ public FmRxRdsData getRTInfo () {
+
+ byte [] buff = new byte[STD_BUF_SIZE];
+ int piLower = 0;
+ int piHigher = 0;
+
+ FmReceiverJNI.getBufferNative(sFd, buff, 2);
+ String rdsStr = new String(buff);
+ /* byte is signed ;(
+ * knock down signed bit
+ */
+ piLower = buff[3] & 0xFF;
+ piHigher = buff[2] & 0xFF;
+ int pi = ((piHigher << 8) | piLower);
+ mRdsData.setPrgmId (pi);
+ mRdsData.setPrgmType ( (int)( buff[1] & 0x1F));
+ try
+ {
+ rdsStr = rdsStr.substring(5, (int) buff[0]+ 5);
+ mRdsData.setRadioText (rdsStr);
+
+ } catch (StringIndexOutOfBoundsException x)
+ {
+ Log.d (TAG, "StringIndexOutOfBoundsException ...");
+ }
+ return mRdsData;
+ }
+
+ public FmRxRdsData getRTPlusInfo() {
+ byte []rt_plus = new byte[STD_BUF_SIZE];
+ int bytes_read;
+ String rt = "";
+ int rt_len;
+ int i, j = 2;
+ byte tag_code, tag_len, tag_start_pos;
+
+ bytes_read = FmReceiverJNI.getBufferNative(sFd, rt_plus, BUF_RTPLUS);
+ if (bytes_read > 0) {
+ if (rt_plus[RT_OR_ERT_IND] == 0)
+ rt = mRdsData.getRadioText();
+ else
+ rt = mRdsData.getERadioText();
+ if ((rt != "") && (rt != null)) {
+ rt_len = rt.length();
+ mRdsData.setTagNums(0);
+ for (i = 1; (i <= 2) && (j < rt_plus[LEN_IND]); i++) {
+ tag_code = rt_plus[j++];
+ tag_start_pos = rt_plus[j++];
+ tag_len = rt_plus[j++];
+ if (((tag_len + tag_start_pos) <= rt_len) && (tag_code > 0)) {
+ mRdsData.setTagValue(rt.substring(tag_start_pos,
+ (tag_len + tag_start_pos)), i);
+ mRdsData.setTagCode(tag_code, i);
+ }
+ }
+ } else {
+ mRdsData.setTagNums(0);
+ }
+ } else {
+ mRdsData.setTagNums(0);
+ }
+ return mRdsData;
+ }
+
+ public FmRxRdsData getERTInfo() {
+ byte [] raw_ert = new byte[STD_BUF_SIZE];
+ byte [] ert_text;
+ int i;
+ String s = "";
+ String encoding_type = "UCS-2";
+ int bytes_read;
+
+ bytes_read = FmReceiverJNI.getBufferNative(sFd, raw_ert, BUF_ERT);
+ if (bytes_read > 0) {
+ ert_text = new byte[raw_ert[LEN_IND]];
+ for(i = 3; (i - 3) < raw_ert[LEN_IND]; i++) {
+ ert_text[i - 3] = raw_ert[i];
+ }
+ if (raw_ert[ENCODE_TYPE_IND] == 1)
+ encoding_type = "UTF-8";
+ try {
+ s = new String (ert_text, encoding_type);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ mRdsData.setERadioText(s);
+ if (raw_ert[ERT_DIR_IND] == 0)
+ mRdsData.setFormatDir(false);
+ else
+ mRdsData.setFormatDir(true);
+ Log.d(TAG, "eRT: " + s + "dir: " +raw_ert[ERT_DIR_IND]);
+ }
+ return mRdsData;
+ }
+
+ /*==============================================================
+ FUNCTION: getAFInfo
+ ==============================================================*/
+ /**
+ * Returns the current RDS/RBDS Alternative Frequency
+ * Information.
+ *
+ * <p>
+ * This is a command which returns the last known Alternative Frequency
+ * information for the currently tuned station. For this command to return
+ * meaningful information, the client must first register for Alternative
+ * Frequency events by registering an FM_RX_RDS_GRP_AF_EBL call back function.
+ * Under normal operating mode, this information will automatically be
+ * sent to the client. However, if the client requires this information
+ * be sent again, this function can be used.
+ *
+ * <p>
+ * Typicaly this method needs to be called when
+ * "FmRxEvRdsAfInfo" callback is invoked.
+ *
+ * @return the RDS data including the AF Information
+ */
+ public int[] getAFInfo() {
+
+ byte [] buff = new byte[STD_BUF_SIZE];
+ int [] AfList = new int [40];
+ int lowerBand;
+
+ FmReceiverJNI.getBufferNative(sFd, buff, TAVARUA_BUF_AF_LIST);
+
+ if ((buff[4] <= 0) || (buff[4] > 25))
+ return null;
+
+ lowerBand = FmReceiverJNI.getLowerBandNative(sFd);
+ Log.d (TAG, "Low band " + lowerBand);
+
+ Log.d (TAG, "AF_buff 0: " + (buff[0] & 0xff));
+ Log.d (TAG, "AF_buff 1: " + (buff[1] & 0xff));
+ Log.d (TAG, "AF_buff 2: " + (buff[2] & 0xff));
+ Log.d (TAG, "AF_buff 3: " + (buff[3] & 0xff));
+ Log.d (TAG, "AF_buff 4: " + (buff[4] & 0xff));
+
+ for (int i=0; i<buff[4]; i++) {
+ AfList[i] = ((buff[i+4] & 0xFF) * 1000) + lowerBand;
+ Log.d (TAG, "AF : " + AfList[i]);
+ }
+
+ return AfList;
+
+ }
+
+ /*==============================================================
+ FUNCTION: setPowerMode
+ ==============================================================*/
+ /**
+ * Puts the driver into or out of low power mode.
+ *
+ * <p>
+ * This is an synchronous command which can put the FM
+ * device and driver into and out of low power mode. Low power mode
+ * should be used when the receiver is tuned to a station and only
+ * the FM audio is required. The typical scenario for low power mode
+ * is when the FM application is no longer visible.
+ *
+ * <p>
+ * While in low power mode, all normal FM and RDS indications from
+ * the FM driver will be suppressed. By disabling these indications,
+ * low power mode can result in fewer interruptions and this may lead
+ * to a power savings.
+ *
+ * <p>
+ * @param powerMode the new driver operating mode.
+ *
+ * @return true if setPowerMode succeeded, false if
+ * setPowerMode failed.
+ */
+ public boolean setPowerMode(int powerMode){
+
+ int re;
+
+ if (powerMode == FM_RX_LOW_POWER_MODE) {
+ re = mControl.setLowPwrMode (sFd, true);
+ }
+ else {
+ re = mControl.setLowPwrMode (sFd, false);
+ }
+
+ if (re == 0)
+ return true;
+ return false;
+ }
+
+ /*==============================================================
+ FUNCTION: getPowerMode
+ ==============================================================*/
+ /**
+ * Get FM device low power mode.
+ * <p>
+ * This is an synchronous method that will read the power mode
+ * of the FM device and driver.
+ * <p>
+ * @return true if the FM Device is in Low power mode and
+ * false if the FM Device in Normal power mode.
+ *
+ * @see #setPowerMode
+ */
+ public int getPowerMode(){
+
+ return mControl.getPwrMode (sFd);
+
+ }
+
+ /*==============================================================
+ FUNCTION: getRssiLimit
+ ==============================================================*/
+ /**
+ * Returns the RSSI thresholds for the FM driver.
+ *
+ * <p>
+ * This method returns the RSSI thresholds for the FM driver.
+ * This function returns a structure containing the minimum RSSI needed
+ * for reception and the minimum RSSI value where reception is perfect.
+ * The minimum RSSI value for reception is the recommended threshold where
+ * an average user would consider the station listenable. Similarly,
+ * the minimum RSSI threshold for perfect reception is the point where
+ * reception quality will improve only marginally even if the RSSI level
+ * improves greatly.
+ *
+ * <p>
+ * These settings should only be used as a guide for describing
+ * the RSSI values returned by the FM driver. Used in conjunction
+ * with getRssiInfo, the client can use the values from this
+ * function to give meaning to the RSSI levels returned by the driver.
+ *
+ * <p>
+ * @return the RSSI level
+ */
+ public int[] getRssiLimit () {
+
+ int[] rssiLimits = {0, 100};
+
+ return rssiLimits;
+ }
+
+ /*==============================================================
+ FUNCTION: getSignalThreshold
+ ==============================================================*/
+ /**
+ * This function returns:
+ * currently set signal threshold - if API invocation
+ * is successful
+ * ERROR - if device is currently
+ * executing another command
+ * <p>
+ * This value used by the FM driver/hardware to determine which
+ * stations are tuned during searches and Alternative Frequency jumps.
+ * Additionally, this level is used to determine at what
+ * threshold FmRxEvServiceAvailable are generated.
+ *
+ * <p>
+ * This is a command used to return the currently set signal
+ * threshold used by the FM driver and/or hardware. This
+ * value is used to determine. which stations are tuned
+ * during searches and Alternative Frequency jumps as well as
+ * when Service available events are generated.
+ *
+ * <p>
+ * Once completed, this command will generate an asynchronous
+ * FmRxEvGetSignalThreshold event to the registered client.
+ * This event will contain the current signal threshold
+ * level.
+ *
+ * <p>
+ * @return the signal threshold
+ */
+ public int getSignalThreshold () {
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "getSignalThreshold: Device currently busy in executing another command.");
+ return ERROR;
+ }
+ int threshold = FM_RX_SIGNAL_STRENGTH_VERY_WEAK, signalStrength;
+ int rmssiThreshold = FmReceiverJNI.getControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH);
+ Log.d(TAG, "Signal Threshhold: "+rmssiThreshold );
+
+ if ( (FM_RX_RSSI_LEVEL_VERY_WEAK < rmssiThreshold) && (rmssiThreshold <= FM_RX_RSSI_LEVEL_WEAK) )
+ {
+ signalStrength = FM_RX_RSSI_LEVEL_WEAK;
+ }
+ else if ( (FM_RX_RSSI_LEVEL_WEAK < rmssiThreshold) && (rmssiThreshold <= FM_RX_RSSI_LEVEL_STRONG))
+ {
+ signalStrength = FM_RX_RSSI_LEVEL_STRONG;
+ }
+ else if ((FM_RX_RSSI_LEVEL_STRONG < rmssiThreshold))
+ {
+ signalStrength = FM_RX_RSSI_LEVEL_VERY_STRONG;
+ }
+ else
+ {
+ signalStrength = FM_RX_RSSI_LEVEL_VERY_WEAK;
+ }
+
+ switch(signalStrength)
+ {
+ case FM_RX_RSSI_LEVEL_VERY_WEAK:
+ threshold = FM_RX_SIGNAL_STRENGTH_VERY_WEAK;
+ break;
+ case FM_RX_RSSI_LEVEL_WEAK:
+ threshold = FM_RX_SIGNAL_STRENGTH_WEAK;
+ break;
+ case FM_RX_RSSI_LEVEL_STRONG:
+ threshold = FM_RX_SIGNAL_STRENGTH_STRONG;
+ break;
+ case FM_RX_RSSI_LEVEL_VERY_STRONG:
+ threshold = FM_RX_SIGNAL_STRENGTH_VERY_STRONG;
+ break;
+ default:
+ /* Should never reach here */
+ break;
+ }
+
+ return threshold;
+ }
+
+
+ /*==============================================================
+ FUNCTION: setRdsGroupOptions
+ ==============================================================*/
+ /**
+ *
+ * This function enables or disables various RDS/RBDS
+ * group filtering and buffering features.
+ *
+ * <p>
+ * Included in these features are the RDS group enable mask, RDS/RBDS group
+ * change filter, and the RDS/RBDS group buffer size.
+ * <p>
+ * This is a function used to set or unset various Rx RDS/RBDS group filtering
+ * and buffering options in the FM driver.
+ * <p>
+ * Included in these options is the ability for the client to select
+ * which RDS/RBDS groups should be sent to the client. By default, all
+ * RDS/RBDS groups are filtered out before reaching the client. To allow one
+ * or more specific groups to be received, the client must set one or mors bits
+ * within the argument enRdsGrpsMask bitmask. Each bit in this
+ * mask corresponds to a specific RDS/RBDS group type. Once a
+ * group is enabled, and when a buffer holding those groups
+ * reaches the threshold defined by argument rdsBuffSize, the
+ * group or groups will be sent to the client as a
+ * FmRxEvRdsGroupData callback.
+ *
+ * <p>
+ * Additionally, this function also allows the client to enable or
+ * disable the RDS/RBDS group change filter. This filter allows the client
+ * to prevent duplicate groups of the same group type from being received.
+ * This filter only applies to consecutive groups, so
+ * identical groups received in different order will not be
+ * filtered out.
+ *
+ * <p>
+ * @param enRdsGrpsMask the bitMask that enables the RT/PS/AF.
+ *
+ * @param rdsBuffSize the number of RDS/RBDS groups the FM
+ * driver should buffer before sending to
+ * the client.
+ *
+ * @param enRdsChangeFilter the Flag used to determine whether
+ * the RDS/RBDS change filter
+ * should be enabled.
+ *
+ * @return true if the command was placed successfully, false
+ * if command failed.
+ *
+ */
+ public boolean setRdsGroupOptions (int enRdsGrpsMask,
+ int rdsBuffSize,
+ boolean enRdsChangeFilter)
+ {
+
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "setRdsGroupOptions: Device currently busy in executing another command.");
+ return false;
+ }
+ // Enable RDS
+ int re = mRdsData.rdsOn(true);
+
+ if (re != 0)
+ return false;
+
+ re = mRdsData.rdsGrpOptions (enRdsGrpsMask, rdsBuffSize, enRdsChangeFilter);
+
+ if (re ==0)
+ return true;
+
+ return false;
+
+ }
+
+ public boolean setRawRdsGrpMask()
+ {
+ return super.setRDSGrpMask(GRP_3A);
+ }
+ /*==============================================================
+ FUNCTION: registerRdsGroupProcessing
+ ==============================================================*/
+ /**
+ *
+ * This function enables or disables RDS/RBDS group processing features.
+ *
+ * <p>
+ * Included in these features is the ability for the FM driver
+ * to return Program Service, RadioText, and Alternative
+ * Frequency information.
+ *
+ * <p>
+ * These options free the client from the burden of collecting a continuous
+ * stream of RDS/RBDS groups and processing them. By setting the
+ * FM_RX_RDS_GRP_RT_EBL bit in argument fmGrpsToProc, the FM
+ * hardware or driver will collect RDS/RBDS 2A/2B groups and
+ * return complete RadioText strings and information in the
+ * form of a FmRxEvRdsRtInfo event. This event will be
+ * generated only when the RadioText information changes.
+ *
+ * <p>
+ * Similarly, by setting either the FM_RX_RDS_GRP_PS_EBL or
+ * FM_RX_RDS_GRP_PS_SIMPLE_EBL bit in argument fmGrpsToProc,
+ * the FM hardware or driver will collect RDS/RBDS 0A/0B
+ * groups and return Program Service information in the form
+ * of a FmRxEvRdsPsInfo event. This event will be generated
+ * whenever the Program Service information changes. This
+ * event will include one or more collected Program Service
+ * strings which can be continuously displayed by the client.
+ *
+ * <p>
+ * Additionally, by setting the FM_RX_RDS_GRP_AF_EBL bit in
+ * argument FmGrpsToProc, the FM hardware or driver will
+ * collect RDS/RBDS 0A/0B groups and return Alternative
+ * Frequency information in the form of a FmRxEvRdsAfInfo
+ * event. This event will be generated when the Alternative
+ * Frequency information changes and will include an up to
+ * date list of all known Alternative Frequencies.
+ *
+ * <p>
+ * Lastly, by setting the FM_RX_RDS_GRP_AF_JUMP_EBL bit in
+ * argument FmGrpsToProc, the FM hardware or driver will
+ * collect RDS/RBDS 0A/0B groups and automatically tune to a
+ * stronger alternative frequency when the signal level falls
+ * below the search threshold.
+ *
+ * @param fmGrpsToProc the bitMask that enables the RT/PS/AF.
+ *
+ * @return true if the command was placed successfully, false
+ * if command failed.
+ *
+ */
+ public boolean registerRdsGroupProcessing (int fmGrpsToProc){
+
+ if (mRdsData == null)
+ return false;
+
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "registerRdsGroupProcessing: Device currently busy in executing another command.");
+ return false;
+ }
+
+ // Enable RDS
+ int re = mRdsData.rdsOn(true);
+
+ if (re != 0)
+ return false;
+
+ re = mRdsData.rdsOptions (fmGrpsToProc);
+
+ if (re ==0)
+ return true;
+
+ return false;
+ }
+
+
+ /*==============================================================
+ FUNCTION: enableAFjump
+ ==============================================================*/
+ /**
+ * Enables automatic jump to alternative frequency
+ *
+ * <p>
+ * This method enables automatic seeking to stations which are
+ * known ahead of time to be Alternative Frequencies for the
+ * currently tuned station. If no alternate frequencies are
+ * known, or if the Alternative Frequencies have weaker signal
+ * strength than the original frequency, the original frequency
+ * will be re-tuned.
+ *
+ * <p>
+ * @return true if successful false otherwise.
+ */
+ public boolean enableAFjump (boolean enable) {
+
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "enableAFjump: Device currently busy in executing another command.");
+ return false;
+ }
+ // Enable RDS
+ int re = mRdsData.rdsOn(true);
+
+ if (re != 0)
+ return false;
+
+ re = mRdsData.enableAFjump(enable);
+
+ if (re == 0)
+ return true;
+
+ return false;
+ }
+
+ /*==============================================================
+ FUNCTION: getStationList
+ ==============================================================*/
+ /**
+ * Returns a frequency List of the searched stations.
+ *
+ * <p>
+ * This method retreives the results of the {@link
+ * #searchStationList}. This method should be called when the
+ * FmRxEvSearchListComplete is invoked.
+ *
+ * <p>
+ * @return An array of integers that corresponds to the
+ * frequency of the searched Stations
+ * @see #searchStationList
+ */
+ public int[] getStationList ()
+ {
+ int state = getFMState();
+ /* Check current state of FM device */
+ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+ Log.d(TAG, "getStationList: Device currently busy in executing another command.");
+ return null;
+ }
+ int[] stnList = new int [100];
+
+ stnList = mControl.stationList (sFd);
+
+ return stnList;
+
+ }
+
+
+ /*==============================================================
+ FUNCTION: getRssi
+ ==============================================================*/
+ /**
+ * Returns the signal strength of the currently tuned station
+ *
+ * <p>
+ * This method returns the signal strength of the currently
+ * tuned station.
+ *
+ * <p>
+ * @return RSSI of currently tuned station
+ */
+ public int getRssi()
+ {
+
+ int rssi = FmReceiverJNI.getRSSINative (sFd);
+
+ return rssi;
+ }
+
+ /*==============================================================
+ FUNCTION: getIoverc
+ ==============================================================*/
+ /**
+ * Returns the Estimated Interference Over Carrier of the currently tuned station
+ *
+ * <p>
+ * This method returns the Estimated Interference Over Carrier of the currently
+ * tuned station.
+ *
+ * <p>
+ * @return IOVERC of currently tuned station on Success.
+ * -1 on failure to retrieve the current IoverC.
+ */
+ public int getIoverc()
+ {
+ int re;
+ re = mControl.IovercControl(sFd);
+ return re;
+ }
+
+ /*==============================================================
+ FUNCTION: getIntDet
+ ==============================================================*/
+ /**
+ * Returns the IntDet the currently tuned station
+ *
+ * <p>
+ * This method returns the IntDet of the currently
+ * tuned station.
+ *
+ * <p>
+ * @return IntDet of currently tuned station.
+ * -1 on failure to retrieve the current IntDet
+ */
+ public int getIntDet()
+ {
+ int re;
+
+ re = mControl.IntDet(sFd);
+ return re;
+ }
+
+
+ /*==============================================================
+ FUNCTION: getMpxDcc
+ ==============================================================*/
+ /**
+ * Returns the MPX_DCC of the currently tuned station
+ *
+ * <p>
+ * This method returns the MPX_DCC of the currently
+ * tuned station.
+ *
+ * <p>
+ * @return MPX_DCC value of currently tuned station.
+ * -1 on failure to retrieve the current MPX_DCC
+ */
+ public int getMpxDcc()
+ {
+ int re;
+
+ re = mControl.Mpx_Dcc(sFd);
+ return re;
+ }
+/*==============================================================
+ FUNCTION: setHiLoInj
+ ==============================================================*/
+ /**
+ * Sets the Hi-Lo injection
+ *
+ * <p>
+ * This method sets the hi-low injection.
+ *
+ * <p>
+ */
+ public void setHiLoInj(int inj)
+ {
+ int re = mControl.setHiLoInj(sFd, inj);
+ }
+
+/*==============================================================
+ FUNCTION: getRmssiDelta
+ ==============================================================*/
+ /**
+ * Gets the value of currently set RMSSI Delta
+ *
+ * <p>
+ * This method gets the currently set RMSSI Delta value.
+ *
+ * <p>
+ */
+ public int getRmssiDelta()
+ {
+ int re = mControl.getRmssiDelta(sFd);
+ Log.d (TAG, "The value of RMSSI Delta is " + re);
+ return re;
+ }
+
+/*==============================================================
+ FUNCTION: setRmssiDel
+ ==============================================================*/
+ /**
+ * Sets the RMSSI Delta
+ *
+ * <p>
+ * This method sets the RMSSI Delta.
+ *
+ * <p>
+ */
+ public void setRmssiDel(int delta)
+ {
+ int re = mControl.setRmssiDel(sFd, delta);
+ }
+
+ /*==============================================================
+ FUNCTION: getRawRDS
+ ==============================================================*/
+ /**
+ * Returns array of Raw RDS data
+ *
+ * <p>
+ * This is a non-blocking call and it returns raw RDS data.
+ * The data is packed in groups of three bytes. The lsb and
+ * msb bytes contain RDS block while the third byte contains
+ * Block description. This call is wrapper around V4L2 read
+ * system call. The FM driver collects RDS/RBDS groups to meet
+ * the threshold described by setRdsGroupOptions() method.
+ * The call returns when one or more groups have been enabled
+ * by setRdsGroupOptions() method.
+ *
+ * @param numBlocks Number of blocks of RDS data
+ *
+ * <p>
+ * @return byte[]
+ */
+
+ public byte[] getRawRDS (int numBlocks)
+ {
+
+ byte[] rawRds = new byte [numBlocks*3];
+ int re;
+
+ re = FmReceiverJNI.getRawRdsNative (sFd, rawRds, numBlocks*3);
+
+ if (re == (numBlocks*3))
+ return rawRds;
+
+ if (re <= 0)
+ return null;
+
+ byte[] buff = new byte [re];
+
+ System.arraycopy (rawRds, 0, buff, 0 , re);
+
+ return buff;
+
+ }
+
+ /*
+ * getFMState() returns:
+ * '0' if FM State is OFF
+ * '1' if FM Rx is On
+ * '2' if FM Tx is On
+ * '3' if FM device is Searching
+ */
+ public int getFMState()
+ {
+ /* Current State of FM device */
+ int currFMState = FmTransceiver.getFMPowerState();
+ return currFMState;
+
+ }
+/*==============================================================
+ FUNCTION: setOnChannelThreshold
+ ==============================================================*/
+ /**
+ * Sets the On channel threshold value
+ *
+ * <p>
+ * This method sets the On channel threshold value.
+ *
+ * <p>
+ */
+ public boolean setOnChannelThreshold(int data)
+ {
+ int re = mControl.setOnChannelThreshold(sFd, data);
+ if (re < 0)
+ return false;
+ else
+ return true;
+ }
+
+/*==============================================================
+ FUNCTION: getOnChannelThreshold
+ ==============================================================*/
+ /**
+ * Gets the On channel threshold value
+ *
+ * <p>
+ * This method gets the currently set On channel threshold value.
+ *
+ * <p>
+ */
+ public int getOnChannelThreshold()
+ {
+ return mControl.getOnChannelThreshold(sFd);
+ }
+
+/*==============================================================
+ FUNCTION: setOffChannelThreshold
+ ==============================================================*/
+ /**
+ * Sets the Off channel threshold value
+ *
+ * <p>
+ * This method sets the Off channel threshold value.
+ *
+ * <p>
+ */
+ public boolean setOffChannelThreshold(int data)
+ {
+ int re = mControl.setOffChannelThreshold(sFd, data);
+ if (re < 0)
+ return false;
+ else
+ return true;
+ }
+/*==============================================================
+ FUNCTION: getOffChannelThreshold
+ ==============================================================*/
+ /**
+ * Gets the Off channel threshold value
+ *
+ * <p>
+ * This method gets the currently set Off channel threshold value.
+ *
+ * <p>
+ */
+ public int getOffChannelThreshold()
+ {
+ return mControl.getOffChannelThreshold(sFd);
+ }
+/*===============================================================
+ FUNCTION: getSINR
+ ==============================================================*/
+ /**
+ * Gets the SINR value of currently tuned station
+ *
+ * <p>
+ * This method gets the SINR value for currently tuned station.
+ *
+ * <p>
+ */
+ public int getSINR()
+ {
+ int re = mControl.getSINR(sFd);
+ Log.d (TAG, "The value of SINR is " + re);
+ return re;
+ }
+
+/*==============================================================
+ FUNCTION: setSINRThreshold
+ ==============================================================*/
+ /**
+ * Sets the SINR threshold value
+ *
+ * <p>
+ * This method sets the SINR threshold value.
+ *
+ * <p>
+ */
+ public boolean setSINRThreshold(int data)
+ {
+ int re = mControl.setSINRThreshold(sFd, data);
+ if (re < 0)
+ return false;
+ else
+ return true;
+ }
+
+/*==============================================================
+ FUNCTION: getSINRThreshold
+ ==============================================================*/
+ /**
+ * Gets the SINR threshold value
+ *
+ * <p>
+ * This method gets the currently set SINR threshold value.
+ *
+ * <p>
+ */
+ public int getSINRThreshold()
+ {
+ return mControl.getSINRThreshold(sFd);
+ }
+
+/*==============================================================
+ FUNCTION: setSINRsamples
+ ==============================================================*/
+ /**
+ * Sets the SINR samples
+ *
+ * <p>
+ * This method sets the number of SINR samples to calculate the SINR value.
+ *
+ * <p>
+ */
+ public boolean setSINRsamples(int data)
+ {
+ int re = mControl.setSINRsamples(sFd, data);
+ if (re < 0)
+ return false;
+ else
+ return true;
+ }
+
+/*==============================================================
+ FUNCTION: getSINRsamples
+ ==============================================================*/
+ /**
+ * Gets the SINR samples value
+ *
+ * <p>
+ * This method gets the number of currently set SINR samples.
+ *
+ * <p>
+ */
+ public int getSINRsamples()
+ {
+ return mControl.getSINRsamples(sFd);
+ }
+
+ public int updateSpurFreq(int freq, int rmssi, boolean enable)
+ {
+ return mControl.updateSpurTable(sFd, freq, rmssi, enable);
+ }
+
+ public int configureSpurTable()
+ {
+ return mControl.configureSpurTable(sFd);
+ }
+}
diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java
new file mode 100644
index 0000000..3c779c2
--- /dev/null
+++ b/qcom/fmradio/FmReceiverJNI.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+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: get upper band
+ * @param fd file descriptor of device
+ * @return Returns upper band in int form
+ */
+ static native int getUpperBandNative (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);
+
+ /**
+ * 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 setNotchFilterNative(int fd, int id, boolean value);
+
+ /**
+ * native method: enable/disable Analog Mode
+ */
+ static native int setAnalogModeNative(boolean value);
+
+ /**
+ * native method: Starts the RT transmission
+ * @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 startRTNative(int fd, String str, int count);
+
+ /**
+ * native method: Stops the RT transmission
+ * @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 stopRTNative(int fd);
+
+ /**
+ * native method: Starts the PS transmission
+ * @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 startPSNative(int fd, String str, int count);
+
+ /**
+ * native method: Stops the PS transmission
+ * @param fd file descriptor of device
+ * @param buff[] buffer
+ * @param count number of bytes to be read
+ */
+ static native int stopPSNative(int fd);
+ /**
+ * native method: Sets the Programme type for transmission
+ * @param fd file descriptor of device
+ * @param pty program type to be transmited
+ * @return {@link #FM_JNI_SUCCESS}
+ * {@link #FM_JNI_FAILURE}
+ */
+ static native int setPTYNative (int fd, int pty);
+
+ /**
+ * native method: Sets the Programme Id for transmission
+ * @param fd file descriptor of device
+ * @param pty program Id to be transmited
+ * @return {@link #FM_JNI_SUCCESS}
+ * {@link #FM_JNI_FAILURE}
+ */
+ static native int setPINative (int fd, int pi);
+
+
+ /**
+ * native method: Sets the repeat count for Programme service
+ * transmission.
+ * @param fd file descriptor of device
+ * @param repeatcount number of times PS string to be transmited
+ * repeatedly.
+ * @return {@link #FM_JNI_SUCCESS}
+ * {@link #FM_JNI_FAILURE}
+ */
+ static native int setPSRepeatCountNative(int fd, int repeatCount);
+ /**
+ * native method: Sets the power level for the tramsmitter
+ * transmission.
+ * @param fd file descriptor of device
+ * @param powLevel is the level at which transmitter operates.
+ * @return {@link #FM_JNI_SUCCESS}
+ * {@link #FM_JNI_FAILURE}
+ */
+ static native int setTxPowerLevelNative(int fd, int powLevel);
+ /**
+ * native method: Sets the calibration
+ * @param fd file descriptor of device
+ * @return {@link #FM_JNI_SUCCESS}
+ * {@link #FM_JNI_FAILURE}
+ */
+ static native int SetCalibrationNative(int fd);
+
+ /**
+ * native method: Configures the spur table
+ * @param fd file descriptor of device
+ * @return {@link #FM_JNI_SUCCESS}
+ * {@link #FM_JNI_FAILURE}
+ */
+ static native int configureSpurTable(int fd);
+}
diff --git a/qcom/fmradio/FmRxControls.java b/qcom/fmradio/FmRxControls.java
new file mode 100644
index 0000000..5c2d42c
--- /dev/null
+++ b/qcom/fmradio/FmRxControls.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+import android.util.Log;
+
+
+class FmRxControls
+{
+
+ private boolean mStateStereo;
+ private boolean mStateMute;
+ private int mFreq;
+
+ static final int FREQ_MUL = 1000;
+ static final int SEEK_FORWARD = 0;
+ static final int SEEK_BACKWARD = 1;
+ static final int SCAN_FORWARD = 2;
+ static final int SCAN_BACKWARD = 3;
+ static final int FM_DIGITAL_PATH = 0;
+ static final int FM_ANALOG_PATH = 1;
+ 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_CID_PRIVATE_TAVARUA_IOVERC = V4L2_CID_PRIVATE_BASE + 24;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_INTDET = V4L2_CID_PRIVATE_BASE + 25;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_MPX_DCC = V4L2_CID_PRIVATE_BASE + 26;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_AF_JUMP = V4L2_CID_PRIVATE_BASE + 27;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA = V4L2_CID_PRIVATE_BASE + 28;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_HLSI = V4L2_CID_PRIVATE_BASE + 29;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH = V4L2_CID_PRIVATE_BASE + 41;
+ private static final int V4L2_CID_PRIVATE_SINR = V4L2_CID_PRIVATE_BASE + 44;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD = V4L2_CID_PRIVATE_BASE + 0x2D;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD = V4L2_CID_PRIVATE_BASE + 0x2E;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD = V4L2_CID_PRIVATE_BASE + 0x2F;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES = V4L2_CID_PRIVATE_BASE + 0x30;
+ private static final int V4L2_CID_PRIVATE_SPUR_FREQ = V4L2_CID_PRIVATE_BASE + 0x31;
+ private static final int V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI = V4L2_CID_PRIVATE_BASE + 0x32;
+ private static final int V4L2_CID_PRIVATE_SPUR_SELECTION = V4L2_CID_PRIVATE_BASE + 0x33;
+
+ 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;
+
+ private int sOnData ;
+ private int sOffData ;
+
+
+
+ /*
+ * Turn on FM Rx/Tx.
+ * Rx = 1 and Tx = 2
+ */
+ public void fmOn(int fd, int device) {
+ int re;
+ FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_STATE, device );
+ setAudioPath(fd, false);
+ re = FmReceiverJNI.SetCalibrationNative(fd);
+ if (re != 0)
+ Log.d(TAG,"Calibration failed");
+ }
+
+ /*
+ * Turn off FM Rx/Tx
+ */
+ public void fmOff(int fd){
+ FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_STATE, 0 );
+ }
+
+ /*
+ * 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, 0 );
+ }
+ }
+ /*
+ * Get Interference over channel
+ */
+ public int IovercControl(int fd)
+ {
+ int ioverc = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_IOVERC);
+ Log.d(TAG, "IOVERC value is : "+ioverc);
+ return ioverc;
+ }
+ /*
+ * Get IntDet
+ */
+ public int IntDet(int fd)
+ {
+ int intdet = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_INTDET);
+ Log.d(TAG, "IOVERC value is : "+intdet);
+ return intdet;
+ }
+
+ /*
+ * Get MPX_DCC
+ */
+ public int Mpx_Dcc(int fd)
+ {
+ int mpx_dcc = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_MPX_DCC);
+ Log.d(TAG, "MPX_DCC value is : " + mpx_dcc);
+ return mpx_dcc;
+ }
+
+ /*
+ * Set Hi-Low injection
+ */
+ public int setHiLoInj(int fd, int inj)
+ {
+ int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_HLSI, inj);
+ return re;
+ }
+
+ /*
+ * Set On channel threshold
+ */
+ public int setOnChannelThreshold(int fd, int sBuff)
+ {
+ int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD, sBuff);
+ if ( re < 0)
+ Log.e(TAG, "Failed to set On channel threshold data");
+ return re;
+ }
+
+ /*
+ * Set Off channel threshold
+ */
+ public int setOffChannelThreshold(int fd, int sBuff)
+ {
+ int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD, sBuff);
+ if ( re < 0)
+ Log.e(TAG, "Failed to set Off channel Threshold data");
+ return re;
+ }
+
+ /*
+ * Get On channel threshold
+ */
+ public int getOnChannelThreshold(int fd)
+ {
+ return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD);
+ }
+
+ /*
+ * Get Off channel threshold
+ */
+ public int getOffChannelThreshold(int fd)
+ {
+ return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD);
+ }
+
+ /*
+ * Set sinr threshold
+ */
+ public int setSINRThreshold(int fd, int sBuff)
+ {
+ int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD, sBuff);
+ if ( re < 0)
+ Log.e(TAG, "Failed to set SINR threshold data");
+ return re;
+ }
+
+ /*
+ * Set number of sinr samples to take in to account for SINR avg calculation
+ */
+ public int setSINRsamples(int fd, int sBuff)
+ {
+ int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES, sBuff);
+ if ( re < 0)
+ Log.e(TAG, "Failed to set SINR samples ");
+ return re;
+ }
+
+ /*
+ * Get SINR threshold
+ */
+ public int getSINRThreshold(int fd)
+ {
+ return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD);
+ }
+
+ /*
+ * Get SINR samples
+ */
+ public int getSINRsamples(int fd)
+ {
+ return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES);
+ }
+
+ /*
+ * Get RMSSI Delta
+ */
+ public int getRmssiDelta(int fd)
+ {
+ int rmssiDel = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA);
+ return rmssiDel;
+ }
+
+ /*
+ * Set RMSSI Delta
+ */
+ public int setRmssiDel(int fd, int delta)
+ {
+ int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA, delta);
+ return re;
+ }
+
+ /*
+ * Set the audio path as analog/digital
+ */
+ public int setAudioPath(int fd, boolean value)
+ {
+ int mode;
+ if (value)
+ mode = FM_ANALOG_PATH;
+ else
+ mode = FM_DIGITAL_PATH;
+ int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH, mode);
+ return re;
+ }
+
+ /*
+ * Tune FM core to specified freq.
+ */
+ public int setStation(int fd) {
+ Log.d(TAG, "** Tune Using: "+fd);
+ int ret = FmReceiverJNI.setFreqNative(fd, mFreq);
+ Log.d(TAG, "** Returned: "+ret);
+ return 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;
+ }
+ /*
+ * Get SINR value
+ */
+ public int getSINR(int fd)
+ {
+ return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_SINR);
+ }
+
+
+ /*
+ * 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, j = 0;
+ int station_num = 0;
+ float real_freq = 0;
+ int [] stationList;
+ byte [] sList = new byte[100];
+ int tmpFreqByte1=0;
+ int tmpFreqByte2=0;
+ float lowBand, highBand;
+
+
+ lowBand = (float) (FmReceiverJNI.getLowerBandNative(fd) / 1000.00);
+ highBand = (float) (FmReceiverJNI.getUpperBandNative(fd) / 1000.00);
+
+ Log.d(TAG, "lowBand: " + lowBand);
+ Log.d(TAG, "highBand: " + highBand);
+
+ FmReceiverJNI.getBufferNative(fd, sList, 0);
+
+ if ((int)sList[0] >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 * 50) + (lowBand * FREQ_MUL);//tuner.rangelow * FREQ_MUL;
+ Log.d(TAG, " real_freq: " + real_freq);
+ if ( (real_freq < (lowBand * FREQ_MUL)) || (real_freq > (highBand * FREQ_MUL)) ) {
+ Log.e(TAG, "Frequency out of band limits");
+ }
+ else {
+ stationList[j] = (int)(real_freq);
+ Log.d(TAG, " stationList: " + stationList[j]);
+ j++;
+ }
+ }
+
+ 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 int 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);
+ if (re != 0) {
+ Log.e(TAG, "setting of search mode failed");
+ return re;
+ }
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, dwell);
+ if (re != 0) {
+ Log.e(TAG, "setting of scan dwell time failed");
+ return re;
+ }
+ if (pty != 0)
+ {
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty);
+ if (re != 0) {
+ Log.e(TAG, "setting of PTY failed");
+ return re;
+ }
+ }
+
+ if (pi != 0)
+ {
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, pi);
+ if (re != 0) {
+ Log.e(TAG, "setting of PI failed");
+ return re;
+ }
+ }
+
+ re = FmReceiverJNI.startSearchNative (fd, dir );
+ return re;
+ }
+
+ /* 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;
+
+ }
+
+ public int updateSpurTable(int fd, int freq, int rmssi, boolean enable) {
+
+ int re;
+
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_FREQ, freq);
+ if (re < 0) {
+ Log.e(TAG, "Failed to program the Spur frequency value");
+ return re;
+ }
+
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI, rmssi);
+ if (re < 0) {
+ Log.e(TAG, "Failed to program the RMSSI level of the Spur frequency");
+ return re;
+ }
+
+ if (enable) {
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_SELECTION, 1);
+ }
+ else {
+ re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_SELECTION, 0);
+ }
+ if (re < 0) {
+ Log.e(TAG, "Failed to program Spur selection");
+ return re;
+ }
+
+ return re;
+ }
+
+ public int configureSpurTable(int fd) {
+ return FmReceiverJNI.configureSpurTable(fd);
+ }
+}
diff --git a/qcom/fmradio/FmRxEvCallbacks.java b/qcom/fmradio/FmRxEvCallbacks.java
new file mode 100644
index 0000000..50d2fb2
--- /dev/null
+++ b/qcom/fmradio/FmRxEvCallbacks.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2009,2012 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+interface FmRxEvCallbacks {
+
+ public void FmRxEvEnableReceiver();
+ public void FmRxEvDisableReceiver();
+ public void FmRxEvRadioReset();
+ 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 FmRxEvSearchCancelled();
+ public void FmRxEvSearchComplete(int freq);
+ public void FmRxEvSearchListComplete();
+ public void FmRxEvRdsGroupData();
+ public void FmRxEvRdsPsInfo();
+ public void FmRxEvRdsRtInfo();
+ public void FmRxEvRdsAfInfo();
+ public void FmRxEvRTPlus();
+ public void FmRxEvERTInfo();
+}
diff --git a/qcom/fmradio/FmRxEvCallbacksAdaptor.java b/qcom/fmradio/FmRxEvCallbacksAdaptor.java
new file mode 100644
index 0000000..458ff59
--- /dev/null
+++ b/qcom/fmradio/FmRxEvCallbacksAdaptor.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009,2012 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+/**
+ *
+ * Class to be implemented for event callbacks
+ * @hide
+ */
+
+public class FmRxEvCallbacksAdaptor implements FmRxEvCallbacks {
+ public void FmRxEvEnableReceiver() {};
+ public void FmRxEvDisableReceiver() {};
+ public void FmRxEvRadioReset() {};
+ 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 FmRxEvSearchCancelled() {};
+ public void FmRxEvSearchComplete(int freq) {};
+ public void FmRxEvSearchListComplete() {};
+ public void FmRxEvRdsGroupData() {};
+ public void FmRxEvRdsPsInfo() {};
+ public void FmRxEvRdsRtInfo() {};
+ public void FmRxEvRdsAfInfo() {};
+ public void FmRxEvRTPlus() {};
+ public void FmRxEvERTInfo() {};
+}
+
diff --git a/qcom/fmradio/FmRxEventListner.java b/qcom/fmradio/FmRxEventListner.java
new file mode 100644
index 0000000..376e430
--- /dev/null
+++ b/qcom/fmradio/FmRxEventListner.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2009,2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+import qcom.fmradio.FmReceiver;
+import qcom.fmradio.FmTransceiver;
+import java.util.Arrays;
+import android.util.Log;
+
+
+class FmRxEventListner {
+
+ private final int EVENT_LISTEN = 1;
+
+ private final int STD_BUF_SIZE = 256;
+
+ 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(){
+ byte [] buff = new byte[STD_BUF_SIZE];
+ Log.d(TAG, "Starting listener " + fd);
+
+ while ((!Thread.currentThread().isInterrupted())) {
+
+ try {
+ int index = 0;
+ int state = 0;
+ Arrays.fill(buff, (byte)0x00);
+ int freq = 0;
+ int eventCount = FmReceiverJNI.getBufferNative (fd, buff, EVENT_LISTEN);
+
+ if (eventCount >= 0)
+ Log.d(TAG, "Received event. Count: " + eventCount);
+
+ for ( index = 0; index < eventCount; index++ ) {
+ Log.d(TAG, "Received <" +buff[index]+ ">" );
+
+ switch(buff[index]){
+ case 0:
+ Log.d(TAG, "Got READY_EVENT");
+ if(FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMRx_Starting) {
+ /*Set the state as FMRxOn */
+ FmTransceiver.setFMPowerState(FmTransceiver.FMState_Rx_Turned_On);
+ Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMRxOn");
+ cb.FmRxEvEnableReceiver();
+ }
+ else if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) {
+ /*Set the state as FMOff */
+ FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off);
+ Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff");
+ FmTransceiver.release("/dev/radio0");
+ cb.FmRxEvDisableReceiver();
+ Thread.currentThread().interrupt();
+ }
+ break;
+ case 1:
+ Log.d(TAG, "Got TUNE_EVENT");
+ freq = FmReceiverJNI.getFreqNative(fd);
+ if (freq > 0)
+ cb.FmRxEvRadioTuneStatus(freq);
+ else
+ Log.e(TAG, "get frequency command failed");
+ break;
+ case 2:
+ Log.d(TAG, "Got SEEK_COMPLETE_EVENT");
+ state = FmReceiver.getSearchState();
+ switch(state) {
+ case FmTransceiver.subSrchLevel_SeekInPrg :
+ case FmTransceiver.subSrchLevel_ScanInProg:
+ Log.v(TAG, "Current state is " + state);
+ FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+ Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
+ cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd));
+ break;
+ case FmTransceiver.subSrchLevel_SrchAbort:
+ Log.v(TAG, "Current state is SRCH_ABORTED");
+ Log.v(TAG, "Aborting on-going search command...");
+ FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+ Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
+ cb.FmRxEvSearchCancelled();
+ break;
+ }
+ 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");
+ state = FmReceiver.getSearchState();
+ switch(state) {
+ case FmTransceiver.subSrchLevel_SrchListInProg:
+ Log.v(TAG, "FmRxEventListener: Current state is AUTO_PRESET_INPROGRESS");
+ FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+ Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
+ cb.FmRxEvSearchListComplete ();
+ break;
+ case FmTransceiver.subSrchLevel_SrchAbort:
+ Log.v(TAG, "Current state is SRCH_ABORTED");
+ Log.v(TAG, "Aborting on-going SearchList command...");
+ FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+ Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
+ cb.FmRxEvSearchCancelled();
+ break;
+ }
+ break;
+ case 15:
+ Log.d(TAG, "Got NEW_AF_LIST");
+ cb.FmRxEvRdsAfInfo();
+ break;
+ case 18:
+ Log.d(TAG, "Got RADIO_DISABLED");
+ if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) {
+ /*Set the state as FMOff */
+ FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off);
+ Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff");
+ FmTransceiver.release("/dev/radio0");
+ cb.FmRxEvDisableReceiver();
+ Thread.currentThread().interrupt();
+ } else {
+ Log.d(TAG, "Unexpected RADIO_DISABLED recvd");
+ cb.FmRxEvRadioReset();
+ }
+ break;
+ case 19:
+ FmTransceiver.setRDSGrpMask(0);
+ break;
+ case 20:
+ Log.d(TAG, "got RT plus event");
+ cb.FmRxEvRTPlus();
+ break;
+ case 21:
+ Log.d(TAG, "got eRT event");
+ cb.FmRxEvERTInfo();
+ break;
+ default:
+ Log.d(TAG, "Unknown event");
+ break;
+ }
+ }//end of for
+ } catch ( Exception ex ) {
+ Log.d( TAG, "RunningThread InterruptedException");
+ ex.printStackTrace();
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ };
+ mThread.start();
+ }
+
+ public void stopListener(){
+ //mThread.stop();
+ //Thread stop is deprecate API
+ //Interrupt the thread and check for the thread status
+ // and return from the run() method to stop the thread
+ //properly
+ Log.d( TAG, "stopping the Listener\n");
+ if( mThread != null ) {
+ mThread.interrupt();
+ }
+ }
+
+}
diff --git a/qcom/fmradio/FmRxRdsData.java b/qcom/fmradio/FmRxRdsData.java
new file mode 100644
index 0000000..dac4194
--- /dev/null
+++ b/qcom/fmradio/FmRxRdsData.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2009,2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package qcom.fmradio;
+import android.util.Log;
+/**
+ *
+ * @hide
+ */
+public class FmRxRdsData {
+
+
+ private String mRadioText = "";
+ private String mPrgmServices;
+ private String mERadioText = "";
+ // false means left-right
+ // true means right-left
+ private boolean formatting_dir = false;
+ private byte []mTagCode = new byte[2];
+ private String []mTag = new String[2];
+ private int tag_nums = 0;
+ private static final int MAX_NUM_TAG = 2;
+ private boolean rt_ert_flag;
+ 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 V4L2_CID_PRIVATE_TAVARUA_AF_JUMP = V4L2_CID_PRIVATE_BASE + 27;
+
+
+ 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 << 6;
+ private static final int RDS_PS_ALL = 1 << 4;
+ private static final int RDS_AF_JUMP = 0x1;
+ private static final int MAX_TAG_CODES = 64;
+
+ 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)
+ {
+ int re;
+ int rds_group_mask = 0;
+
+ Log.d(LOGTAG, "In enableAFjump: AFenable : " + AFenable);
+
+ rds_group_mask = FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC);
+ Log.d(LOGTAG, "Currently set rds_group_mask : " + rds_group_mask);
+
+ if (AFenable)
+ re = FmReceiverJNI.setControlNative(mFd ,V4L2_CID_PRIVATE_TAVARUA_AF_JUMP, 1);
+ else
+ re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_AF_JUMP, 0);
+
+ rds_group_mask = FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC);
+
+ if (AFenable)
+ Log.d(LOGTAG, "After enabling the rds_group_mask is : " + rds_group_mask);
+ else
+ Log.d(LOGTAG, "After disabling the rds_group_mask is : " + rds_group_mask);
+
+ return re;
+ }
+
+
+ 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;
+ }
+ public String getERadioText () {
+ return mERadioText;
+ }
+ public void setERadioText (String x) {
+ mERadioText = x;
+ }
+ public boolean getFormatDir() {
+ return formatting_dir;
+ }
+ public void setFormatDir(boolean dir) {
+ formatting_dir = dir;
+ }
+ public void setTagValue (String x, int tag_num) {
+ if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG)) {
+ mTag[tag_num - 1] = x;
+ tag_nums++;
+ }
+ }
+ public void setTagCode (byte tag_code, int tag_num) {
+ if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG))
+ mTagCode[tag_num - 1] = tag_code;
+ }
+ public String getTagValue (int tag_num) {
+ if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG))
+ return mTag[tag_num - 1];
+ else
+ return "";
+ }
+ public byte getTagCode (int tag_num) {
+ if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG))
+ return mTagCode[tag_num - 1];
+ else
+ return 0;
+ }
+ public int getTagNums() {
+ return tag_nums;
+ }
+ public void setTagNums(int x) {
+ if ((x >= 0) && (x <= MAX_NUM_TAG))
+ tag_nums = x;
+ }
+}
diff --git a/qcom/fmradio/FmTransceiver.java b/qcom/fmradio/FmTransceiver.java
new file mode 100644
index 0000000..8a02c2d
--- /dev/null
+++ b/qcom/fmradio/FmTransceiver.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package qcom.fmradio;
+import android.util.Log;
+
+/** <code>FmTransceiver</code> is the superclass of classes
+ * <code>FmReceiver</code> and <code>FmTransmitter</code>
+ * @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_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.
+ * <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
+ */
+ 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.
+ * <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( 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.
+ * <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 () {
+ mTxEvents.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){
+
+ boolean status;
+ //Acquire the deviceon Enable
+ if( !acquire("/dev/radio0")){
+ return false;
+ }
+ 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.
+ * <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){
+ 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.
+ * <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) {
+ 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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
+ *
+ * <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: setFMPowerState
+ ==============================================================*/
+ /**
+ * Sets the FM power state
+ *
+ * <p>
+ * This method sets the FM power state.
+ *
+ * <p>
+ */
+ 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
+ *
+ * <p>
+ * This method gets the FM power state.
+ *
+ * <p>
+ */
+ 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;
+ }
+}
diff --git a/qcom/fmradio/FmTransmitter.java b/qcom/fmradio/FmTransmitter.java
new file mode 100644
index 0000000..1ae356b
--- /dev/null
+++ b/qcom/fmradio/FmTransmitter.java
@@ -0,0 +1,923 @@
+/*
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+import android.util.Log;
+
+
+/**
+ * This class contains all interfaces and types needed to control the FM transmitter.
+ * @hide
+ */
+public class FmTransmitter extends FmTransceiver
+{
+ private final String TAG = "FmTransmitter";
+ /**
+ * An object that contains the PS Features that SoC supports
+ *
+ * @see #getPSFeatures
+ */
+ public class FmPSFeatures
+ {
+ public int maxPSCharacters;
+ public int maxPSStringRepeatCount;
+ };
+
+
+ /**
+ * Command types for the RDS group transmission.
+ * This is used as argument to #transmitRdsGroupControl to
+ * control the RDS group transmission.
+ *
+ * @see #transmitRdsGroupControl
+ */
+
+ public static final int RDS_GRPS_TX_PAUSE = 0; /* Pauses the Group transmission*/
+
+ public static final int RDS_GRPS_TX_RESUME = 1; /* Resumes the Group transmission*/
+
+ public static final int RDS_GRPS_TX_STOP = 2; /* Stops and clear the Group transmission */
+
+ public static final int FM_TX_MAX_PS_LEN = (96+1);
+ public static final int FM_TX_MAX_RT_LEN = (64-1); /*One space to include NULL*/
+
+ private static final int MAX_PS_CHARS = 97;
+ private static final int MAX_PS_REP_COUNT = 15;
+ private static final int MAX_RDS_GROUP_BUF_SIZE = 62;
+
+ private FmTransmitterCallbacksAdaptor mTxCallbacks;
+ private boolean mPSStarted = false;
+ private boolean mRTStarted = false;
+ private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
+ private static final int V4L2_CID_PRIVATE_TAVARUA_ANTENNA = V4L2_CID_PRIVATE_BASE + 18;
+
+ /**
+ * Power settings
+ *
+ * @see #setPowerMode
+ * @see #getPowerMode
+ */
+ public static final int FM_TX_NORMAL_POWER_MODE =0;
+ public static final int FM_TX_LOW_POWER_MODE =1;
+
+ /**
+ * Transmit Power level settings
+ *
+ * @see #setTxPowerLevel
+ */
+ public static final int FM_TX_PWR_LEVEL_0 =0;
+ public static final int FM_TX_PWR_LEVEL_1 =1;
+ public static final int FM_TX_PWR_LEVEL_2 =2;
+ public static final int FM_TX_PWR_LEVEL_3 =3;
+ public static final int FM_TX_PWR_LEVEL_4 =4;
+ public static final int FM_TX_PWR_LEVEL_5 =5;
+ public static final int FM_TX_PWR_LEVEL_6 =6;
+ public static final int FM_TX_PWR_LEVEL_7 =7;
+
+
+ /**
+ * Constructor for the transmitter class that takes path to
+ * radio device and event callback adapter
+ */
+ public FmTransmitter(String path, FmTransmitterCallbacksAdaptor callbacks) throws InstantiationException{
+
+ mTxEvents = new FmTxEventListner();
+ mControl = new FmRxControls();
+ mTxCallbacks = callbacks;
+ }
+
+ /*==============================================================
+ FUNCTION: enable
+ ==============================================================*/
+ /**
+ * Enables the FM device in Transmit Mode.
+ * <p>
+ * This is a synchronous method used to initialize the FM
+ * device in transmitt mode. If already initialized this function will
+ * intialize the Fm device with default settings. Only after
+ * successfully calling this function can many of the FM device
+ * interfaces be used.
+ * <p>
+ * When enabling the transmitter, 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
+ * transmitter.
+ *
+ * @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 = true;
+
+ int state = getFMState();
+ if (state == FMState_Tx_Turned_On) {
+ Log.d(TAG, "enable: FM Tx already turned On and running");
+ return status;
+ } else if (state == subPwrLevel_FMTurning_Off) {
+ Log.v(TAG, "FM is in the process of turning off.Pls wait for sometime.");
+ return status;
+ } else if(state == subPwrLevel_FMTx_Starting) {
+ Log.v(TAG, "FM is in the process of turning On.Pls wait for sometime.");
+ return status;
+ }
+ setFMPowerState(subPwrLevel_FMTx_Starting);
+ Log.v(TAG, "enable: CURRENT-STATE : FMOff ---> NEW-STATE : FMTxStarting");
+ status = super.enable(configSettings, FmTransceiver.FM_TX);
+ if(status == true) {
+ registerTransmitClient(mTxCallbacks);
+ mRdsData = new FmRxRdsData(sFd);
+ } else {
+ status = false;
+ Log.e(TAG, "enable: failed to turn On FM TX");
+ Log.e(TAG, "enable: CURRENT-STATE : FMTxStarting ---> NEW-STATE : FMOff");
+ setFMPowerState(FMState_Turned_Off);
+ }
+ return status;
+ }
+ /*==============================================================
+ FUNCTION: setRdsOn
+ ==============================================================*/
+ /**
+ *
+ * This function enables RDSCTRL register for SoC.
+ *
+ * <p>
+ * This API enables the ability of the FM driver
+ * to send Program Service, RadioText information.
+ *
+ *
+ * @return true if the command was placed successfully, false
+ * if command failed.
+ *
+ */
+ public boolean setRdsOn (){
+
+ if (mRdsData == null)
+ return false;
+ // Enable RDS
+ int re = mRdsData.rdsOn(true);
+
+ if (re ==0)
+ return true;
+
+ return false;
+ }
+
+ /*==============================================================
+ 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 = false;
+ int state;
+
+ state = getFMState();
+ switch(state) {
+ case FMState_Turned_Off:
+ Log.d(TAG, "FM already tuned Off.");
+ return true;
+ case subPwrLevel_FMTx_Starting:
+ /*
+ * If, FM is in the process of turning On, then wait for
+ * the turn on operation to complete before turning off.
+ */
+ Log.d(TAG, "disable: FM not yet turned On...");
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ /* Check for the state of FM device */
+ state = getFMState();
+ if(state == subPwrLevel_FMTx_Starting) {
+ Log.e(TAG, "disable: FM in bad state");
+ return status;
+ }
+ break;
+ case subPwrLevel_FMTurning_Off:
+ /*
+ * If, FM is in the process of turning Off, then wait for
+ * the turn off operation to complete.
+ */
+ Log.v(TAG, "disable: FM is getting turned Off.");
+ return status;
+ }
+ setFMPowerState(subPwrLevel_FMTurning_Off);
+ Log.v(TAG, "disable: CURRENT-STATE : FMTxOn ---> NEW-STATE : FMTurningOff");
+ //Stop all the RDS transmissions if there any
+ if(mPSStarted) {
+ if(!stopPSInfo()) {
+ Log.d(TAG, "FmTrasmitter:stopPSInfo failed\n");
+ }
+ }
+ if(mRTStarted) {
+ if(!stopRTInfo()) {
+ Log.d(TAG, "FmTrasmitter:stopRTInfo failed\n");
+ }
+ }
+ if(!transmitRdsGroupControl(RDS_GRPS_TX_STOP) ) {
+ Log.d(TAG, "FmTrasmitter:transmitRdsGroupControl failed\n");
+ }
+ super.disable();
+ return true;
+ }
+
+ /*==============================================================
+ FUNCTION: reset
+ ==============================================================*/
+ /**
+ * Reset the FM Device.
+ * <p>
+ * This is a synchronous command used to reset the state of FM
+ * device in case of unrecoverable error. This function is
+ * expected to be used when the client receives unexpected
+ * notification of radio disabled. Once called, most
+ * functionality offered by the FM device will be disabled
+ * until the client re-enables the device again via
+ * {@link #enable}.
+ * <p>
+ * @return true if reset succeeded, false if reset failed.
+ * @see #enable
+ * @see #disable
+ * @see #registerTransmitClient
+ */
+ public boolean reset(){
+ boolean status = false;
+
+ status = unregisterTransmitClient();
+ return status;
+ }
+
+ /*==============================================================
+ 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 FmTransmitterCallbacks::onTuneStatusChange 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) {
+
+ //Stop If there is any ongoing RDS transmissions
+ boolean status = false;
+ if( mPSStarted ){
+ Log.d(TAG,"FmTransmitter:setStation mPSStarted");
+ if( !stopPSInfo() ) return status;
+ }
+ if( mRTStarted ) {
+ Log.d(TAG,"FmTransmitter:setStation mRTStarted");
+ if(!stopRTInfo()) return status;
+ }
+ if(!transmitRdsGroupControl(RDS_GRPS_TX_STOP) )return status;
+
+ Log.d(TAG, "FmTrasmitter:SetStation\n");
+ status = super.setStation(frequencyKHz);
+
+ return status;
+ }
+ /*==============================================================
+ 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_TX_LOW_POWER_MODE) {
+ re = mControl.setLowPwrMode (sFd, true);
+ }
+ else {
+ re = mControl.setLowPwrMode (sFd, false);
+ }
+
+ if (re == 0)
+ return true;
+ return false;
+ }
+
+
+ /*==============================================================
+ 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 = MAX_PS_CHARS;
+ psFeatures.maxPSStringRepeatCount = MAX_PS_REP_COUNT;
+ return psFeatures;
+ }
+
+ /*==============================================================
+ FUNCTION: startPSInfo
+ ==============================================================*/
+ /**
+ * Continuously transmit RDS/RBDS Program Service information
+ * over an already tuned station.
+ * <p>
+ * This is a synchronous 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>
+ * Maximux Programme service string lenght that can be sent is
+ * FM_TX_MAX_PS_LEN. If the application sends PS string longer than
+ * this threshold, string will be truncated to FM_TX_MAX_PS_LEN.
+ *
+ * @param psStr the program service strings to transmit
+ * @param pty the program type to use in the program Service
+ * information.
+ * @param pi 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 #stopPSInfo
+ */
+ public boolean startPSInfo(String psStr, int pty, int pi, int repeatCount){
+
+ //Set the PTY
+ if((pty < 0) || (pty > 31 )) {
+ Log.d(TAG,"pTy is expected from 0 to 31");
+ return false;
+ }
+
+ int err = FmReceiverJNI.setPTYNative( sFd, pty );
+ if( err < 0 ){
+ Log.d(TAG,"setPTYNative is failure");
+ return false;
+ }
+
+ if((pi < 0) || (pi > 65535)) {
+ Log.d(TAG,"pi is expected from 0 to 65535");
+ return false;
+ }
+
+ //Set the PI
+ err = FmReceiverJNI.setPINative( sFd, pi );
+ if( err < 0 ){
+ Log.d(TAG,"setPINative is failure");
+ return false;
+ }
+
+ if((repeatCount < 0) || (repeatCount > 15)) {
+ Log.d(TAG,"repeat count is expected from 0 to 15");
+ return false;
+ }
+
+ err = FmReceiverJNI.setPSRepeatCountNative( sFd, repeatCount );
+ if( err < 0 ){
+ Log.d(TAG,"setPSRepeatCountNative is failure");
+ return false;
+ }
+
+ if( psStr.length() > FM_TX_MAX_PS_LEN ){
+ /*truncate the PS string to
+ MAX possible length*/
+ psStr = psStr.substring( 0, FM_TX_MAX_PS_LEN );
+
+ }
+
+ err = FmReceiverJNI.startPSNative( sFd, psStr , psStr.length() );
+ Log.d(TAG,"return for startPS is "+err);
+
+ if( err < 0 ){
+ Log.d(TAG, "FmReceiverJNI.startPSNative returned false\n");
+ return false;
+
+ } else {
+ Log.d(TAG,"startPSNative is successful");
+ mPSStarted = true;
+ return true;
+ }
+ }
+
+ /*==============================================================
+ FUNCTION: stopPSInfo
+ ==============================================================*/
+ /**
+ * Stops an active Program Service transmission.
+ *
+ * <p>
+ * This is a synchrnous function used to stop an active Program Service transmission
+ * started by {@link #startPSInfo}.
+ *
+ * @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 #startPSInfo
+ *
+ */
+ public boolean stopPSInfo(){
+ int err =0;
+ if( (err =FmReceiverJNI.stopPSNative( sFd )) < 0 ){
+ Log.d(TAG,"return for startPS is "+err);
+ return false;
+ } else{
+ Log.d(TAG,"stopPSNative is successful");
+ mPSStarted = false;
+ return true;
+ }
+ }
+
+
+ /*==============================================================
+ FUNCTION: startRTInfo
+ ==============================================================*/
+ /**
+ * Continuously transmit RDS/RBDS RadioText information over an
+ * already tuned station.
+ *
+ * <p>
+ * This is a synchronous 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>
+ * <p>
+ * Maximux Radio Text string length that can be sent is
+ * FM_TX_MAX_RT_LEN. If the application sends RT string longer than
+ * this threshold, string will be truncated to FM_TX_MAX_RT_LEN.
+ *
+ * @param rtStr the Radio Text string to transmit
+ * @param pty the program type to use in the Radio text
+ * transmissions.
+ * @param pi the program identifier to use in the Radio text
+ * transmissions.
+ *
+ * @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 #stopRTInfo
+ */
+ public boolean startRTInfo(String rtStr, int pty, int pi){
+
+ if((pty < 0) || (pty > 31 )) {
+ Log.d(TAG,"pTy is expected from 0 to 31");
+ return false;
+ }
+ //Set the PTY
+ int err = FmReceiverJNI.setPTYNative( sFd, pty );
+ if( err < 0 ){
+ Log.d(TAG,"setPTYNative is failure");
+ return false;
+ }
+
+ if((pi < 0) || (pi > 65535)) {
+ Log.d(TAG,"pi is expected from 0 to 65535");
+ return false;
+ }
+
+ err = FmReceiverJNI.setPINative( sFd, pi );
+ if( err < 0 ){
+ Log.d(TAG,"setPINative is failure");
+ return false;
+ }
+
+
+ if( rtStr.length() > FM_TX_MAX_RT_LEN )
+ {
+ //truncate it to max length
+ rtStr = rtStr.substring( 0, FM_TX_MAX_RT_LEN );
+ }
+
+ err = FmReceiverJNI.startRTNative( sFd, rtStr, rtStr.length() );
+
+ if( err < 0 ){
+ Log.d(TAG, "FmReceiverJNI.startRTNative returned false\n");
+ return false;
+ } else {
+ Log.d(TAG,"mRTStarted is true");
+ mRTStarted = true;
+ return true;
+ }
+ }
+
+ /*==============================================================
+ FUNCTION: stopRTInfo
+ ==============================================================*/
+ /**
+ * Stops an active Radio Text information transmission.
+ *
+ * <p>
+ * This is a synchrnous function used to stop an active Radio Text
+ * transmission started by {@link #startRTInfo}.
+ *
+ * @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 #startRTInfo
+ *
+ */
+ public boolean stopRTInfo(){
+
+ if( FmReceiverJNI.stopRTNative( sFd ) < 0 ){
+ Log.d(TAG,"stopRTNative is failure");
+ return false;
+ } else{
+ Log.d(TAG,"mRTStarted is false");
+ mRTStarted = false;
+ return true;
+ }
+ }
+
+ /*==============================================================
+ 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 MAX_RDS_GROUP_BUF_SIZE;
+ }
+
+
+ /*==============================================================
+ FUNCTION: transmitRdsGroups
+ ==============================================================*/
+ /**
+ * This function will transmit RDS/RBDS groups
+ * over an already tuned station.
+ * This is an asynchronous function used to transmit RDS/RBDS
+ * groups over an already tuned station. This functionality is
+ * is currently unsupported.
+ * <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 though all 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){
+ /*
+ * This functionality is currently unsupported
+ */
+
+ return -1;
+ }
+ /*==============================================================
+ FUNCTION: transmitContRdsGroups
+ ==============================================================*/
+ /**
+ * This function will continuously transmit RDS/RBDS groups over an already tuned station.
+ * <p>
+ * This is an asynchronous function used to continuously
+ * transmit RDS/RBDS groups over an already tuned station.
+ * This functionality is currently unsupported.
+ * <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>
+ * Application can send a complete RDS group buffer for the transmission.
+ * This data will be sent continuously to the driver. Only single RDS
+ * group can be continuously transmitter at a time. So, application has to
+ * send the complete RDS buffer it intends to transmit. trying to pass the
+ * single buffer in two calls will be interprted as two different RDS/RBDS
+ * groups and hence all the unset groups will be cleared.
+ * <p>
+ * As continuous RDS/RBDS group transmission is done over single buffer,
+ * Application has to wait for the "onContRDSGroupsComplete()" callback
+ * to initiate the further RDS/RBDS group transmissions. 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 or onContRDSGroupsComplete.
+ * 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
+ * onRDSContGroupsComplete 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 transmitRdsContGroups(byte[] rdsGroups, long numGroupsToTransmit){
+ /*
+ * This functionality is currently unsupported.
+ */
+ return -1;
+ }
+
+ /*==============================================================
+ FUNCTION: transmitRdsGroupControl
+ ==============================================================*/
+ /**
+ * Pause/Resume RDS/RBDS group transmission, or stop and clear
+ * all RDS groups.
+ * <p>
+ * This is a function used to pause/resume RDS/RBDS
+ * group transmission, or stop and clear all RDS groups. This
+ * function can be used to control continuous and
+ * non-continuous RDS/RBDS group transmissions. This functionality
+ * is currently unsupported.
+ * <p>
+ * @param ctrlCmd The Tx RDS group control.This should be one of the
+ * contants RDS_GRPS_TX_PAUSE/RDS_GRPS_TX_RESUME/RDS_GRPS_TX_STOP
+ *
+ * @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 #rdsGroupControlCmdType
+ * @see #transmitRdsGroups
+ */
+ public boolean transmitRdsGroupControl(int ctrlCmd){
+ boolean bStatus = true;
+ /*
+ * This functionality is currently unsupported.
+ */
+ int val = 0;
+ switch( ctrlCmd ) {
+ case RDS_GRPS_TX_PAUSE:break;
+ case RDS_GRPS_TX_RESUME:break;
+ case RDS_GRPS_TX_STOP:break;
+ default:
+ /*Shouldn't reach here*/
+ bStatus = false;
+ }
+ return bStatus;
+ }
+
+ /*==============================================================
+ FUNCTION: setTxPowerLevel
+ ==============================================================*/
+ /**
+ * Sets the transmitter power level.
+ *
+ * <p>
+ * This is a function used for setting the power level of
+ * Tx device.
+ * <p>
+ * @param powLevel The Tx power level value to be set. The value should be
+ * in range 0-7.If input is -ve level will be set to 0
+ * and if it is above 7 level will be set to max i.e.,7.
+ *
+ * @return true on success, false on failure.
+ *
+ */
+ public boolean setTxPowerLevel(int powLevel){
+ boolean bStatus = true;
+ int err = FmReceiverJNI.setTxPowerLevelNative( sFd, powLevel );
+ if( err < 0 ){
+ Log.d(TAG,"setTxPowerLevel is failure");
+ return false;
+ }
+ return bStatus;
+ }
+
+ /*
+ * getFMState() returns:
+ * '0' if FM State is OFF
+ * '1' if FM Rx is On
+ * '2' if FM Tx is On
+ * '3' if FM device is Searching
+ */
+ public int getFMState() {
+ /* Current State of FM device */
+ int currFMState = FmTransceiver.getFMPowerState();
+ return currFMState;
+ }
+};
diff --git a/qcom/fmradio/FmTransmitterCallbacks.java b/qcom/fmradio/FmTransmitterCallbacks.java
new file mode 100644
index 0000000..a868c29
--- /dev/null
+++ b/qcom/fmradio/FmTransmitterCallbacks.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+ /** @hide
+ * 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
+ * #FmTransmitter}.
+ * <p>
+ * Application has to register for these callbacks by sending
+ * a valid instance of TransmitterCallbacks's adapter while
+ * instantiating the FMTransmitter.
+ *
+ * @see #FmTransmitter
+ */
+ public interface FmTransmitterCallbacks
+ {
+ /**
+ * The callback indicates that the transmitter is tuned to a
+ * new frequency Typically received after setStation.
+ */
+ public void FmTxEvTuneStatusChange(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.
+ *
+ * Application can start to send down the remaining groups
+ * to the available group buffers upon recieving this callback.
+ */
+ public void FmTxEvRDSGroupsAvailable();
+ /**
+ * The callback will indicate the succesful completion of #transmitRdsGroups.
+ * This indicates that the FM driver has a complete buffer to transmit the
+ * RDS/RBDS data to the Application. Application can free to switch between continuous or
+ * non-continuous RDS/RBDS group transmissions.
+ */
+ public void FmTxEvRDSGroupsComplete();
+ /**
+ * The callback will indicate the succesful completion of #transmitRdsContGroups.
+ * This indicates that the FM driver has a complete buffer to transmit the
+ * RDS/RBDS data to the Application. Application can free to switch between continuous or
+ * non-continuous RDS/RBDS group transmissions.
+ *
+ */
+ public void FmTxEvContRDSGroupsComplete();
+ /**
+ * The callback indicates that Radio has been Disabled.
+ * This indicates that the FM driver has disabled the radio.
+ *
+ */
+ public void FmTxEvRadioDisabled();
+ /**
+ * The callback indicates that Radio has been Enabled.
+ * This indicates that the FM driver has Enabled the radio.
+ *
+ */
+ public void FmTxEvRadioEnabled();
+ /**
+ * The callback indicates that Radio has been Reset.
+ * This indicates that the FM driver has reset the radio.
+ *
+ */
+ public void FmTxEvRadioReset();
+ };
diff --git a/qcom/fmradio/FmTransmitterCallbacksAdaptor.java b/qcom/fmradio/FmTransmitterCallbacksAdaptor.java
new file mode 100644
index 0000000..8e30bd5
--- /dev/null
+++ b/qcom/fmradio/FmTransmitterCallbacksAdaptor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+ /**
+ * @hide
+ * Class to be implemented for Tx events callbacks
+ *
+ */
+ public class FmTransmitterCallbacksAdaptor implements FmTransmitterCallbacks
+ {
+ public void FmTxEvTuneStatusChange(int freq) {};
+ public void FmTxEvRDSGroupsAvailable() {};
+ public void FmTxEvRDSGroupsComplete() {};
+ public void FmTxEvContRDSGroupsComplete() {};
+ public void FmTxEvRadioDisabled() {};
+ public void FmTxEvRadioEnabled() {};
+ public void FmTxEvRadioReset() {};
+ };
+
diff --git a/qcom/fmradio/FmTxEventListner.java b/qcom/fmradio/FmTxEventListner.java
new file mode 100644
index 0000000..998ef30
--- /dev/null
+++ b/qcom/fmradio/FmTxEventListner.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2011,2012, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package qcom.fmradio;
+
+import android.util.Log;
+import qcom.fmradio.FmTransceiver;
+
+class FmTxEventListner {
+
+
+ private final int EVENT_LISTEN = 1;
+
+ private final int TUNE_EVENT = 1; /*Tune completion event*/
+ private final int TXRDSDAT_EVENT = 16; /*RDS Group available event*/
+ private final int TXRDSDONE_EVENT = 17; /*RDS group complete event */
+ private final int RADIO_DISABLED = 18;
+ private final int READY_EVENT = 0;
+ private byte []buff = new byte[128];
+ private Thread mThread;
+ private static final String TAG = "FMTxEventListner";
+
+ public void startListner (final int fd, final FmTransmitterCallbacks cb) {
+ /* start a thread and listen for messages */
+ mThread = new Thread(){
+ public void run(){
+
+ Log.d(TAG, "Starting Tx Event listener " + fd);
+
+ while((!Thread.currentThread().isInterrupted())) {
+ try {
+ int index = 0;
+ int freq = 0;
+ Log.d(TAG, "getBufferNative called");
+ int eventCount = FmReceiverJNI.getBufferNative
+ (fd, buff, EVENT_LISTEN);
+ Log.d(TAG, "Received event. Count: " + eventCount);
+
+ for(index = 0; index < eventCount; index++) {
+ Log.d(TAG, "Received <" +buff[index]+ ">" );
+ switch(buff[index]){
+ case READY_EVENT:
+ Log.d(TAG, "Got RADIO_ENABLED");
+ if(FmTransceiver.getFMPowerState() ==
+ FmTransceiver.subPwrLevel_FMTx_Starting) {
+ /*Set the state as FMRxOn */
+ FmTransceiver.setFMPowerState
+ (FmTransceiver.FMState_Tx_Turned_On);
+ Log.v(TAG, "TxEvtList: CURRENT-STATE:" +
+ "FMTxStarting ---> NEW-STATE : FMTxOn");
+ cb.FmTxEvRadioEnabled();
+ }
+ break;
+ case TUNE_EVENT:
+ Log.d(TAG, "Got TUNE_EVENT");
+ freq = FmReceiverJNI.getFreqNative(fd);
+ if (freq > 0)
+ cb.FmTxEvTuneStatusChange(freq);
+ else
+ Log.e(TAG, "get frqency cmd failed");
+ break;
+ case TXRDSDAT_EVENT:
+ Log.d(TAG, "Got TXRDSDAT_EVENT");
+ cb.FmTxEvRDSGroupsAvailable();
+ break;
+ case TXRDSDONE_EVENT:
+ Log.d(TAG, "Got TXRDSDONE_EVENT");
+ cb.FmTxEvContRDSGroupsComplete();
+ break;
+ case RADIO_DISABLED:
+ Log.d(TAG, "Got RADIO_DISABLED");
+ if(FmTransceiver.getFMPowerState() ==
+ FmTransceiver.subPwrLevel_FMTurning_Off) {
+ /*Set the state as FMOff */
+ FmTransceiver.setFMPowerState
+ (FmTransceiver.FMState_Turned_Off);
+ Log.v(TAG, "TxEvtList:CURRENT-STATE :" +
+ "FMTurningOff ---> NEW-STATE: FMOff");
+ FmTransceiver.release("/dev/radio0");
+ cb.FmTxEvRadioDisabled();
+ Thread.currentThread().interrupt();
+ } else {
+ Log.d(TAG, "Unexpected RADIO_DISABLED recvd");
+ cb.FmTxEvRadioReset();
+ }
+ break;
+ default:
+ Log.d(TAG, "Unknown event");
+ break;
+ }//switch
+ }//for
+ }catch (Exception ex) {
+ Log.d( TAG, "RunningThread InterruptedException");
+ Thread.currentThread().interrupt();
+ }//try
+ }//while
+ Log.d(TAG, "Came out of the while loop");
+ }
+ };
+ mThread.start();
+ }
+
+ public void stopListener(){
+ Log.d(TAG, "Thread Stopped\n");
+ //Thread stop is deprecate API
+ //Interrupt the thread and check for the thread status
+ // and return from the run() method to stop the thread
+ //properly
+ Log.d(TAG, "stopping the Listener\n");
+
+ if(mThread != null) {
+ mThread.interrupt();
+ }
+ Log.d(TAG, "Thread Stopped\n");
+ }
+}