nanohub: chre: add support for osChreSensorConfigure

Bug: 32319611
Test: subscribe to sensor using chre calls and verify samples
are received by the chre event handler in the expected chre format.
Change-Id: I54b328e79d17412585113e1ac1f852b33c655b34
Signed-off-by: Ben Fennema <fennema@google.com>
diff --git a/firmware/app/chre/common/chre_app.c b/firmware/app/chre/common/chre_app.c
index d12941a..f09a238 100644
--- a/firmware/app/chre/common/chre_app.c
+++ b/firmware/app/chre/common/chre_app.c
@@ -19,8 +19,14 @@
 #include <timer.h>
 #include <toolchain.h>
 #include <crt_priv.h>
+#include <string.h>
 
 #include <chre.h>
+#include <sensors.h>
+#include <syscallDo.h>
+#include <hostIntf.h>
+
+#define SENSOR_TYPE(x)      ((x) & 0xFF)
 
 /*
  * Common CHRE App support code
@@ -38,6 +44,146 @@
     __crt_exit();
 }
 
+static void initDataHeader(struct chreSensorDataHeader *header, uint64_t timestamp, uint32_t sensorHandle) {
+    header->baseTimestamp = timestamp;
+    header->sensorHandle = sensorHandle;
+    header->readingCount = 1;
+    header->reserved[0] = header->reserved[1] = 0;
+}
+
+static void processTripleAxisData(const struct TripleAxisDataEvent *src, uint32_t sensorHandle, uint8_t sensorType)
+{
+    int i;
+    struct chreSensorThreeAxisData three;
+
+    initDataHeader(&three.header, src->referenceTime, sensorHandle);
+    three.readings[0].timestampDelta = 0;
+
+    for (i=0; i<src->samples[0].firstSample.numSamples; i++) {
+        if (i > 0)
+            three.header.baseTimestamp += src->samples[i].deltaTime;
+        three.readings[0].x = src->samples[i].x;
+        three.readings[0].y = src->samples[i].y;
+        three.readings[0].z = src->samples[i].z;
+
+        nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &three);
+    }
+}
+
+static void processSingleAxisData(const struct SingleAxisDataEvent *src, uint32_t sensorHandle, uint8_t sensorType)
+{
+    int i;
+
+    switch (sensorType) {
+    case CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT:
+    case CHRE_SENSOR_TYPE_STATIONARY_DETECT: {
+        struct chreSensorOccurrenceData occ;
+
+        initDataHeader(&occ.header, src->referenceTime, sensorHandle);
+        occ.readings[0].timestampDelta = 0;
+
+        for (i=0; i<src->samples[0].firstSample.numSamples; i++) {
+            if (i > 0)
+                occ.header.baseTimestamp += src->samples[i].deltaTime;
+
+            nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &occ);
+        }
+        break;
+    }
+    case CHRE_SENSOR_TYPE_LIGHT:
+    case CHRE_SENSOR_TYPE_PRESSURE: {
+        struct chreSensorFloatData flt;
+
+        initDataHeader(&flt.header, src->referenceTime, sensorHandle);
+        flt.readings[0].timestampDelta = 0;
+
+        for (i=0; i<src->samples[0].firstSample.numSamples; i++) {
+            if (i > 0)
+                flt.header.baseTimestamp += src->samples[i].deltaTime;
+            flt.readings[0].value = src->samples[i].fdata;
+
+            nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &flt);
+        }
+        break;
+    }
+    case CHRE_SENSOR_TYPE_PROXIMITY: {
+        struct chreSensorByteData byte;
+
+        initDataHeader(&byte.header, src->referenceTime, sensorHandle);
+        byte.readings[0].timestampDelta = 0;
+
+        for (i=0; i<src->samples[0].firstSample.numSamples; i++) {
+            if (i > 0)
+                byte.header.baseTimestamp += src->samples[i].deltaTime;
+            byte.readings[0].isNear = src->samples[i].fdata == 0.0f;
+
+            nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &byte);
+        }
+        break;
+    }
+    }
+}
+
+static void processEmbeddedData(const void *src, uint32_t sensorHandle, uint8_t sensorType)
+{
+    union EmbeddedDataPoint data = (union EmbeddedDataPoint)((void *)src);
+
+    switch (sensorType) {
+    case CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT:
+    case CHRE_SENSOR_TYPE_STATIONARY_DETECT: {
+        struct chreSensorOccurrenceData occ;
+
+        initDataHeader(&occ.header, eOsSensorGetTime(), sensorHandle);
+        occ.readings[0].timestampDelta = 0;
+
+        nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &occ);
+        break;
+    }
+    case CHRE_SENSOR_TYPE_LIGHT:
+    case CHRE_SENSOR_TYPE_PRESSURE: {
+        struct chreSensorFloatData flt;
+
+        initDataHeader(&flt.header, eOsSensorGetTime(), sensorHandle);
+        flt.readings[0].timestampDelta = 0;
+        flt.readings[0].value = data.fdata;
+
+        nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &flt);
+        break;
+    }
+    case CHRE_SENSOR_TYPE_PROXIMITY: {
+        struct chreSensorByteData byte;
+
+        initDataHeader(&byte.header, eOsSensorGetTime(), sensorHandle);
+        byte.readings[0].timestampDelta = 0;
+        byte.readings[0].isNear = data.fdata == 0.0f;
+
+        nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &byte);
+        break;
+    }
+    }
+}
+
+static void chreappProcessSensorData(uint16_t evt, const void *eventData)
+{
+    const struct SensorInfo *si;
+    uint32_t sensorHandle;
+
+    si = eOsSensorFind(SENSOR_TYPE(evt), 0, &sensorHandle);
+    if (si) {
+        switch (si->numAxis) {
+        case NUM_AXIS_EMBEDDED:
+            processEmbeddedData(eventData, sensorHandle, SENSOR_TYPE(evt));
+            break;
+        case NUM_AXIS_ONE:
+            processSingleAxisData(eventData, sensorHandle, SENSOR_TYPE(evt));
+            break;
+        case NUM_AXIS_THREE:
+            processTripleAxisData(eventData, sensorHandle, SENSOR_TYPE(evt));
+            break;
+        }
+    }
+}
+
 static void chreappHandle(uint32_t eventTypeAndTid, const void *eventData)
 {
     uint16_t evt = eventTypeAndTid;
@@ -74,6 +220,10 @@
         // ignore any other system events; OS may send them to any app
         if (evt < EVT_NO_FIRST_USER_EVENT)
             return;
+        else if (evt > EVT_NO_FIRST_SENSOR_EVENT && evt < EVT_NO_SENSOR_CONFIG_EVENT) {
+            chreappProcessSensorData(evt, data);
+            return;
+        }
     }
     nanoappHandleEvent(srcTid, evt, data);
 }
diff --git a/firmware/os/core/nanohub_chre.c b/firmware/os/core/nanohub_chre.c
index 7bb42c8..5a7cb7d 100644
--- a/firmware/os/core/nanohub_chre.c
+++ b/firmware/os/core/nanohub_chre.c
@@ -21,6 +21,7 @@
 #include <string.h>
 
 #include <cpu.h>
+#include <cpu/cpuMath.h>
 #include <heap.h>
 #include <sensors.h>
 #include <sensors_priv.h>
@@ -260,10 +261,25 @@
     if (!s || !status)
         return false;
 
-    // TODO
-    status->interval = 0;
-    status->latency = 0;
-    status->enabled = 0;
+    if (s->currentRate == SENSOR_RATE_OFF) {
+        status->enabled = 0;
+        status->interval = 0;
+        status->latency = 0;
+    } else {
+        status->enabled = true;
+        if ((s->currentRate == SENSOR_RATE_ONDEMAND ||
+             s->currentRate == SENSOR_RATE_ONCHANGE ||
+             s->currentRate == SENSOR_RATE_ONESHOT))
+            status->interval = CHRE_SENSOR_INTERVAL_DEFAULT;
+        else
+            status->interval = (UINT32_C(1024000000) / s->currentRate) * UINT64_C(1000);
+
+        if (s->currentLatency == SENSOR_LATENCY_NODATA)
+            status->latency = CHRE_SENSOR_INTERVAL_DEFAULT;
+        else
+            status->latency = s->currentLatency;
+    }
+
     return true;
 }
 
@@ -278,9 +294,55 @@
                          enum chreSensorConfigureMode mode,
                          uint64_t interval, uint64_t latency)
 {
-    // TODO
-    osLog(LOG_ERROR, "%s: not implemented\n", __func__);
-    return false;
+    uint32_t rate, interval_us;
+    bool ret;
+    struct Sensor *s = sensorFindByHandle(sensorHandle);
+    if (!s)
+        return false;
+
+    if (mode & CHRE_SENSOR_CONFIGURE_RAW_POWER_ON) {
+        if (interval == CHRE_SENSOR_INTERVAL_DEFAULT) {
+            // use first rate in supported rates list
+            const struct SensorInfo *si = s->si;
+            if (!si)
+                return false;
+
+            if (!si->supportedRates || si->supportedRates[0] == 0)
+                rate = SENSOR_RATE_ONCHANGE;
+            else
+                rate = si->supportedRates[0];
+        } else {
+            interval_us = U64_DIV_BY_CONST_U16(interval, 1000);
+            rate = UINT32_C(1024000000) / interval_us;
+        }
+        if (!rate) // 0 is a reserved value. minimum is 1
+            rate = 1;
+        if (latency == CHRE_SENSOR_LATENCY_DEFAULT)
+            latency = 0ULL;
+        if (s->currentRate == SENSOR_RATE_OFF) {
+            if ((ret = sensorRequest(0, sensorHandle, rate, latency)))
+                ret = osEventSubscribe(0, sensorGetMyEventType(s->si->sensorType));
+            else
+                sensorRelease(0, sensorHandle);
+        } else {
+            ret = sensorRequestRateChange(0, sensorHandle, rate, latency);
+        }
+    } else if (mode & (CHRE_SENSOR_CONFIGURE_RAW_REPORT_CONTINUOUS|CHRE_SENSOR_CONFIGURE_RAW_REPORT_ONE_SHOT)) {
+        // TODO: ONE_SHOT: unsubscribe after receiving a sample
+        if (s->currentRate == SENSOR_RATE_OFF)
+            ret = osEventSubscribe(0, sensorGetMyEventType(s->si->sensorType));
+        else
+            ret = true;
+    } else {
+        if (s->currentRate != SENSOR_RATE_OFF) {
+            if ((ret = sensorRelease(0, sensorHandle)))
+                ret = osEventUnsubscribe(0, sensorGetMyEventType(s->si->sensorType));
+        } else {
+            ret = true;
+        }
+    }
+
+    return ret;
 }
 
 static void osChreApiSensorConfig(uintptr_t *retValP, va_list args)