flounder: sensor_hub: Enhance timestamp accuracy

Change-Id: I7916c971388560a9065e0b6d5160ceb4b9ea17b3
diff --git a/sensor_hub/libsensors/CwMcuSensor.cpp b/sensor_hub/libsensors/CwMcuSensor.cpp
index cbfcc37..ca2fbde 100644
--- a/sensor_hub/libsensors/CwMcuSensor.cpp
+++ b/sensor_hub/libsensors/CwMcuSensor.cpp
@@ -40,7 +40,6 @@
 #define COMPASS_CALIBRATION_DATA_SIZE 26
 #define G_SENSOR_CALIBRATION_DATA_SIZE 3
 #define NS_PER_MS 1000000LL
-#define SYNC_ACK_MAGIC  0x66
 #define EXHAUSTED_MAGIC 0x77
 
 /*****************************************************************************/
@@ -167,14 +166,96 @@
 int fill_block_debug = 0;
 
 pthread_mutex_t sys_fs_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t sync_timestamp_algo_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t last_timestamp_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void CwMcuSensor::sync_time_thread_in_class(void) {
+    int fd;
+    char buf[24];
+    int err;
+    int64_t mcu_current_time;
+    int64_t cpu_current_time;
+    int open_errno;
+
+    ALOGV("sync_time_thread_in_class++:\n");
+
+    pthread_mutex_lock(&sys_fs_mutex);
+
+    strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "batch_enable");
+
+    fd = open(fixed_sysfs_path, O_RDWR);
+    open_errno = errno;
+    pthread_mutex_unlock(&sys_fs_mutex);
+    if (fd >= 0) {
+        err = read(fd, buf, sizeof(buf) - 1);
+        cpu_current_time = getTimestamp();
+        if (err < 0) {
+            ALOGE("sync_time_thread_in_class: read fail, err = %d\n", err);
+        } else {
+            buf[err] = '\0';
+            mcu_current_time = strtoll(buf, NULL, 10) * NS_PER_US;
+            if (errno == ERANGE) {
+                ALOGE("sync_time_thread_in_class: strtoll fails, strerr = %s, buf = %s\n",
+                      strerror(errno), buf);
+            } else {
+                pthread_mutex_lock(&sync_timestamp_algo_mutex);
+
+                cpu_to_mcu_time_offset = cpu_current_time - mcu_current_time;
+                ALOGV("Syncronization: cpu_to_mcu_time_offset = %" PRId64 " us\n", cpu_to_mcu_time_offset / NS_PER_US);
+
+                if (mcu_current_time != last_mcu_sync_time) {
+                    cpu_divided_by_mcu = (float)(cpu_current_time - last_cpu_sync_time) /
+                                         (float)(mcu_current_time - last_mcu_sync_time);
+                } else {
+                    ALOGE("mcu_current_time == last_mcu_sync_time, unexpected\n");
+                }
+                last_mcu_sync_time = mcu_current_time;
+                last_cpu_sync_time = cpu_current_time;
+                ALOGV("Syncronization: cpu_divided_by_mcu = %f\n", cpu_divided_by_mcu);
+
+                /*** weighted cpu_divided_by_mcu estimated algorithm ***/
+                if (last_cpu_divided_by_mcu == 0) {
+                    last_cpu_divided_by_mcu = cpu_divided_by_mcu;
+                }
+                cpu_divided_by_mcu = (cpu_divided_by_mcu + last_cpu_divided_by_mcu) * 0.5;
+                ALOGV("Syncronization: weighted cpu_divided_by_mcu = %f\n", cpu_divided_by_mcu);
+                last_cpu_divided_by_mcu = cpu_divided_by_mcu;
+                /*** weighted cpu_divided_by_mcu estimated algorithm ***/
+
+                pthread_mutex_unlock(&sync_timestamp_algo_mutex);
+
+                offset_changed = true;
+            }
+        }
+        close(fd);
+    } else {
+        ALOGE("sync_time_thread_in_class: open failed, path = .../batch_enable, fd = %d,"
+              " strerr = %s\n", fd, strerror(open_errno));
+    }
+
+    ALOGV("sync_time_thread_in_class--:\n");
+}
+
+void *sync_time_thread_run(void *context) {
+    CwMcuSensor *myClass = (CwMcuSensor *)context;
+
+    while (1) {
+        ALOGV("sync_time_thread_run++:\n");
+        myClass->sync_time_thread_in_class();
+        sleep(PERIODIC_SYNC_TIME_SEC);
+        ALOGV("sync_time_thread_run--:\n");
+    }
+    return NULL;
+}
 
 CwMcuSensor::CwMcuSensor()
     : SensorBase(NULL, "CwMcuSensor")
     , mEnabled(0)
     , mInputReader(IIO_MAX_BUFF_SIZE)
     , mFlushSensorEnabled(-1)
-    , l_timestamp(0)
-    , g_timestamp(0)
+    , offset_changed(true)
+    , cpu_divided_by_mcu(0)
+    , cpu_to_mcu_time_offset(0)
     , init_trigger_done(false) {
 
     int rc;
@@ -352,6 +433,9 @@
 
     pthread_mutex_unlock(&sys_fs_mutex);
 
+    pthread_create(&sync_time_thread, (const pthread_attr_t *) NULL,
+                    sync_time_thread_run, (void *)this);
+
 }
 
 CwMcuSensor::~CwMcuSensor() {
@@ -507,7 +591,7 @@
 
     what = find_sensor(handle);
 
-    ALOGD("CwMcuSensor::setEnable: [v03-Format Sensor List structure], handle = %d, en = %d,"
+    ALOGD("CwMcuSensor::setEnable: [v04-Enhance timestamp accuracy], handle = %d, en = %d,"
           " what = %d\n", handle, en, what);
 
     if (uint32_t(what) >= numSensors) {
@@ -568,12 +652,12 @@
     int timeout_ms;
     bool dryRun = false;
 
-    ALOGV("CwMcuSensor::batch++: handle = %d, flags = %d, period_ns = %"PRId64", timeout = %"PRId64"\n",
+    ALOGV("CwMcuSensor::batch++: handle = %d, flags = %d, period_ns = %" PRId64 ", timeout = %" PRId64 "\n",
         handle, flags, period_ns, timeout);
 
     what = find_sensor(handle);
-    delay_ms = period_ns/NS_PER_MS;
-    timeout_ms = timeout/NS_PER_MS;
+    delay_ms = period_ns/NS_PER_MS; // int64_t is being dropped to an int type
+    timeout_ms = timeout/NS_PER_MS; // int64_t is being dropped to an int type
 
     if(flags & SENSORS_BATCH_DRY_RUN) {
         dryRun = true;
@@ -633,8 +717,6 @@
         }
     }
 
-    sync_timestamp_locked();
-
     strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "batch_enable");
 
     fd = open(fixed_sysfs_path, O_RDWR);
@@ -702,47 +784,6 @@
 }
 
 
-int CwMcuSensor::sync_timestamp_locked(void) {
-    int fd;
-    char buf[10] = {0};
-    int err;
-
-    strcpy(&fixed_sysfs_path[fixed_sysfs_path_len], "flush");
-
-    fd = open(fixed_sysfs_path, O_RDWR);
-    if (fd >= 0) {
-        size_t n = snprintf(buf, sizeof(buf), "%d\n", TIMESTAMP_SYNC_CODE);
-        err = write(fd, buf, min(n, sizeof(buf)));
-        close(fd);
-        if (err < 0) {
-            err = -EIO;
-        } else {
-            l_timestamp = getTimestamp();
-            err = 0;
-        }
-    } else {
-        err = -ENOENT;
-    }
-    return err;
-}
-
-int CwMcuSensor::sync_timestamp(void)
-{
-    int err;
-
-    ALOGV("%s: Before pthread_mutex_lock()\n", __func__);
-    pthread_mutex_lock(&sys_fs_mutex);
-    ALOGV("%s: Acquired pthread_mutex_lock()\n", __func__);
-
-    err = sync_timestamp_locked();
-
-    pthread_mutex_unlock(&sys_fs_mutex);
-
-    ALOGV("CwMcuSensor::sync_timestamp: path = %s, err = %d\n", fixed_sysfs_path, err);
-
-    return err;
-}
-
 bool CwMcuSensor::hasPendingEvents() const {
     return mPendingMask;
 }
@@ -757,7 +798,7 @@
     pthread_mutex_lock(&sys_fs_mutex);
     ALOGV("%s: Acquired pthread_mutex_lock()\n", __func__);
 
-    ALOGV("CwMcuSensor::setDelay: handle = %"PRId32", delay_ns = %"PRId64"\n",
+    ALOGV("CwMcuSensor::setDelay: handle = %" PRId32 ", delay_ns = %" PRId64 "\n",
             handle, delay_ns);
 
     what = find_sensor(handle);
@@ -828,8 +869,67 @@
             count--;
             numEventReceived++;
             ALOGD("CwMcuSensor::readEvents: metadata = %d\n", mPendingEventsFlush.meta_data.sensor);
+        } else if ((id == TIME_DIFF_EXHAUSTED) || (id == CW_TIME_BASE)) {
+            ALOGV("readEvents: id = %d\n", id);
         } else {
-            mPendingEvents[id].timestamp = getTimestamp();
+            /*** The algorithm which parsed mcu_time into cpu_time for each event ***/
+            uint64_t event_mcu_time = mPendingEvents[id].timestamp;
+            uint64_t event_cpu_time;
+            if (offset_changed) {
+                pthread_mutex_lock(&sync_timestamp_algo_mutex);
+                if (cpu_to_mcu_time_offset == 0) {
+                    pthread_mutex_unlock(&sync_timestamp_algo_mutex);
+                    ALOGI("Not syncronized, cpu_to_mcu_time_offset == 0\n");
+                    sync_time_thread_in_class();
+                    pthread_mutex_lock(&sync_timestamp_algo_mutex);
+                }
+                algo_mcu_base = event_mcu_time;
+                algo_cpu_base = algo_mcu_base + cpu_to_mcu_time_offset;
+
+                pthread_mutex_unlock(&sync_timestamp_algo_mutex);
+
+                event_cpu_time = algo_cpu_base;
+                offset_changed = false;
+            } else {
+                pthread_mutex_lock(&sync_timestamp_algo_mutex);
+                if (cpu_divided_by_mcu == 0) {
+                    pthread_mutex_unlock(&sync_timestamp_algo_mutex);
+                    ALOGV("Not syncronized, cpu_divided_by_mcu == 0\n");
+                    sync_time_thread_in_class();
+                    pthread_mutex_lock(&sync_timestamp_algo_mutex);
+                }
+
+                uint64_t algo_mcu_diff = event_mcu_time - algo_mcu_base;
+                uint64_t algo_cpu_diff = algo_mcu_diff * cpu_divided_by_mcu;
+
+                pthread_mutex_unlock(&sync_timestamp_algo_mutex);
+
+                event_cpu_time = algo_cpu_base + algo_cpu_diff;
+            }
+
+            pthread_mutex_lock(&last_timestamp_mutex);
+
+            if ((event_cpu_time - last_timestamp[id]) <= 0) {
+                ALOGV("Filter event which delta_timestamp <= 0, delta = %" PRId64 " us\n",
+                      (event_cpu_time - last_timestamp[id]) / NS_PER_US);
+                event_cpu_time = last_timestamp[id];
+            }
+            ALOGV("readEvents: id = %d,"
+                  " mcu_time = %" PRId64 " ms,"
+                  " cpu_time = %" PRId64 " ns,"
+                  " delta = %" PRId64 " us,"
+                  " HALtime = %" PRId64 " ns\n",
+                  id,
+                  event_mcu_time / NS_PER_MS,
+                  event_cpu_time,
+                  (event_cpu_time - last_timestamp[id]) / NS_PER_US,
+                  getTimestamp());
+            last_timestamp[id] = event_cpu_time;
+            pthread_mutex_unlock(&last_timestamp_mutex);
+            /*** The algorithm which parsed mcu_time into cpu_time for each event ***/
+
+            mPendingEvents[id].timestamp = event_cpu_time;
+
             if (mEnabled & (1<<id)) {
                 if (id == CW_SIGNIFICANT_MOTION) {
                     setEnable(ID_CW_SIGNIFICANT_MOTION, 0);
@@ -860,7 +960,7 @@
     memcpy(bias, &event[7], 6);
     memcpy(&time, &event[13], 8);
 
-    mPendingEvents[sensorsid].timestamp = time;
+    mPendingEvents[sensorsid].timestamp = time * NS_PER_MS;
 
     switch (sensorsid) {
     case CW_ORIENTATION:
@@ -940,19 +1040,6 @@
         mPendingEventsFlush.meta_data.sensor = find_handle(data[0]);
         ALOGV("CW_META_DATA: meta_data.sensor = %d\n", mPendingEventsFlush.meta_data.sensor);
         break;
-    case CW_SYNC_ACK:
-        if (data[0] == SYNC_ACK_MAGIC) {
-            ALOGV("processEvent: g_timestamp = l_timestamp = %"PRId64"\n", l_timestamp);
-            g_timestamp = l_timestamp;
-        }
-        break;
-    case TIME_DIFF_EXHAUSTED:
-        ALOGV("processEvent: data[0] = 0x%x\n", data[0]);
-        if (data[0] == EXHAUSTED_MAGIC) {
-            ALOGV("processEvent: TIME_DIFF_EXHAUSTED\n");
-            sync_timestamp();
-        }
-        break;
     default:
         ALOGW("%s: Unknown sensorsid = %d\n", __func__, sensorsid);
         break;
diff --git a/sensor_hub/libsensors/CwMcuSensor.h b/sensor_hub/libsensors/CwMcuSensor.h
index 3e5bf19..0f8d1b4 100644
--- a/sensor_hub/libsensors/CwMcuSensor.h
+++ b/sensor_hub/libsensors/CwMcuSensor.h
@@ -50,7 +50,7 @@
     HTC_ANY_MOTION                 = 28,
     CW_SENSORS_ID_END, // Be careful, do not exceed 31
     TIME_DIFF_EXHAUSTED            = 97,
-    CW_SYNC_ACK                    = 98,
+    CW_TIME_BASE                   = 98,
     CW_META_DATA                   = 99,
     CW_MAGNETIC_UNCALIBRATED_BIAS  = 100,
     CW_GYROSCOPE_UNCALIBRATED_BIAS = 101
@@ -66,6 +66,8 @@
 
 #define TIMESTAMP_SYNC_CODE        (98)
 
+#define PERIODIC_SYNC_TIME_SEC     (1)
+
 class CwMcuSensor : public SensorBase {
 
         uint32_t mEnabled;
@@ -81,8 +83,16 @@
         char mDevPath[PATH_MAX];
         char mTriggerName[PATH_MAX];
 
-        int64_t l_timestamp;
-        int64_t g_timestamp;
+        bool offset_changed;
+        float cpu_divided_by_mcu;
+        float last_cpu_divided_by_mcu;
+        int64_t last_timestamp[numSensors];
+        int64_t last_mcu_sync_time;
+        int64_t last_cpu_sync_time;
+        int64_t cpu_to_mcu_time_offset;
+        pthread_t sync_time_thread;
+        uint64_t algo_cpu_base;
+        uint64_t algo_mcu_base;
 
         bool init_trigger_done;
 
@@ -98,14 +108,13 @@
         virtual int getEnable(int32_t handle);
         virtual int batch(int handle, int flags, int64_t period_ns, int64_t timeout);
         virtual int flush(int handle);
-        int sync_timestamp(void);
-        int sync_timestamp_locked(void);
         int find_sensor(int32_t handle);
         int find_handle(int32_t sensors_id);
         void cw_save_calibrator_file(int type, const char * path, int* str);
         int cw_read_calibrator_file(int type, const char * path, int* str);
         int processEvent(uint8_t *event);
         void calculate_rv_4th_element(int sensors_id);
+        void sync_time_thread_in_class(void);
 };
 
 /*****************************************************************************/