From d8731b709019c2d20767b0242484e7c5eeeda861 Mon Sep 17 00:00:00 2001
From: Satish kumar sugasi <ssugas@codeaurora.org>
Date: Wed, 27 Jan 2016 14:45:45 -0800
Subject: [PATCH]  Add Support to enable ECC events and update in UI

This does enable ECC bit during RDS group processing and add
logic to receive ECC events from SOC and sent the ECC code to
application.

Change-Id: I61687ea6fe041d2dc4aed16700632be5cdd781d8
---
 fmapp2/src/com/caf/fmradio/FMRadio.java       | 24 +++++++++
 .../src/com/caf/fmradio/FMRadioService.java   | 27 ++++++++++
 fmapp2/src/com/caf/fmradio/FMStats.java       |  4 ++
 .../src/com/caf/fmradio/IFMRadioService.aidl  |  1 +
 .../caf/fmradio/IFMRadioServiceCallbacks.aidl |  1 +
 helium/radio-helium.h                         |  4 ++
 helium/radio_helium_hal.c                     | 29 ++++++++++-
 jni/android_hardware_fm.cpp                   | 49 ++++++++++++++-----
 qcom/fmradio/FmReceiver.java                  | 15 ++++++
 qcom/fmradio/FmReceiverJNI.java               | 11 +++++
 qcom/fmradio/FmRxEvCallbacks.java             |  1 +
 qcom/fmradio/FmRxEvCallbacksAdaptor.java      |  1 +
 qcom/fmradio/FmRxRdsData.java                 |  7 +++
 13 files changed, 160 insertions(+), 14 deletions(-)

diff --git a/fmapp2/src/com/caf/fmradio/FMRadio.java b/fmapp2/src/com/caf/fmradio/FMRadio.java
index 909a14c..ee8ef3d 100644
--- a/fmapp2/src/com/caf/fmradio/FMRadio.java
+++ b/fmapp2/src/com/caf/fmradio/FMRadio.java
@@ -218,6 +218,7 @@ public class FMRadio extends Activity
    /* Bottom row in the station info layout */
    private TextView mRadioTextTV;
    private TextView mERadioTextTV;
+   private TextView mEContryCodeTV;
 
    /* Sleep and Recording Messages */
    private TextView mSleepMsgTV;
@@ -2805,6 +2806,26 @@ public class FMRadio extends Activity
       }
    };
 
+   Runnable mUpdateExtenCountryCode = new Runnable() {
+      public void run() {
+         String str = "";
+         int value;
+         if ((mService != null) && isFmOn()) {
+            try {
+               /* Get Extended Radio Text and update the display */
+               value = mService.getExtenCountryCode();
+               str = Integer.toString(value);
+               Log.d(LOGTAG, "mUpdateExtenCountryCode: Updatable string: [" + str + "]");
+               mERadioTextTV.setText(str);
+               mERadioTextScroller.mOriginalString = str;
+               mERadioTextScroller.startScroll();
+            }catch (RemoteException e) {
+               e.printStackTrace();
+            }
+         }
+      }
+   };
+
    /* Create runnable for posting */
    Runnable mUpdateProgramService = new Runnable() {
       public void run() {
@@ -3124,6 +3145,9 @@ public class FMRadio extends Activity
       public void onExtenRadioTextChanged() {
          mHandler.post(mUpdateExtenRadioText);
       }
+      public void onExtenCountryCodeChanged() {
+         mHandler.post(mUpdateExtenCountryCode);
+      }
       public void onAlternateFrequencyChanged() {
          Log.d(LOGTAG, "mServiceCallbacks.onAlternateFrequencyChanged :");
       }
diff --git a/fmapp2/src/com/caf/fmradio/FMRadioService.java b/fmapp2/src/com/caf/fmradio/FMRadioService.java
index 65f33cb..f4b24fb 100644
--- a/fmapp2/src/com/caf/fmradio/FMRadioService.java
+++ b/fmapp2/src/com/caf/fmradio/FMRadioService.java
@@ -2043,6 +2043,10 @@ public class FMRadioService extends Service
          return(mService.get().isA2DPConnected());
       }
 
+      public int getExtenCountryCode()
+      {
+         return(mService.get().getExtenCountryCode());
+      }
    }
    private final IBinder mBinder = new ServiceStub(this);
 
@@ -2741,6 +2745,16 @@ public class FMRadioService extends Service
       Log.d(LOGTAG, "eRadio Text:[" + str +"]");
       return str;
    }
+   public int  getExtenCountryCode() {
+      int val = 0;
+      if (mFMRxRDSData != null)
+      {
+         val = mFMRxRDSData.getECountryCode();
+      }
+      Log.d(LOGTAG, "eCountry Code :[" + val +"]");
+      return val;
+   }
+
    /* Retrieves the RDS Program Type (PTY) code.
     *
     * @return int - RDS PTY code.
@@ -3295,6 +3309,19 @@ public class FMRadioService extends Service
              e.printStackTrace();
          }
       }
+      public void FmRxEvECCInfo()
+      {
+         Log.d(LOGTAG, "FmRxEvECCInfo");
+         try {
+             if (mReceiver != null) {
+                mFMRxRDSData = mReceiver.getECCInfo();
+                if(mCallbacks != null)
+                   mCallbacks.onExtenCountryCodeChanged();
+             }
+         } catch (RemoteException e) {
+             e.printStackTrace();
+         }
+      }
       public void FmRxEvRdsPiMatchAvailable()
       {
          Log.d(LOGTAG, "FmRxEvRdsPiMatchAvailable");
diff --git a/fmapp2/src/com/caf/fmradio/FMStats.java b/fmapp2/src/com/caf/fmradio/FMStats.java
index c035475..75ba4c6 100644
--- a/fmapp2/src/com/caf/fmradio/FMStats.java
+++ b/fmapp2/src/com/caf/fmradio/FMStats.java
@@ -2657,6 +2657,10 @@ public class FMStats extends Activity  {
           {
              Log.d(LOGTAG, "Extended Radio Text changed:");
           }
+          public void onExtenCountryCodeChanged()
+          {
+             Log.d(LOGTAG, "Extended ountry Code  changed:");
+          }
           public void onAlternateFrequencyChanged()
           {
              Log.d(LOGTAG, "mServiceCallbacks.onAlternateFrequencyChanged :");
diff --git a/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl b/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
index a02c593..766961a 100644
--- a/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
+++ b/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
@@ -53,6 +53,7 @@ interface IFMRadioService
     boolean setIntfDetLowTh(int intfLowTh);
     boolean setIntfDetHighTh(int intfHighTh);
     String getExtenRadioText();
+    int getExtenCountryCode();
     int getSinrSamplesCnt();
     int getSinrTh();
     int getSearchAlgoType();
diff --git a/fmapp2/src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl b/fmapp2/src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl
index 24aaa70..826b5f3 100644
--- a/fmapp2/src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl
+++ b/fmapp2/src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl
@@ -50,4 +50,5 @@ interface IFMRadioServiceCallbacks
   void onA2DPConnectionstateChanged(boolean state);
   void onFmAudioPathStarted();
   void onFmAudioPathStopped();
+  void onExtenCountryCodeChanged();
 }
diff --git a/helium/radio-helium.h b/helium/radio-helium.h
index 5c21bdd..98452d8 100644
--- a/helium/radio-helium.h
+++ b/helium/radio-helium.h
@@ -163,6 +163,7 @@ typedef void (*rds_grp_cntrs_cb)(char *rds_params);
 typedef void (*fm_peek_cb)(char *peek_rsp);
 typedef void (*fm_ssbi_peek_cb)(char *ssbi_peek_rsp);
 typedef void (*fm_ch_det_th_cb)(char *ch_det_rsp);
+typedef void (*fm_ecc_evt_cb)(char *ecc_rsp);
 
 typedef struct {
     size_t  size;
@@ -185,6 +186,7 @@ typedef struct {
     fm_peek_cb fm_peek_rsp_cb;
     fm_ssbi_peek_cb fm_ssbi_peek_rsp_cb;
     fm_ch_det_th_cb fm_ch_det_th_rsp_cb;
+    fm_ecc_evt_cb	ext_country_code_cb;
     callback_thread_event thread_evt_cb;
 } fm_vendor_callbacks_t;
 
@@ -501,6 +503,8 @@ struct hci_fm_blend_table {
 #define HCI_EV_SEARCH_COMPLETE          0x12
 #define HCI_EV_SEARCH_RDS_COMPLETE      0x13
 #define HCI_EV_SEARCH_LIST_COMPLETE     0x14
+
+#define HCI_EV_EXT_COUNTRY_CODE         0x17
 #define HCI_EV_RADIO_TEXT_PLUS_ID       0x18
 #define HCI_EV_RADIO_TEXT_PLUS_TAG      0x19
 #define HCI_EV_HW_ERR_EVENT             0x1A
diff --git a/helium/radio_helium_hal.c b/helium/radio_helium_hal.c
index fd673ab..561c92a 100644
--- a/helium/radio_helium_hal.c
+++ b/helium/radio_helium_hal.c
@@ -558,6 +558,28 @@ static void hci_ev_rt_plus_tag(char *buff)
      }
 }
 
+static void  hci_ev_ext_country_code(char *buff)
+{
+    char *data = NULL;
+    int len = 15;
+    ALOGD("%s:%s: start", LOG_TAG, __func__);
+    data = malloc(len);
+    if (data != NULL) {
+        data[0] = len;
+        ALOGI("%s:%s: data length=%d\n", LOG_TAG, __func__,data[0]);
+        data[1] = buff[RDS_PTYPE];
+        data[2] = buff[RDS_PID_LOWER];
+        data[3] = buff[RDS_PID_HIGHER];
+        data[4] = buff[3];
+        memcpy(&data[RDS_OFFSET], &buff[4], len-RDS_OFFSET);
+        // data[len] = 0x00;
+        jni_cb->ext_country_code_cb(data);
+        free(data);
+    } else {
+        ALOGE("%s:memory allocation failed\n", LOG_TAG);
+    }
+}
+
 static void hci_ev_ert()
 {
     char *data = NULL;
@@ -770,9 +792,12 @@ void radio_hci_event_packet(char *evt_buf)
     case HCI_EV_RADIO_TEXT_PLUS_TAG:
         hci_ev_rt_plus_tag(((FM_EVT_HDR *)evt_buf)->cmd_params);
         break;
+    case HCI_EV_EXT_COUNTRY_CODE:
+        hci_ev_ext_country_code(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
     case HCI_EV_HW_ERR_EVENT:
-	    hci_ev_hw_error(((FM_EVT_HDR *)evt_buf)->cmd_params);
-	    break;
+        hci_ev_hw_error(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
     default:
         break;
     }
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
index 53e757a..21528bb 100644
--- a/jni/android_hardware_fm.cpp
+++ b/jni/android_hardware_fm.cpp
@@ -78,7 +78,6 @@ enum search_dir_t {
     SCAN_DN
 };
 
-
 static JNIEnv *g_jEnv = NULL;
 static JavaVM *g_jVM = NULL;
 
@@ -89,7 +88,6 @@ char *FM_LIBRARY_NAME = "fm_helium.so";
 char *FM_LIBRARY_SYMBOL_NAME = "FM_HELIUM_LIB_INTERFACE";
 void *lib_handle;
 
-
 typedef void (*enb_result_cb)();
 typedef void (*tune_rsp_cb)(int Freq);
 typedef void (*seek_rsp_cb)(int Freq);
@@ -109,6 +107,7 @@ typedef void (*rds_grp_cntrs_cb)(char *rds_params);
 typedef void (*fm_peek_cb)(char *peek_rsp);
 typedef void (*fm_ssbi_peek_cb)(char *ssbi_peek_rsp);
 typedef void (*fm_ch_det_th_cb)(char *ch_det_rsp);
+typedef void (*fm_ecc_evt_cb)(char *ecc);
 
 static JNIEnv *mCallbackEnv = NULL;
 static jobject mCallbacksObj = NULL;
@@ -120,6 +119,7 @@ static jmethodID method_rtCallback;
 static jmethodID method_ertCallback;
 static jmethodID method_aflistCallback;
 static jmethodID method_rtplusCallback;
+static jmethodID method_eccCallback;
 
 jmethodID method_enableCallback;
 jmethodID method_tuneCallback;
@@ -289,7 +289,7 @@ void fm_rt_plus_update_cb(char *rt_plus)
 
 void fm_ert_update_cb(char *ert)
 {
-    ALOGE("ERT_EVT");
+    ALOGI("ERT_EVT");
     jbyteArray ert_buff = NULL;
     int i,len;
 
@@ -301,19 +301,44 @@ void fm_ert_update_cb(char *ert)
     len = (int)(ert[0] & 0xFF);
     len = len+3;
 
-    ALOGE(" ert data len=%d :",len);
+    ALOGI(" ert data len=%d :",len);
     ert_buff = mCallbackEnv->NewByteArray(len);
     if (ert_buff == NULL) {
-        ALOGE(" ps data allocate failed :");
+        ALOGE(" ert data allocate failed :");
         return;
     }
 
     mCallbackEnv->SetByteArrayRegion(ert_buff, 0, len,(jbyte *)ert);
-    jbyte* bytes= mCallbackEnv->GetByteArrayElements(ert_buff,0);
+   // jbyte* bytes= mCallbackEnv->GetByteArrayElements(ert_buff,0);
     mCallbackEnv->CallVoidMethod(mCallbacksObj, method_ertCallback,ert_buff);
     mCallbackEnv->DeleteLocalRef(ert_buff);
 }
 
+void fm_ext_country_code_cb(char *ecc)
+{
+    ALOGI("Extended Contry code ");
+    jbyteArray ecc_buff = NULL;
+    int i,len;
+
+    if (!checkCallbackThread()) {
+        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+        return;
+    }
+
+    len = (int)(ecc[0] & 0xFF);
+
+    ALOGI(" ecc data len=%d :",len);
+    ecc_buff = mCallbackEnv->NewByteArray(len);
+    if (ecc_buff == NULL) {
+        ALOGE(" ecc data allocate failed :");
+        return;
+    }
+    mCallbackEnv->SetByteArrayRegion(ecc_buff, 0, len,(jbyte *)ecc);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_eccCallback,ecc_buff);
+    mCallbackEnv->DeleteLocalRef(ecc_buff);
+}
+
+
 void rds_grp_cntrs_rsp_cb(char * evt_buffer)
 {
    ALOGE("rds_grp_cntrs_rsp_cb");
@@ -376,6 +401,7 @@ typedef struct {
    fm_peek_cb fm_peek_rsp_cb;
    fm_ssbi_peek_cb fm_ssbi_peek_rsp_cb;
    fm_ch_det_th_cb fm_ch_det_th_rsp_cb;
+   fm_ecc_evt_cb   ext_country_code_cb;
    callback_thread_event thread_evt_cb;
 } fm_vendor_callbacks_t;
 
@@ -407,6 +433,7 @@ static   fm_vendor_callbacks_t fm_callbacks = {
     fm_peek_rsp_cb,
     fm_ssbi_peek_rsp_cb,
     fm_ch_det_th_rsp_cb,
+    fm_ext_country_code_cb,
     fm_thread_evt_cb
 };
 #endif
@@ -1336,7 +1363,6 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
 
     ALOGI("ClassInit native called \n");
 #ifdef FM_SOC_TYPE_CHEROKEE
-
     jclass dataClass = env->FindClass("qcom/fmradio/FmReceiverJNI");
     javaClassRef = (jclass) env->NewGlobalRef(dataClass);
     lib_handle = dlopen(FM_LIBRARY_NAME, RTLD_NOW);
@@ -1344,7 +1370,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
         ALOGE("%s unable to open %s: %s", __func__, FM_LIBRARY_NAME, dlerror());
         goto error;
     }
-    ALOGE("Opened %s shared object library successfully", FM_LIBRARY_NAME);
+    ALOGI("Opened %s shared object library successfully", FM_LIBRARY_NAME);
 
     ALOGI("Obtaining handle: '%s' to the shared object library...", FM_LIBRARY_SYMBOL_NAME);
     vendor_interface = (fm_interface_t *)dlsym(lib_handle, FM_LIBRARY_SYMBOL_NAME);
@@ -1356,9 +1382,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
     method_psInfoCallback = env->GetMethodID(javaClassRef, "PsInfoCallback", "([B)V");
     method_rtCallback = env->GetMethodID(javaClassRef, "RtCallback", "([B)V");
     method_ertCallback = env->GetMethodID(javaClassRef, "ErtCallback", "([B)V");
+    method_eccCallback = env->GetMethodID(javaClassRef, "EccCallback", "([B)V");
     method_rtplusCallback = env->GetMethodID(javaClassRef, "RtPlusCallback", "([B)V");
     method_aflistCallback = env->GetMethodID(javaClassRef, "AflistCallback", "([B)V");
-    ALOGI("method_psInfoCallback: '%p' env =%p...", method_psInfoCallback, env);
     method_enableCallback = env->GetMethodID(javaClassRef, "enableCallback", "()V");
     method_tuneCallback = env->GetMethodID(javaClassRef, "tuneCallback", "(I)V");
     method_seekCmplCallback = env->GetMethodID(javaClassRef, "seekCmplCallback", "(I)V");
@@ -1390,9 +1416,8 @@ static void initNative(JNIEnv *env, jobject object) {
             ALOGE("%s unable to initialize vendor library: %d", __func__, status);
             return;
         }
-        ALOGE("***** FM HAL Initialization complete *****\n");
+        ALOGI("***** FM HAL Initialization complete *****\n");
     }
-    ALOGE("object =%p, env = %p\n",object,env);
     mCallbacksObj = env->NewGlobalRef(object);
 #endif
 }
@@ -1485,7 +1510,7 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved)
     int status;
     g_jVM = jvm;
 
-    ALOGE("FM : Loading QCOMM FM-JNI");
+    ALOGI("FM : Loading QCOMM FM-JNI");
     if (jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) {
         ALOGE("JNI version mismatch error");
         return JNI_ERR;
diff --git a/qcom/fmradio/FmReceiver.java b/qcom/fmradio/FmReceiver.java
index 95a8c5e..8e681e7 100644
--- a/qcom/fmradio/FmReceiver.java
+++ b/qcom/fmradio/FmReceiver.java
@@ -1600,6 +1600,21 @@ public class FmReceiver extends FmTransceiver
       return mRdsData;
    }
 
+   public FmRxRdsData getECCInfo() {
+      byte [] raw_ecc = new byte[STD_BUF_SIZE];
+      int ecc_code =0;
+      int bytes_read;
+
+      raw_ecc = FmReceiverJNI.getPsBuffer(raw_ecc);
+      bytes_read = raw_ecc[0];
+      Log.d (TAG, "bytes_read = " + bytes_read);
+      if (bytes_read > 0) {
+          ecc_code =  raw_ecc[9] & 0xFF;
+          mRdsData.setECountryCode(ecc_code);
+          Log.d(TAG, "ECC code: " + ecc_code );
+      }
+      return mRdsData;
+   }
    /*==============================================================
    FUNCTION:  getAFInfo
    ==============================================================*/
diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java
index 1cafe37..d085476 100644
--- a/qcom/fmradio/FmReceiverJNI.java
+++ b/qcom/fmradio/FmReceiverJNI.java
@@ -113,6 +113,17 @@ class FmReceiverJNI {
         Log.d(TAG, "RtCallback exit " );
     }
 
+    public void EccCallback(byte[] ecc) {
+        Log.i(TAG, "EccCallback enter " );
+        if (ecc == null) {
+            Log.e(TAG, "ECC null return  ");
+            return;
+        }
+        mRdsBuffer = Arrays.copyOf(ecc, ecc.length);
+        FmReceiver.mCallback.FmRxEvECCInfo();
+        Log.i(TAG, "EccCallback exit " );
+    }
+
     public void PsInfoCallback(byte[] psInfo) {
         Log.d(TAG, "PsInfoCallback enter " );
         if (psInfo == null) {
diff --git a/qcom/fmradio/FmRxEvCallbacks.java b/qcom/fmradio/FmRxEvCallbacks.java
index 50d2fb2..267d73d 100644
--- a/qcom/fmradio/FmRxEvCallbacks.java
+++ b/qcom/fmradio/FmRxEvCallbacks.java
@@ -46,4 +46,5 @@ interface FmRxEvCallbacks {
     public void FmRxEvRdsAfInfo();
     public void FmRxEvRTPlus();
     public void FmRxEvERTInfo();
+    public void FmRxEvECCInfo();
 }
diff --git a/qcom/fmradio/FmRxEvCallbacksAdaptor.java b/qcom/fmradio/FmRxEvCallbacksAdaptor.java
index 458ff59..753d506 100644
--- a/qcom/fmradio/FmRxEvCallbacksAdaptor.java
+++ b/qcom/fmradio/FmRxEvCallbacksAdaptor.java
@@ -51,5 +51,6 @@ public class FmRxEvCallbacksAdaptor implements FmRxEvCallbacks {
     public void FmRxEvRdsAfInfo() {};
     public void FmRxEvRTPlus() {};
     public void FmRxEvERTInfo() {};
+    public void FmRxEvECCInfo() {};
 }
 
diff --git a/qcom/fmradio/FmRxRdsData.java b/qcom/fmradio/FmRxRdsData.java
index f0e5b9e..1f722f1 100644
--- a/qcom/fmradio/FmRxRdsData.java
+++ b/qcom/fmradio/FmRxRdsData.java
@@ -50,6 +50,7 @@ public class FmRxRdsData {
     private int mPrgmId;
     private int mPrgmType;
     private int mFd;
+    private int mECountryCode;
 
     /* V4L2 controls */
     private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
@@ -216,6 +217,12 @@ public class FmRxRdsData {
     public void setERadioText (String x) {
          mERadioText = x;
     }
+    public void setECountryCode(int x) {
+         mECountryCode = x;
+    }
+    public int getECountryCode() {
+         return mECountryCode;
+    }
     public boolean getFormatDir() {
          return formatting_dir;
     }
-- 
GitLab