Merge "nanohub: drivers/st_acc44: Add support for STMicroelectronics ACC44 sensor driver" am: 2677c52945 am: 04b934efb6
am: 6667ab3b4b

Change-Id: Ieb6a58cb23e9439105d14abe8ae4a52ca80dbbad
diff --git a/contexthubhal/nanohubhal.h b/contexthubhal/nanohubhal.h
index 68446e4..6a0432c 100644
--- a/contexthubhal/nanohubhal.h
+++ b/contexthubhal/nanohubhal.h
@@ -37,7 +37,7 @@
 void dumpBuffer(const char *pfx, const hub_app_name_t &appId, uint32_t evtId, const void *data, size_t len, int status = 0);
 
 struct nano_message_chre {
-    HostMsgHdrChre hdr;
+    HostMsgHdrChreV10 hdr;
     uint8_t data[MAX_RX_PACKET];
 } __attribute__((packed));
 
@@ -115,7 +115,7 @@
 
     int doSubscribeMessages(uint32_t hub_id, context_hub_callback *cbk, void *cookie);
     int doSendToNanohub(uint32_t hub_id, const hub_message_t *msg);
-    int doSendToDevice(const hub_app_name_t name, const void *data, uint32_t len, uint32_t messageType);
+    int doSendToDevice(const hub_app_name_t name, const void *data, uint32_t len, uint32_t messageType = 0);
     void doSendToApp(HubMessage &&msg);
 
     static constexpr unsigned int FL_MESSAGE_TRACING = 1;
@@ -148,7 +148,7 @@
     }
     // passes message to kernel driver directly
     static int sendToDevice(const hub_app_name_t *name, const void *data, uint32_t len) {
-        return hubInstance()->doSendToDevice(*name, data, len, 0);
+        return hubInstance()->doSendToDevice(*name, data, len);
     }
     // passes message to APP via callback
     static void sendToApp(HubMessage &&msg) {
diff --git a/contexthubhal/system_comms.cpp b/contexthubhal/system_comms.cpp
index 4a67a66..b0e4bc9 100644
--- a/contexthubhal/system_comms.cpp
+++ b/contexthubhal/system_comms.cpp
@@ -90,7 +90,10 @@
     } else if (no_status) {
         status = 0;
     } else {
-        status = buf.readU32();
+        if (cmd == NANOHUB_START_UPLOAD || cmd == NANOHUB_CONT_UPLOAD || cmd == NANOHUB_FINISH_UPLOAD)
+            status = buf.readU8();
+        else
+            status = buf.readU32();
     }
 }
 
@@ -273,6 +276,8 @@
     mCmd = appMsg->message_type;
     mLen = appMsg->message_len;
     mPos = 0;
+    mNextPos = 0;
+    mErrCnt = 0;
 
     switch (mCmd) {
     case  CONTEXT_HUB_APPS_ENABLE:
@@ -361,10 +366,20 @@
 
     char data[MAX_RX_PACKET];
     MessageBuf buf(data, sizeof(data));
+    const bool success = rsp.status != 0;
 
     static_assert(NANOHUB_UPLOAD_CHUNK_SZ_MAX <= (MAX_RX_PACKET-5),
                   "Invalid chunk size");
 
+    if (success) {
+        mPos = mNextPos;
+        mErrCnt = 0;
+    } else if (mErrCnt > 5) {
+        mPos = mLen;
+    } else {
+        mErrCnt ++;
+    }
+
     if (mPos < mLen) {
         uint32_t chunkSize = mLen - mPos;
 
@@ -375,7 +390,7 @@
         buf.writeU8(NANOHUB_CONT_UPLOAD);
         buf.writeU32(mPos);
         buf.writeRaw(&mData[mPos], chunkSize);
-        mPos += chunkSize;
+        mNextPos = mPos + chunkSize;
     } else {
         buf.writeU8(NANOHUB_FINISH_UPLOAD);
         setState(FINISH);
diff --git a/contexthubhal/system_comms.h b/contexthubhal/system_comms.h
index e1b08e3..d949083 100644
--- a/contexthubhal/system_comms.h
+++ b/contexthubhal/system_comms.h
@@ -19,6 +19,7 @@
 
 #include <utils/Condition.h>
 
+#include <chrono>
 #include <condition_variable>
 #include <map>
 #include <mutex>
@@ -173,8 +174,13 @@
         }
         int wait() {
             std::unique_lock<std::mutex> lk(mDoneMutex);
-            mDoneCond.wait(lk, [this] { return mState == SESSION_DONE; });
-            return 0;
+            bool success = mDoneCond.wait_for(
+                    lk, std::chrono::seconds(30),
+                    [this] { return mState == SESSION_DONE; });
+            if (!success) {
+                ALOGE("Timed out waiting for response");
+            }
+            return success ? 0 : -1;
         }
         virtual int getState() const override {
             std::lock_guard<std::mutex> _l(mDoneMutex);
@@ -204,6 +210,8 @@
         std::vector<uint8_t> mData;
         uint32_t mLen;
         uint32_t mPos;
+        uint32_t mNextPos;
+        uint32_t mErrCnt;
         hub_app_name_t mAppName;
 
         int setupMgmt(const hub_message_t *appMsg, uint32_t cmd);
diff --git a/firmware/app/chre/chre.mk b/firmware/app/chre/chre.mk
index a147677..aed3ce7 100644
--- a/firmware/app/chre/chre.mk
+++ b/firmware/app/chre/chre.mk
@@ -21,12 +21,13 @@
 
 SRCS += $(NANOHUB_DIR)/app/chre/common/chre_app.c
 SRCS += $(NANOHUB_DIR)/app/chre/common/chre_app_syscalls.c
-CFLAGS += -I$(NANOHUB_DIR)/../inc
 
 include $(NANOHUB_DIR)/firmware_conf.mk
 
 CFLAGS += $(COMMON_FLAGS)
 
-BIN_POSTPROCESS_ARGS := -f 0x10
+# CHRE API 1.1
+BIN_POSTPROCESS_ARGS := -c 0x0101
+CFLAGS += -I$(NANOHUB_DIR)/../../../../system/chre/chre_api/include/chre_api
 
 include $(NANOHUB_DIR)/app/app.mk
diff --git a/firmware/app/chre/chre10.mk b/firmware/app/chre/chre10.mk
new file mode 100644
index 0000000..f09d184
--- /dev/null
+++ b/firmware/app/chre/chre10.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+################################################################################
+#
+# NanoApp C/C++ Makefile Utils
+#
+################################################################################
+
+SRCS += $(NANOHUB_DIR)/app/chre/common/chre10_app.c
+SRCS += $(NANOHUB_DIR)/app/chre/common/chre10_app_syscalls.c
+
+include $(NANOHUB_DIR)/firmware_conf.mk
+
+CFLAGS += $(COMMON_FLAGS)
+
+# CHRE API 1.0
+BIN_POSTPROCESS_ARGS := -c 0x0100
+CFLAGS += -I$(NANOHUB_DIR)/../../../../system/chre/chre_api/legacy/v1_0
+
+include $(NANOHUB_DIR)/app/app.mk
diff --git a/firmware/app/chre/chre_test0.app/main.c b/firmware/app/chre/chre_test0.app/main.c
index acdba52..03e6d8d 100644
--- a/firmware/app/chre/chre_test0.app/main.c
+++ b/firmware/app/chre/chre_test0.app/main.c
@@ -39,7 +39,7 @@
 
 static uint32_t mMyTid;
 static uint64_t mMyAppId;
-static int cnt;
+static int mCnt;
 static struct MyTimer mTimer;
 
 static void nanoappFreeEvent(uint16_t eventType, void *data)
@@ -60,7 +60,7 @@
 {
     mMyAppId = chreGetAppId();
     mMyTid = chreGetInstanceId();
-    cnt = 3;
+    mCnt = 3;
     chreSendEvent(EVT_LOCAL_SETUP, (void*)0x87654321, nanoappFreeEvent, mMyTid);
     chreLog(CHRE_LOG_INFO, CHRE_APP_TAG "init\n");
     return true;
@@ -86,11 +86,11 @@
 
         chreLog(CHRE_LOG_INFO, CHRE_APP_TAG "received timer %" PRIu32
                                " (TIME: %" PRIu64
-                               ") cnt: %d\n", t->timerId, chreGetTime(), cnt);
+                               ") cnt: %d\n", t->timerId, chreGetTime(), mCnt);
         extMsg->msg = 0x01;
-        extMsg->val = cnt;
+        extMsg->val = mCnt;
         chreSendMessageToHost(extMsg, sizeof(*extMsg), 0, nanoappFreeMessage);
-        if (cnt-- <= 0)
+        if (mCnt-- <= 0)
             chreTimerCancel(t->timerId);
         break;
     }
diff --git a/firmware/app/chre/chre_test1.app/main.cpp b/firmware/app/chre/chre_test1.app/main.cpp
index 22a33ce..201448a 100644
--- a/firmware/app/chre/chre_test1.app/main.cpp
+++ b/firmware/app/chre/chre_test1.app/main.cpp
@@ -39,7 +39,7 @@
 
 static uint32_t mMyTid;
 static uint64_t mMyAppId;
-static int cnt;
+static int mCnt;
 static struct MyTimer mTimer;
 
 // Default implementation for message free
@@ -52,7 +52,7 @@
 {
     mMyAppId = chreGetAppId();
     mMyTid = chreGetInstanceId();
-    cnt = 3;
+    mCnt = 3;
     chreSendEvent(EVT_LOCAL_SETUP, NULL, NULL, mMyTid);
     chreLog(CHRE_LOG_INFO, APP_LABEL "init");
     return true;
@@ -99,11 +99,11 @@
 
         chreLog(CHRE_LOG_INFO, APP_LABEL "received timer %" PRIu32
                                " (TIME: %" PRIu64
-                               ") cnt: %d\n", t->timerId, chreGetTime(), cnt);
+                               ") cnt: %d\n", t->timerId, chreGetTime(), mCnt);
         extMsg->msg = 0x01;
-        extMsg->val = cnt;
+        extMsg->val = mCnt;
         chreSendMessageToHost(extMsg, sizeof(*extMsg), 0, nanoappFreeMessage);
-        if (cnt-- <= 0)
+        if (mCnt-- <= 0)
             chreTimerCancel(t->timerId);
         break;
     }
diff --git a/firmware/app/chre/chre_test2.app/Android.mk b/firmware/app/chre/chre_test2.app/Android.mk
new file mode 100644
index 0000000..0a471f1
--- /dev/null
+++ b/firmware/app/chre/chre_test2.app/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_NANO_VARS)
+
+LOCAL_MODULE := chre_test2
+LOCAL_MODULE_TAGS := optional
+
+# Googl + T + 0x9002
+LOCAL_NANO_APP_ID := 476f6f676c549002
+LOCAL_NANO_APP_VERSION := 0
+
+LOCAL_SRC_FILES := \
+    main.cpp \
+
+include $(BUILD_NANOHUB_APP_CHRE_EXECUTABLE)
diff --git a/firmware/app/chre/chre_test2.app/Makefile b/firmware/app/chre/chre_test2.app/Makefile
new file mode 100644
index 0000000..45819ff
--- /dev/null
+++ b/firmware/app/chre/chre_test2.app/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+################################################################################
+#
+# test NanoApp Makefile
+#
+################################################################################
+
+
+SRCS := main.cpp
+BIN := chre_test2
+APP_ID := 476f6f676c549002
+APP_VERSION := 0
+
+# Nanohub relative path
+NANOHUB_DIR := ../../..
+
+# Device configuration #########################################################
+
+# select device variant for this app
+TARGET_PRODUCT ?= nucleo
+VARIANT := $(TARGET_PRODUCT)
+
+include $(NANOHUB_DIR)/app/chre/chre.mk
diff --git a/firmware/app/chre/chre_test2.app/main.cpp b/firmware/app/chre/chre_test2.app/main.cpp
new file mode 100644
index 0000000..427221f
--- /dev/null
+++ b/firmware/app/chre/chre_test2.app/main.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <chre.h>
+
+#define APP_LABEL "CHRE App 2: "
+
+/* chre.h does not define printf format attribute for chreLog() */
+void chreLog(enum chreLogLevel level, const char *str, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+
+#define EVT_LOCAL_SETUP CHRE_EVENT_FIRST_USER_VALUE
+
+struct MyTimer {
+    uint64_t startTime;
+    uint32_t timerId;
+};
+
+struct ExtMsg
+{
+    uint8_t msg;
+    uint32_t val;
+} __attribute__((packed));
+
+static const uint64_t kOneSecond = UINT64_C(1000000000); // in nanoseconds
+
+static uint32_t mMyTid;
+static uint64_t mMyAppId;
+static int mCnt;
+static struct MyTimer mTimer;
+
+bool nanoappStart(void)
+{
+    mMyAppId = chreGetAppId();
+    mMyTid = chreGetInstanceId();
+    mCnt = 3;
+    chreSendEvent(EVT_LOCAL_SETUP, NULL, NULL, mMyTid);
+    chreLog(CHRE_LOG_INFO, APP_LABEL "init: offset: %" PRId64, chreGetEstimatedHostTimeOffset());
+    chreConfigureNanoappInfoEvents(true);
+    return true;
+}
+
+void nanoappEnd(void)
+{
+    chreLog(CHRE_LOG_INFO, APP_LABEL "terminating");
+}
+
+void nanoappHandleEvent(uint32_t srcTid, uint16_t evtType, const void* evtData)
+{
+    switch (evtType) {
+    case  EVT_LOCAL_SETUP:
+    {
+        uint32_t instanceId = chreGetInstanceId();
+        uint64_t appId = chreGetAppId();
+        struct chreNanoappInfo info;
+
+        mTimer.startTime = chreGetTime();
+        mTimer.timerId = chreTimerSet(kOneSecond, &mTimer, false);
+        chreLog(CHRE_LOG_INFO, APP_LABEL "started with tid %04" PRIX32
+                               " timerid %" PRIu32
+                               "\n", mMyTid, mTimer.timerId);
+        chreLog(CHRE_LOG_INFO, APP_LABEL "appId=%016llx; instanceId=%ld",
+            appId, instanceId);
+        if (chreGetNanoappInfoByInstanceId(instanceId, &info)) {
+            chreLog(CHRE_LOG_INFO, APP_LABEL "info by instanceId; appId=%08llx; version=%ld; instanceId=%ld",
+                info.appId, info.version, info.instanceId);
+        } else {
+            chreLog(CHRE_LOG_INFO, APP_LABEL "error getting info by instance id");
+        }
+        if (chreGetNanoappInfoByAppId(appId, &info)) {
+            chreLog(CHRE_LOG_INFO, APP_LABEL "info by appId; appId=%08llx; version=%ld; instanceId=%ld",
+                info.appId, info.version, info.instanceId);
+        } else {
+             chreLog(CHRE_LOG_INFO, APP_LABEL "error getting info by app id");
+        }
+        break;
+    }
+    case CHRE_EVENT_TIMER:
+    {
+        const struct MyTimer *t = (const struct MyTimer *)evtData;
+
+        chreLog(CHRE_LOG_INFO, APP_LABEL "received timer %" PRIu32
+                               " (START: %" PRIu64 " TIME: %" PRIu64 " OFFSET: %" PRId64
+                               ") cnt: %d\n", t->timerId, t->startTime, chreGetTime(),
+                               chreGetEstimatedHostTimeOffset(),  mCnt);
+        if (mCnt-- <= 0) {
+            chreTimerCancel(t->timerId);
+            chreAbort(0x0001);
+            chreAbort(0x0002);
+        }
+        break;
+    }
+    case CHRE_EVENT_MESSAGE_FROM_HOST:
+    {
+        const struct chreMessageFromHostData *msg = (const struct chreMessageFromHostData *)evtData;
+        const uint8_t *data = (const uint8_t *)msg->message;
+        const size_t size = msg->messageSize;
+        const uint32_t type = msg->messageType;
+        const uint16_t endpoint = msg->hostEndpoint;
+        chreLog(CHRE_LOG_INFO, APP_LABEL "message=%p; code=%d; size=%zu; type=%ld; endpoint=%d",
+                data, (data && size) ? data[0] : 0, size, type, endpoint);
+        break;
+    }
+    case CHRE_EVENT_NANOAPP_STARTED:
+    {
+        const struct chreNanoappInfo *msg = (const struct chreNanoappInfo *)evtData;
+        const uint64_t appId = msg->appId;
+        const uint32_t version = msg->version;
+        const uint32_t instanceId = msg->instanceId;
+        chreLog(CHRE_LOG_INFO, APP_LABEL "app started; appId=%08llx; version=%ld; instanceId=%ld",
+                appId, version, instanceId);
+        break;
+    }
+    case CHRE_EVENT_NANOAPP_STOPPED:
+    {
+        const struct chreNanoappInfo *msg = (const struct chreNanoappInfo *)evtData;
+        const uint64_t appId = msg->appId;
+        const uint32_t version = msg->version;
+        const uint32_t instanceId = msg->instanceId;
+        chreLog(CHRE_LOG_INFO, APP_LABEL "app stopped; appId=%08llx; version=%ld; instanceId=%ld",
+                appId, version, instanceId);
+        break;
+    }
+    }
+}
diff --git a/firmware/app/chre/common/chre10_app.c b/firmware/app/chre/common/chre10_app.c
new file mode 100644
index 0000000..deda37b
--- /dev/null
+++ b/firmware/app/chre/common/chre10_app.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <eventnums.h>
+#include <seos.h>
+#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
+ */
+
+static bool chreappStart(uint32_t tid)
+{
+    __crt_init();
+    return nanoappStart();
+}
+
+static void chreappEnd(void)
+{
+    nanoappEnd();
+    __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;
+            byte.readings[0].invalid = false;
+            byte.readings[0].padding0 = 0;
+
+            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;
+        byte.readings[0].invalid = false;
+        byte.readings[0].padding0 = 0;
+
+        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;
+
+    if (eventData == SENSOR_DATA_EVENT_FLUSH)
+        return;
+
+    si = eOsSensorFind(SENSOR_TYPE(evt), 0, &sensorHandle);
+    if (si && eOsSensorGetReqRate(sensorHandle)) {
+        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;
+        }
+
+        if (SENSOR_TYPE(evt) == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT
+            || SENSOR_TYPE(evt) == CHRE_SENSOR_TYPE_STATIONARY_DETECT) {
+            // one-shot, disable after receiving sample
+            chreSensorConfigure(sensorHandle, CHRE_SENSOR_CONFIGURE_MODE_DONE, CHRE_SENSOR_INTERVAL_DEFAULT, CHRE_SENSOR_LATENCY_DEFAULT);
+        }
+    }
+}
+
+static void chreappProcessConfigEvt(uint16_t evt, const void *eventData)
+{
+    const struct SensorRateChangeEvent *msg = eventData;
+    struct chreSensorSamplingStatusEvent change;
+
+    change.sensorHandle = msg->sensorHandle;
+    if (!msg->newRate) {
+        change.status.enabled = 0;
+        change.status.interval = 0;
+        change.status.latency = 0;
+    } else {
+        change.status.enabled = true;
+        if (msg->newRate == SENSOR_RATE_ONDEMAND
+            || msg->newRate == SENSOR_RATE_ONCHANGE
+            || msg->newRate == SENSOR_RATE_ONESHOT)
+            change.status.interval = CHRE_SENSOR_INTERVAL_DEFAULT;
+        else
+            change.status.interval = (UINT32_C(1024000000) / msg->newRate) * UINT64_C(1000);
+
+        if (msg->newLatency == SENSOR_LATENCY_NODATA)
+            change.status.latency = CHRE_SENSOR_INTERVAL_DEFAULT;
+        else
+            change.status.latency = msg->newLatency;
+    }
+
+    nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_SAMPLING_CHANGE, &change);
+}
+
+static void chreappHandle(uint32_t eventTypeAndTid, const void *eventData)
+{
+    uint16_t evt = eventTypeAndTid;
+    uint16_t srcTid = eventTypeAndTid >> 16;
+    const void *data = eventData;
+
+    union EventLocalData {
+    struct chreMessageFromHostData msg;
+    } u;
+
+    switch(evt) {
+    case EVT_APP_TIMER:
+        evt = CHRE_EVENT_TIMER;
+        data = ((struct TimerEvent *)eventData)->data;
+        break;
+    case EVT_APP_FROM_HOST:
+        srcTid = CHRE_INSTANCE_ID;
+        evt = CHRE_EVENT_MESSAGE_FROM_HOST;
+        data = &u.msg;
+        u.msg.message = (uint8_t*)eventData + 1;
+        u.msg.reservedMessageType = 0;
+        u.msg.messageSize = *(uint8_t*)eventData;
+        break;
+    case EVT_APP_FROM_HOST_CHRE:
+    {
+        const struct NanohubMsgChreHdrV10 *hdr = eventData;
+        srcTid = CHRE_INSTANCE_ID;
+        evt = CHRE_EVENT_MESSAGE_FROM_HOST;
+        data = &u.msg;
+        u.msg.message = hdr + 1;
+        u.msg.reservedMessageType = hdr->appEvent;
+        u.msg.messageSize = hdr->size;
+        break;
+    }
+    case EVT_APP_SENSOR_SELF_TEST:
+    case EVT_APP_SENSOR_MARSHALL:
+    case EVT_APP_SENSOR_SEND_ONE_DIR_EVT:
+    case EVT_APP_SENSOR_CFG_DATA:
+    case EVT_APP_SENSOR_CALIBRATE:
+    case EVT_APP_SENSOR_TRIGGER:
+    case EVT_APP_SENSOR_FLUSH:
+    case EVT_APP_SENSOR_SET_RATE:
+    case EVT_APP_SENSOR_FW_UPLD:
+    case EVT_APP_SENSOR_POWER:
+        // sensor events; pass through
+        break;
+    default:
+        // 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) {
+            return chreappProcessSensorData(evt, data);
+        } else if (evt > EVT_NO_SENSOR_CONFIG_EVENT && evt < EVT_APP_START) {
+            return chreappProcessConfigEvt(evt, data);
+        }
+    }
+    nanoappHandleEvent(srcTid, evt, data);
+}
+
+// Collect entry points
+const struct AppFuncs SET_EXTERNAL_APP_ATTRIBUTES(used, section (".app_init"),visibility("default")) _mAppFuncs = {
+    .init   = chreappStart,
+    .end    = chreappEnd,
+    .handle = chreappHandle,
+};
+
+// declare version for compatibility with current runtime
+const uint32_t SET_EXTERNAL_APP_VERSION(used, section (".app_version"), visibility("default")) _mAppVer = 0;
diff --git a/firmware/app/chre/common/chre10_app_syscalls.c b/firmware/app/chre/common/chre10_app_syscalls.c
new file mode 100644
index 0000000..666bdae
--- /dev/null
+++ b/firmware/app/chre/common/chre10_app_syscalls.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdarg.h>
+
+#include <gpio.h>
+#include <osApi.h>
+#include <sensors.h>
+#include <seos.h>
+#include <util.h>
+
+/* CHRE syscalls */
+#include <chre.h>
+#include <chreApi.h>
+#include <syscall.h>
+#include <syscall_defs.h>
+
+#define SYSCALL_CHRE_API(name) \
+    SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_MAIN, SYSCALL_CHRE_MAIN_API, SYSCALL_CHRE_MAIN_API_ ## name)
+
+uint64_t chreGetAppId(void)
+{
+    uint64_t appId = 0;
+    (void)syscallDo1P(SYSCALL_CHRE_API(GET_APP_ID), &appId);
+    return appId;
+}
+
+uint32_t chreGetInstanceId(void)
+{
+    return syscallDo0P(SYSCALL_CHRE_API(GET_INST_ID));
+}
+
+uint64_t chreGetTime(void) {
+    uint64_t time_ns = 0;
+    (void)syscallDo1P(SYSCALL_CHRE_API(GET_TIME), &time_ns);
+    return time_ns;
+}
+
+void chreLog(enum chreLogLevel level, const char *str, ...)
+{
+    va_list vl;
+
+    va_start(vl, str);
+    (void)syscallDo3P(SYSCALL_CHRE_API(LOG), level, str, VA_LIST_TO_INTEGER(vl));
+    va_end(vl);
+}
+
+uint32_t chreTimerSet(uint64_t duration, const void* cookie, bool oneShot)
+{
+    uint32_t dur_lo = duration;
+    uint32_t dur_hi = duration >> 32;
+    return syscallDo4P(SYSCALL_CHRE_API(TIMER_SET), dur_lo, dur_hi, cookie, oneShot);
+}
+
+bool chreTimerCancel(uint32_t timerId)
+{
+    return syscallDo1P(SYSCALL_CHRE_API(TIMER_CANCEL), timerId);
+}
+
+void chreAbort(uint32_t abortCode)
+{
+    (void)syscallDo1P(SYSCALL_CHRE_API(ABORT), abortCode);
+}
+
+void* chreHeapAlloc(uint32_t bytes)
+{
+    return (void *)syscallDo1P(SYSCALL_CHRE_API(HEAP_ALLOC), bytes);
+}
+
+void chreHeapFree(void* ptr)
+{
+    (void)syscallDo1P(SYSCALL_CHRE_API(HEAP_FREE), ptr);
+}
+
+bool chreSensorFindDefault(uint8_t sensorType, uint32_t *handle)
+{
+    return syscallDo2P(SYSCALL_CHRE_API(SENSOR_FIND_DEFAULT), sensorType, handle);
+}
+
+bool chreGetSensorInfo(uint32_t sensorHandle, struct chreSensorInfo *info)
+{
+    return syscallDo2P(SYSCALL_CHRE_API(SENSOR_GET_INFO), sensorHandle, info);
+}
+
+bool chreGetSensorSamplingStatus(uint32_t sensorHandle,
+                                 struct chreSensorSamplingStatus *status)
+{
+    return syscallDo2P(SYSCALL_CHRE_API(SENSOR_GET_STATUS), sensorHandle, status);
+}
+
+bool chreSensorConfigure(uint32_t sensorHandle,
+                         enum chreSensorConfigureMode mode,
+                         uint64_t interval, uint64_t latency)
+{
+    uint32_t interval_lo = interval;
+    uint32_t interval_hi = interval >> 32;
+    uint32_t latency_lo = latency;
+    uint32_t latency_hi = latency >> 32;
+    return syscallDo6P(SYSCALL_CHRE_API(SENSOR_CONFIG), sensorHandle, mode,
+                       interval_lo, interval_hi, latency_lo, latency_hi);
+}
+
+bool chreSendEvent(uint16_t eventType, void *eventData,
+                   chreEventCompleteFunction *freeCallback,
+                   uint32_t targetInstanceId)
+{
+    return syscallDo4P(SYSCALL_CHRE_API(SEND_EVENT), eventType, eventData, freeCallback, targetInstanceId);
+}
+
+bool chreSendMessageToHost(void *message, uint32_t messageSize,
+                           uint32_t reservedMessageType,
+                           chreMessageFreeFunction *freeCallback)
+{
+    return syscallDo4P(SYSCALL_CHRE_API(SEND_MSG), message, messageSize, reservedMessageType, freeCallback);
+}
+
+uint32_t chreGetApiVersion(void)
+{
+    return syscallDo0P(SYSCALL_CHRE_API(GET_OS_API_VERSION));
+}
+
+uint32_t chreGetVersion(void)
+{
+    return syscallDo0P(SYSCALL_CHRE_API(GET_OS_VERSION));
+}
+
+uint64_t chreGetPlatformId(void)
+{
+    uint64_t plat = 0;
+    (void)syscallDo1P(SYSCALL_CHRE_API(GET_PLATFORM_ID), &plat);
+    return plat;
+}
diff --git a/firmware/app/chre/common/chre_app.c b/firmware/app/chre/common/chre_app.c
index 55bbdf2..0eba239 100644
--- a/firmware/app/chre/common/chre_app.c
+++ b/firmware/app/chre/common/chre_app.c
@@ -232,7 +232,8 @@
     const void *data = eventData;
 
     union EventLocalData {
-    struct chreMessageFromHostData msg;
+        struct chreMessageFromHostData msg;
+        struct chreNanoappInfo info;
     } u;
 
     switch(evt) {
@@ -245,18 +246,46 @@
         evt = CHRE_EVENT_MESSAGE_FROM_HOST;
         data = &u.msg;
         u.msg.message = (uint8_t*)eventData + 1;
-        u.msg.reservedMessageType = 0;
+        u.msg.messageType = 0;
         u.msg.messageSize = *(uint8_t*)eventData;
+        u.msg.hostEndpoint = CHRE_HOST_ENDPOINT_UNSPECIFIED;
         break;
     case EVT_APP_FROM_HOST_CHRE:
     {
-        const struct NanohubMsgChreHdr *hdr = eventData;
+        if (chreGetApiVersion() == CHRE_API_VERSION_1_0) {
+            const struct NanohubMsgChreHdrV10 *hdr = eventData;
+            srcTid = CHRE_INSTANCE_ID;
+            evt = CHRE_EVENT_MESSAGE_FROM_HOST;
+            data = &u.msg;
+            u.msg.message = hdr + 1;
+            u.msg.messageType = hdr->appEvent;
+            u.msg.messageSize = hdr->size;
+            u.msg.hostEndpoint = CHRE_HOST_ENDPOINT_UNSPECIFIED;
+        } else {
+            const struct NanohubMsgChreHdr *hdr = eventData;
+            srcTid = CHRE_INSTANCE_ID;
+            evt = CHRE_EVENT_MESSAGE_FROM_HOST;
+            data = &u.msg;
+            u.msg.message = hdr + 1;
+            u.msg.messageType = hdr->appEvent;
+            u.msg.messageSize = hdr->size;
+            u.msg.hostEndpoint = hdr->endpoint;
+        }
+        break;
+    }
+    case EVT_APP_STARTED:
+    case EVT_APP_STOPPED:
+    {
+        const struct AppEventStartStop *msg = eventData;
         srcTid = CHRE_INSTANCE_ID;
-        evt = CHRE_EVENT_MESSAGE_FROM_HOST;
-        data = &u.msg;
-        u.msg.message = hdr + 1;
-        u.msg.reservedMessageType = hdr->appEvent;
-        u.msg.messageSize = hdr->size;
+        if (evt == EVT_APP_STARTED)
+            evt = CHRE_EVENT_NANOAPP_STARTED;
+        else
+            evt = CHRE_EVENT_NANOAPP_STOPPED;
+        data = &u.info;
+        u.info.appId = msg->appId;
+        u.info.version = msg->version;
+        u.info.instanceId = msg->tid;
         break;
     }
     case EVT_APP_SENSOR_SELF_TEST:
diff --git a/firmware/app/chre/common/chre_app_syscalls.c b/firmware/app/chre/common/chre_app_syscalls.c
index 666bdae..fc1bc8c 100644
--- a/firmware/app/chre/common/chre_app_syscalls.c
+++ b/firmware/app/chre/common/chre_app_syscalls.c
@@ -49,6 +49,12 @@
     return time_ns;
 }
 
+int64_t chreGetEstimatedHostTimeOffset(void) {
+    int64_t time_ns = 0;
+    (void)syscallDo1P(SYSCALL_CHRE_API(GET_HOST_TIME_OFFSET), &time_ns);
+    return time_ns;
+}
+
 void chreLog(enum chreLogLevel level, const char *str, ...)
 {
     va_list vl;
@@ -113,23 +119,12 @@
                        interval_lo, interval_hi, latency_lo, latency_hi);
 }
 
-bool chreSendEvent(uint16_t eventType, void *eventData,
-                   chreEventCompleteFunction *freeCallback,
-                   uint32_t targetInstanceId)
-{
-    return syscallDo4P(SYSCALL_CHRE_API(SEND_EVENT), eventType, eventData, freeCallback, targetInstanceId);
-}
-
-bool chreSendMessageToHost(void *message, uint32_t messageSize,
-                           uint32_t reservedMessageType,
-                           chreMessageFreeFunction *freeCallback)
-{
-    return syscallDo4P(SYSCALL_CHRE_API(SEND_MSG), message, messageSize, reservedMessageType, freeCallback);
-}
-
 uint32_t chreGetApiVersion(void)
 {
-    return syscallDo0P(SYSCALL_CHRE_API(GET_OS_API_VERSION));
+    static uint32_t apiVersion = 0;
+    if (!apiVersion)
+        apiVersion = syscallDo0P(SYSCALL_CHRE_API(GET_OS_API_VERSION));
+    return apiVersion;
 }
 
 uint32_t chreGetVersion(void)
@@ -143,3 +138,97 @@
     (void)syscallDo1P(SYSCALL_CHRE_API(GET_PLATFORM_ID), &plat);
     return plat;
 }
+
+bool chreSendEvent(uint16_t eventType, void *eventData,
+                   chreEventCompleteFunction *freeCallback,
+                   uint32_t targetInstanceId)
+{
+    if (chreGetApiVersion() == CHRE_API_VERSION_1_0)
+        return syscallDo4P(SYSCALL_CHRE_API(SEND_EVENT), eventType, eventData, freeCallback, targetInstanceId);
+    else
+        return syscallDo4P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_MAIN, SYSCALL_CHRE_MAIN_EVENT, SYSCALL_CHRE_MAIN_EVENT_SEND_EVENT), eventType, eventData, freeCallback, targetInstanceId);
+}
+
+bool chreSendMessageToHost(void *message, uint32_t messageSize,
+                           uint32_t messageType,
+                           chreMessageFreeFunction *freeCallback)
+{
+    if (chreGetApiVersion() == CHRE_API_VERSION_1_0)
+        return syscallDo4P(SYSCALL_CHRE_API(SEND_MSG), message, messageSize, messageType, freeCallback);
+    else
+        return syscallDo5P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_MAIN, SYSCALL_CHRE_MAIN_EVENT, SYSCALL_CHRE_MAIN_EVENT_SEND_MSG), message, messageSize, messageType, CHRE_HOST_ENDPOINT_BROADCAST, freeCallback);
+}
+
+bool chreSendMessageToHostEndpoint(void *message, size_t messageSize,
+                                   uint32_t messageType, uint16_t hostEndpoint,
+                                   chreMessageFreeFunction *freeCallback)
+{
+    return syscallDo5P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_MAIN, SYSCALL_CHRE_MAIN_EVENT, SYSCALL_CHRE_MAIN_EVENT_SEND_MSG), message, messageSize, messageType, hostEndpoint, freeCallback);
+}
+
+bool chreGetNanoappInfoByAppId(uint64_t appId, struct chreNanoappInfo *info)
+{
+    uint32_t app_lo = appId;
+    uint32_t app_hi = appId >> 32;
+    return syscallDo3P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_MAIN, SYSCALL_CHRE_MAIN_EVENT, SYSCALL_CHRE_MAIN_EVENT_INFO_BY_APP_ID), app_lo, app_hi, info);
+}
+
+bool chreGetNanoappInfoByInstanceId(uint32_t instanceId, struct chreNanoappInfo *info)
+{
+    return syscallDo2P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_MAIN, SYSCALL_CHRE_MAIN_EVENT, SYSCALL_CHRE_MAIN_EVENT_INFO_BY_INST_ID), instanceId, info);
+}
+
+void chreConfigureNanoappInfoEvents(bool enable)
+{
+    syscallDo1P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_MAIN, SYSCALL_CHRE_MAIN_EVENT, SYSCALL_CHRE_MAIN_EVENT_CFG_INFO), enable);
+}
+
+uint32_t chreGnssGetCapabilities(void)
+{
+    return syscallDo0P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_GNSS, SYSCALL_CHRE_DRV_GNSS_GET_CAP));
+}
+
+bool chreGnssLocationSessionStartAsync(uint32_t minIntervalMs, uint32_t minTimeToNextFixMs, const void *cookie)
+{
+    return syscallDo3P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_GNSS, SYSCALL_CHRE_DRV_GNSS_LOC_START_ASYNC), minIntervalMs, minTimeToNextFixMs, cookie);
+}
+
+bool chreGnssLocationSessionStopAsync(const void *cookie)
+{
+    return syscallDo1P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_GNSS, SYSCALL_CHRE_DRV_GNSS_LOC_STOP_ASYNC), cookie);
+}
+
+bool chreGnssMeasurementSessionStartAsync(uint32_t minIntervalMs, const void *cookie)
+{
+    return syscallDo2P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_GNSS, SYSCALL_CHRE_DRV_GNSS_MEAS_START_ASYNC), minIntervalMs, cookie);
+}
+
+bool chreGnssMeasurementSessionStopAsync(const void *cookie)
+{
+    return syscallDo1P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_GNSS, SYSCALL_CHRE_DRV_GNSS_MEAS_STOP_ASYNC), cookie);
+}
+
+uint32_t chreWifiGetCapabilities(void)
+{
+    return syscallDo0P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_WIFI, SYSCALL_CHRE_DRV_WIFI_GET_CAP));
+}
+
+bool chreWifiConfigureScanMonitorAsync(bool enable, const void *cookie)
+{
+    return syscallDo2P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_WIFI, SYSCALL_CHRE_DRV_WIFI_CONF_SCAN_MON_ASYNC), enable, cookie);
+}
+
+bool chreWifiRequestScanAsync(const struct chreWifiScanParams *params, const void *cookie)
+{
+    return syscallDo2P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_WIFI, SYSCALL_CHRE_DRV_WIFI_REQ_SCAN_ASYNC), params, cookie);
+}
+
+uint32_t chreWwanGetCapabilities(void)
+{
+    return syscallDo0P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_WWAN, SYSCALL_CHRE_DRV_WWAN_GET_CAP));
+}
+
+bool chreWwanGetCellInfoAsync(const void *cookie)
+{
+    return syscallDo1P(SYSCALL_NO(SYSCALL_DOMAIN_CHRE, SYSCALL_CHRE_DRIVERS, SYSCALL_CHRE_DRV_WWAN, SYSCALL_CHRE_DRV_WWAN_GET_CELL_INFO_ASYNC), cookie);
+}
diff --git a/firmware/build/app_chre_executable.mk b/firmware/build/app_chre_executable.mk
index 0169699..009dc15 100644
--- a/firmware/build/app_chre_executable.mk
+++ b/firmware/build/app_chre_executable.mk
@@ -24,8 +24,8 @@
 my_variants := $(AUX_OS_VARIANT_LIST_$(NANO_OS))
 endif
 
-# mark the app as CHRE nanoapp
-LOCAL_NANO_APP_POSTPROCESS_FLAGS += -f 0x10
+# mark the app as CHRE 1.1 nanoapp
+LOCAL_NANO_APP_POSTPROCESS_FLAGS += -c 0x0101
 
 # add app-side CHRE implementation
 LOCAL_WHOLE_STATIC_LIBRARIES += \
diff --git a/firmware/build/app_config.mk b/firmware/build/app_config.mk
index 1bb4177..e7734cf 100644
--- a/firmware/build/app_config.mk
+++ b/firmware/build/app_config.mk
@@ -27,7 +27,9 @@
 LOCAL_FORCE_STATIC_EXECUTABLE := false
 
 LOCAL_CFLAGS +=                                 \
+    -DNANOAPP_ID=0x$(LOCAL_NANO_APP_ID)         \
     -DAPP_ID=$(LOCAL_NANO_APP_ID)               \
+    -DNANOAPP_VERSION=$(LOCAL_NANO_APP_VERSION) \
     -DAPP_VERSION=$(LOCAL_NANO_APP_VERSION)     \
     -D__NANOHUB__                               \
 
diff --git a/firmware/build/config_internal.mk b/firmware/build/config_internal.mk
index 533d38f..3a01504 100644
--- a/firmware/build/config_internal.mk
+++ b/firmware/build/config_internal.mk
@@ -19,7 +19,7 @@
     $(NANOHUB_OS_PATH)/os/platform/$(AUX_ARCH)/inc      \
     $(NANOHUB_OS_PATH)/os/cpu/$(AUX_CPU)/inc            \
     $(NANOHUB_OS_PATH)/../lib/include                   \
-    $(NANOHUB_OS_PATH)/../inc                           \
+    system/chre/chre_api/include/chre_api               \
 
 LOCAL_WHOLE_STATIC_LIBRARIES_BL += libnanohub_bl_$(AUX_CPU)
 LOCAL_WHOLE_STATIC_LIBRARIES_BL += libnanohub_bl_$(AUX_ARCH)
diff --git a/firmware/firmware.mk b/firmware/firmware.mk
index 8627748..9e02634 100644
--- a/firmware/firmware.mk
+++ b/firmware/firmware.mk
@@ -56,7 +56,7 @@
 FLAGS += -I$(VARIANT_PATH)/inc
 FLAGS += -Iexternal/freebsd/inc
 FLAGS += -I../lib/include
-FLAGS += -I../inc
+FLAGS += -I../../../../system/chre/chre_api/include/chre_api
 
 FLAGS += -Wall -Werror
 #help avoid commmon embedded C mistakes
diff --git a/firmware/os/algos/calibration/accelerometer/accel_cal.c b/firmware/os/algos/calibration/accelerometer/accel_cal.c
index c700253..da402ea 100644
--- a/firmware/os/algos/calibration/accelerometer/accel_cal.c
+++ b/firmware/os/algos/calibration/accelerometer/accel_cal.c
@@ -36,8 +36,8 @@
 #define MIN_TEMP 20.0f  // No Data is collected below 20 degree C.
 #define MAX_TEMP 45.0f  // No Data is collected above 45 degree C.
 #define TEMP_CUT 30     // Separation point for temperature buckets 30 degree C.
-#define EIGEN_RATIO 0.35  // EIGEN_RATIO (must be greater than 0.35).
-#define EIGEN_MAG 0.97    // Eigen value magnitude (must be greater than 0.97).
+#define EIGEN_RATIO 0.35f  // EIGEN_RATIO (must be greater than 0.35).
+#define EIGEN_MAG 0.97f    // Eigen value magnitude (must be greater than 0.97).
 #ifdef ACCEL_CAL_DBG_ENABLED
 #define TEMP_HIST_LOW \
   16  // Putting all Temp counts in first bucket for temp < 16 degree C.
diff --git a/firmware/os/algos/calibration/common/diversity_checker.c b/firmware/os/algos/calibration/common/diversity_checker.c
index d71ad9a..3655147 100644
--- a/firmware/os/algos/calibration/common/diversity_checker.c
+++ b/firmware/os/algos/calibration/common/diversity_checker.c
@@ -78,10 +78,8 @@
   diverse_data->data_full = false;
 }
 
-void diversityCheckerUpdate(
-    struct DiversityChecker* diverse_data, float x, float y, float z) {
-  ASSERT_NOT_NULL(diverse_data);
-
+int32_t diversityCheckerFindNearestPoint(struct DiversityChecker* diverse_data,
+                                         float x, float y, float z) {
   // Converting three single inputs to a vector.
   const float vec[3] = {x, y, z};
 
@@ -91,44 +89,59 @@
   // normSquared result (k)
   float norm_squared_result;
 
-  // If memory is full, no need to run through the data.
-  if (!diverse_data->data_full) {
-    size_t i;
-    // Running over all existing data points
-    for (i = 0; i < diverse_data->num_points; ++i) {
-      // v = v1 - v2;
-      vecSub(vec_diff,
-             &diverse_data->diverse_data[i * THREE_AXIS_DATA_DIM],
-             vec,
-             THREE_AXIS_DATA_DIM);
+  size_t i;
 
-      // k = |v|^2
-      norm_squared_result = vecNormSquared(vec_diff, THREE_AXIS_DATA_DIM);
+  // Running over all existing data points
+  for (i = 0; i < diverse_data->num_points; ++i) {
+    // v = v1 - v2;
+    vecSub(vec_diff,
+           &diverse_data->diverse_data[i * THREE_AXIS_DATA_DIM],
+           vec,
+           THREE_AXIS_DATA_DIM);
 
-      // if k < Threshold then leave the function.
-      if (norm_squared_result < diverse_data->threshold) {
-        return;
-      }
+    // k = |v|^2
+    norm_squared_result = vecNormSquared(vec_diff, THREE_AXIS_DATA_DIM);
 
-      // if k > max_distance, count and leave the function.
-      if (norm_squared_result > diverse_data->max_distance) {
-        diverse_data->num_max_dist_violations++;
-        return;
-      }
+    // if k < Threshold then leave the function.
+    if (norm_squared_result < diverse_data->threshold) {
+      return (int32_t)i;
     }
 
-    // If none of the above caused to leave the function, data is diverse.
-    // Notice that the first data vector will be stored no matter what.
-    memcpy(&diverse_data->
-           diverse_data[diverse_data->num_points * THREE_AXIS_DATA_DIM],
-           vec,
-           sizeof(float) * THREE_AXIS_DATA_DIM);
-    // Count new data point.
-    diverse_data->num_points++;
+    // if k > max_distance, count and leave the function.
+    if (norm_squared_result > diverse_data->max_distance) {
+      diverse_data->num_max_dist_violations++;
+      return -2;
+    }
+  }
+  return -1;
+}
 
-    // Setting data_full to 1, if memory is full.
-    if (diverse_data->num_points == NUM_DIVERSE_VECTORS) {
-      diverse_data->data_full = true;
+void diversityCheckerUpdate(
+    struct DiversityChecker* diverse_data, float x, float y, float z) {
+  ASSERT_NOT_NULL(diverse_data);
+
+  // If memory is full, no need to run through the data.
+  if (!diverse_data->data_full) {
+
+    // diversityCheckerDataSet() returns -1, if input data is diverse against
+    // the already stored.
+    if (diversityCheckerFindNearestPoint(diverse_data, x, y, z) == -1) {
+      // Converting three single inputs to a vector.
+      const float vec[3] = {x, y, z};
+
+      // Notice that the first data vector will be stored no matter what.
+      memcpy(&diverse_data->
+             diverse_data[diverse_data->num_points * THREE_AXIS_DATA_DIM],
+             vec,
+             sizeof(float) * THREE_AXIS_DATA_DIM);
+
+      // Count new data point.
+      diverse_data->num_points++;
+
+      // Setting data_full to 1, if memory is full.
+      if (diverse_data->num_points == NUM_DIVERSE_VECTORS) {
+        diverse_data->data_full = true;
+      }
     }
   }
 }
diff --git a/firmware/os/algos/calibration/common/diversity_checker.h b/firmware/os/algos/calibration/common/diversity_checker.h
index 5a24529..62a1b3e 100644
--- a/firmware/os/algos/calibration/common/diversity_checker.h
+++ b/firmware/os/algos/calibration/common/diversity_checker.h
@@ -82,7 +82,7 @@
   // Threshold value that is used to check k against.
   float threshold;
 
-  // Threshold tuning paramter used to calculate threshold (k_algo):
+  // Threshold tuning parameter used to calculate threshold (k_algo):
   // threshold = threshold_tuning_param_sq * (local_field)^2.
   float threshold_tuning_param_sq;
 
@@ -133,6 +133,13 @@
 // as well as the setup variables for NormQuality check untouched.
 void diversityCheckerReset(struct DiversityChecker* diverse_data);
 
+// Checks if data point (x, y, z) is diverse against the diverse_data set. It
+// returns -1: when the input point is diverse or the index to which vector the
+// input is diverse
+  // returns -2: when a maximum distance check is violated
+int32_t diversityCheckerFindNearestPoint(struct DiversityChecker* diverse_data,
+                                         float x, float y, float z);
+
 // Main function. Tests the data (x,y,z) against the memory if diverse and
 // stores it, if so.
 void diversityCheckerUpdate(struct DiversityChecker* diverse_data, float x,
diff --git a/firmware/os/algos/calibration/common/sphere_fit_calibration.c b/firmware/os/algos/calibration/common/sphere_fit_calibration.c
index 2c26af5..b417506 100644
--- a/firmware/os/algos/calibration/common/sphere_fit_calibration.c
+++ b/firmware/os/algos/calibration/common/sphere_fit_calibration.c
@@ -19,7 +19,7 @@
                            const struct SphereFitData *data,
                            uint64_t timestamp_nanos);
 
-#define MIN_VALID_DATA_NORM (1e-4)
+#define MIN_VALID_DATA_NORM (1e-4f)
 
 // FUNCTION IMPLEMENTATIONS
 //////////////////////////////////////////////////////////////////////////////
diff --git a/firmware/os/algos/common/math/mat.c b/firmware/os/algos/common/math/mat.c
index 34aaa51..8b62cce 100644
--- a/firmware/os/algos/common/math/mat.c
+++ b/firmware/os/algos/common/math/mat.c
@@ -32,8 +32,8 @@
 #include <stddef.h>
 #include <string.h>
 
-#define EPSILON 1E-5
-#define CHOLESKY_TOLERANCE 1E-6
+#define EPSILON 1E-5f
+#define CHOLESKY_TOLERANCE 1E-6f
 
 // Forward declarations.
 static void mat33SwapRows(struct Mat33 *A, uint32_t i, uint32_t j);
@@ -248,8 +248,8 @@
       }
     }
     // divide by zero guard.
-    ASSERT(fabs(tmp.elem[i][i]) > 0);
-    if(!(fabs(tmp.elem[i][i]) > 0)) {
+    ASSERT(fabsf(tmp.elem[i][i]) > 0);
+    if(!(fabsf(tmp.elem[i][i]) > 0)) {
       return;
     }
     t = 1.0f / tmp.elem[i][i];
@@ -407,6 +407,16 @@
   initVec3(eigenvals, _eigenvals[0], _eigenvals[1], _eigenvals[2]);
 }
 
+float mat33Determinant(const struct Mat33 *A) {
+  ASSERT_NOT_NULL(A);
+  return A->elem[0][0] *
+      (A->elem[1][1] * A->elem[2][2] - A->elem[1][2] * A->elem[2][1])
+      - A->elem[0][1] *
+      (A->elem[1][0] * A->elem[2][2] - A->elem[1][2] * A->elem[2][0])
+      + A->elem[0][2] *
+      (A->elem[1][0] * A->elem[2][1] - A->elem[1][1] * A->elem[2][0]);
+}
+
 // index of largest off-diagonal element in row k
 UNROLLED
 uint32_t mat33Maxind(const struct Mat33 *A, uint32_t k) {
diff --git a/firmware/os/algos/common/math/mat.h b/firmware/os/algos/common/math/mat.h
index 13494f5..9d69405 100644
--- a/firmware/os/algos/common/math/mat.h
+++ b/firmware/os/algos/common/math/mat.h
@@ -125,6 +125,8 @@
 void mat33GetEigenbasis(struct Mat33 *S, struct Vec3 *eigenvals,
                         struct Mat33 *eigenvecs);
 
+// Computes the determinant of a 3 by 3 matrix.
+float mat33Determinant(const struct Mat33 *A);
 
 // 4x4 MATRIX MATH /////////////////////////////////////////////////////////////
 // Updates out with the multiplication of A and v, i.e.:
diff --git a/firmware/os/algos/common/math/vec.h b/firmware/os/algos/common/math/vec.h
index 0a4c8b3..e839ad5 100644
--- a/firmware/os/algos/common/math/vec.h
+++ b/firmware/os/algos/common/math/vec.h
@@ -70,6 +70,17 @@
   v->z += w->z;
 }
 
+// Sets u as the sum of v and w.
+static inline void vec3AddVecs(struct Vec3 *u, const struct Vec3 *v,
+                               const struct Vec3 *w) {
+  ASSERT_NOT_NULL(u);
+  ASSERT_NOT_NULL(v);
+  ASSERT_NOT_NULL(w);
+  u->x = v->x + w->x;
+  u->y = v->y + w->y;
+  u->z = v->z + w->z;
+}
+
 // Updates v as the subtraction of w from v.
 static inline void vec3Sub(struct Vec3 *v, const struct Vec3 *w) {
   ASSERT_NOT_NULL(v);
@@ -79,6 +90,17 @@
   v->z -= w->z;
 }
 
+// Sets u as the difference of v and w.
+static inline void vec3SubVecs(struct Vec3 *u, const struct Vec3 *v,
+                               const struct Vec3 *w) {
+  ASSERT_NOT_NULL(u);
+  ASSERT_NOT_NULL(v);
+  ASSERT_NOT_NULL(w);
+  u->x = v->x - w->x;
+  u->y = v->y - w->y;
+  u->z = v->z - w->z;
+}
+
 // Scales v by the scalar c, i.e. v = c * v.
 static inline void vec3ScalarMul(struct Vec3 *v, float c) {
   ASSERT_NOT_NULL(v);
diff --git a/firmware/os/core/appSec.c b/firmware/os/core/appSec.c
index 94cfeda..b1974f0 100644
--- a/firmware/os/core/appSec.c
+++ b/firmware/os/core/appSec.c
@@ -310,9 +310,21 @@
         .fwFlags = image->layout.flags,
         .appVer  = aosp->app_version,
         .payInfoType = image->layout.payload,
-        .rfu = { 0xFF, 0xFF },
+        .chreApiMajor = 0xFF,
+        .chreApiMinor = 0xFF,
     };
 
+    if (image->layout.flags & FL_APP_HDR_CHRE) {
+        if (aosp->chre_api_major || aosp->chre_api_minor) {
+            common.chreApiMajor = aosp->chre_api_major;
+            common.chreApiMinor = aosp->chre_api_minor;
+        } else {
+            // fields not defined prior to CHRE 1.1
+            common.chreApiMajor = 0x01;
+            common.chreApiMinor = 0x00;
+        }
+    }
+
     // check to see if this is special system types of payload
     switch(image->layout.payload) {
     case LAYOUT_APP:
diff --git a/firmware/os/core/nanohubCommand.c b/firmware/os/core/nanohubCommand.c
index 79d8804..6726118 100644
--- a/firmware/os/core/nanohubCommand.c
+++ b/firmware/os/core/nanohubCommand.c
@@ -50,6 +50,8 @@
 #include <cpu/cpuMath.h>
 #include <algos/ap_hub_sync.h>
 
+#include <chre.h>
+
 #define NANOHUB_COMMAND(_reason, _fastHandler, _handler, _minReqType, _maxReqType) \
         { .reason = _reason, .fastHandler = _fastHandler, .handler = _handler, \
           .minDataLen = sizeof(_minReqType), .maxDataLen = sizeof(_maxReqType) }
@@ -563,7 +565,7 @@
         if (mDownloadState->erase == true) {
             reply = NANOHUB_FIRMWARE_CHUNK_REPLY_WAIT;
             if (!mDownloadState->eraseScheduled) {
-                ret = osExtAppStopApps(APP_ID_ANY);
+                ret = osExtAppStopAppsByAppId(APP_ID_ANY);
                 osLog(LOG_INFO, "%s: unloaded apps, ret=%08lx\n", __func__, ret);
                 mDownloadState->eraseScheduled = osDefer(firmwareErase, NULL, false);
             }
@@ -664,12 +666,26 @@
     return sizeof(*resp);
 }
 
+static void nanohubDelayStartApps(void *cookie)
+{
+    uint32_t status = 0;
+    status = osExtAppStartAppsDelayed();
+    osLog(LOG_DEBUG, "Started delayed apps; EXT status: %08" PRIX32 "\n", status);
+}
+
 static void addDelta(struct ApHubSync *sync, uint64_t apTime, uint64_t hubTime)
 {
+    static bool delayStart = false;
+
 #if DEBUG_APHUB_TIME_SYNC
     syncDebugAdd(apTime, hubTime);
 #endif
     apHubSyncAddDelta(sync, apTime, hubTime);
+
+    if (!delayStart) {
+        delayStart = true;
+        osDefer(nanohubDelayStartApps, NULL, false);
+    }
 }
 
 static int64_t getAvgDelta(struct ApHubSync *sync)
@@ -930,13 +946,23 @@
         }
     } else if (event == EVT_APP_FROM_HOST_CHRE) {
         // new version of HAL; full support for CHRE apps
+        struct HostMsgHdrChreV10 *hostPacketV10 = rx;
         struct HostMsgHdrChre *hostPacket = rx;
         if (rx_len >= sizeof(struct HostMsgHdrChre) &&
             rx_len == sizeof(struct HostMsgHdrChre) + hostPacket->len &&
             osTidById(&hostPacket->appId, &tid)) {
-            if (osAppIsChre(tid)) {
+            if (osAppChreVersion(tid) == CHRE_API_VERSION_1_1) {
                 struct NanohubMsgChreHdr hdr = {
                     .size = hostPacket->len,
+                    .endpoint = hostPacket->endpoint,
+                    .appEvent = hostPacket->appEventId,
+                };
+                // CHRE app receives message in new format
+                resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len,
+                                               &hdr, sizeof(hdr), tid);
+            } else if (osAppChreVersion(tid) == CHRE_API_VERSION_1_0) {
+                struct NanohubMsgChreHdrV10 hdr = {
+                    .size = hostPacket->len,
                     .appEvent = hostPacket->appEventId,
                 };
                 // CHRE app receives message in new format
@@ -947,6 +973,31 @@
                 resp->accepted = forwardPacket(EVT_APP_FROM_HOST, hostPacket + 1, hostPacket->len,
                                                &hostPacket->len, sizeof(hostPacket->len), tid);
             }
+        } else if (rx_len >= sizeof(struct HostMsgHdrChreV10) &&
+                   rx_len == sizeof(struct HostMsgHdrChreV10) + hostPacketV10->len &&
+                   osTidById(&hostPacketV10->appId, &tid)) {
+            if (osAppChreVersion(tid) == CHRE_API_VERSION_1_1) {
+                struct NanohubMsgChreHdr hdr = {
+                    .size = hostPacketV10->len,
+                    .endpoint = CHRE_HOST_ENDPOINT_UNSPECIFIED,
+                    .appEvent = hostPacketV10->appEventId,
+                };
+                // CHRE app receives message in new format
+                resp->accepted = forwardPacket(event, hostPacketV10 + 1, hostPacketV10->len,
+                                               &hdr, sizeof(hdr), tid);
+            } else if (osAppChreVersion(tid) == CHRE_API_VERSION_1_0) {
+                struct NanohubMsgChreHdrV10 hdr = {
+                    .size = hostPacketV10->len,
+                    .appEvent = hostPacketV10->appEventId,
+                };
+                // CHRE app receives message in new format
+                resp->accepted = forwardPacket(event, hostPacketV10 + 1, hostPacketV10->len,
+                                               &hdr, sizeof(hdr), tid);
+            } else {
+                // legacy app receives message in old format
+                resp->accepted = forwardPacket(EVT_APP_FROM_HOST, hostPacketV10 + 1, hostPacketV10->len,
+                                               &hostPacketV10->len, sizeof(hostPacketV10->len), tid);
+            }
         } else {
             resp->accepted = false;
         }
@@ -1049,21 +1100,21 @@
 {
     struct NanohubHalMgmtRx *req = rx;
 
-    halSendMgmtResponse(NANOHUB_HAL_EXT_APPS_ON, osExtAppStartApps(le64toh(unaligned_u64(&req->appId))));
+    halSendMgmtResponse(NANOHUB_HAL_EXT_APPS_ON, osExtAppStartAppsByAppId(le64toh(unaligned_u64(&req->appId))));
 }
 
 static void halExtAppsOff(void *rx, uint8_t rx_len)
 {
     struct NanohubHalMgmtRx *req = rx;
 
-    halSendMgmtResponse(NANOHUB_HAL_EXT_APPS_OFF, osExtAppStopApps(le64toh(unaligned_u64(&req->appId))));
+    halSendMgmtResponse(NANOHUB_HAL_EXT_APPS_OFF, osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId))));
 }
 
 static void halExtAppDelete(void *rx, uint8_t rx_len)
 {
     struct NanohubHalMgmtRx *req = rx;
 
-    halSendMgmtResponse(NANOHUB_HAL_EXT_APP_DELETE, osExtAppEraseApps(le64toh(unaligned_u64(&req->appId))));
+    halSendMgmtResponse(NANOHUB_HAL_EXT_APP_DELETE, osExtAppEraseAppsByAppId(le64toh(unaligned_u64(&req->appId))));
 }
 
 static void halQueryMemInfo(void *rx, uint8_t rx_len)
@@ -1238,6 +1289,16 @@
     return NULL;
 }
 
+int64_t hostGetTimeDelta(void)
+{
+    int64_t delta = getAvgDelta(&mTimeSync);
+
+    if (delta == INT64_MIN)
+        return 0ULL;
+    else
+        return delta;
+}
+
 uint64_t hostGetTime(void)
 {
     int64_t delta = getAvgDelta(&mTimeSync);
diff --git a/firmware/os/core/nanohub_chre.c b/firmware/os/core/nanohub_chre.c
index b8e6825..5ed419b 100644
--- a/firmware/os/core/nanohub_chre.c
+++ b/firmware/os/core/nanohub_chre.c
@@ -31,6 +31,7 @@
 #include <timer.h>
 #include <util.h>
 #include <printf.h>
+#include <nanohubCommand.h>
 
 #include <chre.h>
 #include <chreApi.h>
@@ -75,7 +76,7 @@
     va_list innerArgs;
     enum chreLogLevel level = va_arg(args, int /* enums promoted to ints in va_args in C */);
     const static char levels[] = "EWIDV";
-    char clevel = (level > CHRE_LOG_DEBUG || level < 0) ? 'V' : levels[level];
+    char clevel = (level > CHRE_LOG_DEBUG || (int) level < 0) ? 'V' : levels[level];
     const char *str = va_arg(args, const char*);
     uintptr_t inner = va_arg(args, uintptr_t);
 
@@ -89,7 +90,7 @@
     va_list innerArgs;
     enum chreLogLevel level = va_arg(args, int /* enums promoted to ints in va_args in C */);
     const static char levels[] = "EWIDV";
-    char clevel = (level > CHRE_LOG_DEBUG || level < 0) ? 'V' : levels[level];
+    char clevel = (level > CHRE_LOG_DEBUG || (int) level < 0) ? 'V' : levels[level];
     const char *str = va_arg(args, const char*);
     uintptr_t inner = va_arg(args, uintptr_t);
 
@@ -105,6 +106,13 @@
         *timeNanos = sensorGetTime();
 }
 
+static void osChreApiGetHostTimeOffset(uintptr_t *retValP, va_list args)
+{
+    uint64_t *timeNanos = va_arg(args, uint64_t *);
+    if (timeNanos)
+        *timeNanos = hostGetTimeDelta();
+}
+
 static inline uint32_t osChreTimerSet(uint64_t duration, const void* cookie, bool oneShot)
 {
     uint32_t timId = timTimerSetNew(duration, cookie, oneShot);
@@ -132,9 +140,19 @@
 static inline void osChreAbort(uint32_t abortCode)
 {
     struct Task *task = osGetCurrentTask();
-    osLog(LOG_ERROR, "APP ID=0x%" PRIX64 " TID=0x%" PRIX16 " aborted [code 0x%" PRIX32 "]",
-          task->app->hdr.appId, task->tid, abortCode);
-    osTaskAbort(task);
+    if (task) {
+        if (task->app) {
+            osLog(LOG_ERROR, "APP ID=0x%" PRIX64 " TID=0x%" PRIX16 " aborted [code 0x%" PRIX32 "]",
+                  task->app->hdr.appId, task->tid, abortCode);
+        } else {
+            osLog(LOG_ERROR, "APP ID=NULL TID=0x%" PRIX16 " aborted [code 0x%" PRIX32 "]",
+                  task->tid, abortCode);
+        }
+        osTaskAbort(task);
+    } else {
+        osLog(LOG_ERROR, "osChreAbort called with no current task [code 0x%" PRIX32 "]",
+              abortCode);
+    }
 }
 
 static void osChreApiAbort(uintptr_t *retValP, va_list args)
@@ -184,17 +202,8 @@
     return osEnqueuePrivateEvtNew(evtType, evtData, evtFreeCallback, toTid);
 }
 
-static void osChreApiSendEvent(uintptr_t *retValP, va_list args)
-{
-    uint16_t evtType = va_arg(args, uint32_t); // stored as 32-bit
-    void *evtData = va_arg(args, void *);
-    chreEventCompleteFunction *freeCallback = va_arg(args, chreEventCompleteFunction *);
-    uint32_t toTid = va_arg(args, uint32_t);
-    *retValP = osChreSendEvent(evtType, evtData, freeCallback, toTid);
-}
-
 static bool osChreSendMessageToHost(void *message, uint32_t messageSize,
-                           uint32_t reservedMessageType,
+                           uint32_t messageType, uint16_t hostEndpoint,
                            chreMessageFreeFunction *freeCallback)
 {
     bool result = false;
@@ -224,10 +233,10 @@
 {
     void *message = va_arg(args, void *);
     uint32_t messageSize = va_arg(args, uint32_t);
-    uint32_t reservedMessageType = va_arg(args, uint32_t);
+    uint32_t messageType = va_arg(args, uint32_t);
     chreMessageFreeFunction *freeCallback = va_arg(args, chreMessageFreeFunction *);
 
-    *retValP = osChreSendMessageToHost(message, messageSize, reservedMessageType, freeCallback);
+    *retValP = osChreSendMessageToHost(message, messageSize, messageType, CHRE_HOST_ENDPOINT_BROADCAST, freeCallback);
 }
 
 static bool osChreSensorFindDefault(uint8_t sensorType, uint32_t *pHandle)
@@ -247,7 +256,7 @@
     *retValP = osChreSensorFindDefault(sensorType, pHandle);
 }
 
-static bool osChreSensorGetInfo(uint32_t sensorHandle, struct chreSensorInfo *info)
+static bool osChreSensorGetInfoOld(uint32_t sensorHandle, struct chreSensorInfo *info)
 {
     struct Sensor *s = sensorFindByHandle(sensorHandle);
     if (!s || !info)
@@ -267,6 +276,48 @@
     return true;
 }
 
+static bool osChreSensorGetInfo(uint32_t sensorHandle, struct chreSensorInfo *info)
+{
+    struct Sensor *s = sensorFindByHandle(sensorHandle);
+    uint32_t max = 0;
+    int i;
+    if (!s || !info)
+        return false;
+    const struct SensorInfo *si = s->si;
+    info->sensorName = si->sensorName;
+    info->sensorType = si->sensorType;
+    info->unusedFlags = 0;
+
+    if (si->sensorType == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT
+        || si->sensorType == CHRE_SENSOR_TYPE_STATIONARY_DETECT)
+        info->isOneShot = true;
+    else
+        info->isOneShot = false;
+    info->isOnChange = s->hasOnchange;
+    info->minInterval = CHRE_SENSOR_INTERVAL_DEFAULT;
+    if (si->supportedRates) {
+        for (i=0; si->supportedRates[i] != 0; i++) {
+            if (si->supportedRates[i] > max
+                && si->supportedRates[i] != SENSOR_RATE_ONDEMAND
+                && si->supportedRates[i] != SENSOR_RATE_ONCHANGE
+                && si->supportedRates[i] != SENSOR_RATE_ONESHOT) {
+                max = si->supportedRates[i];
+            }
+        }
+        if (max)
+            info->minInterval = (UINT32_C(1024000000) / max) * UINT64_C(1000);
+    }
+
+    return true;
+}
+
+static void osChreApiSensorGetInfoOld(uintptr_t *retValP, va_list args)
+{
+    uint32_t sensorHandle = va_arg(args, uint32_t);
+    struct chreSensorInfo *info = va_arg(args, struct chreSensorInfo *);
+    *retValP = osChreSensorGetInfoOld(sensorHandle, info);
+}
+
 static void osChreApiSensorGetInfo(uintptr_t *retValP, va_list args)
 {
     uint32_t sensorHandle = va_arg(args, uint32_t);
@@ -278,27 +329,32 @@
                                  struct chreSensorSamplingStatus *status)
 {
     struct Sensor *s = sensorFindByHandle(sensorHandle);
+    uint32_t rate;
+    uint64_t latency;
+
     if (!s || !status)
         return false;
 
-    if (s->currentRate == SENSOR_RATE_OFF
-        || s->currentRate >= SENSOR_RATE_POWERING_ON) {
+    rate = sensorGetHwRate(sensorHandle);
+    latency = sensorGetHwLatency(sensorHandle);
+
+    if (rate == 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)
+        if (rate == SENSOR_RATE_ONDEMAND
+            || rate == SENSOR_RATE_ONCHANGE
+            || rate == SENSOR_RATE_ONESHOT)
             status->interval = CHRE_SENSOR_INTERVAL_DEFAULT;
         else
-            status->interval = (UINT32_C(1024000000) / s->currentRate) * UINT64_C(1000);
+            status->interval = (UINT32_C(1024000000) / rate) * UINT64_C(1000);
 
-        if (s->currentLatency == SENSOR_LATENCY_NODATA)
+        if (latency == SENSOR_LATENCY_NODATA)
             status->latency = CHRE_SENSOR_INTERVAL_DEFAULT;
         else
-            status->latency = s->currentLatency;
+            status->latency = latency;
     }
 
     return true;
@@ -355,10 +411,7 @@
             ret = sensorRequestRateChange(0, sensorHandle, rate, latency);
         }
     } else if (mode & (CHRE_SENSOR_CONFIGURE_RAW_REPORT_CONTINUOUS|CHRE_SENSOR_CONFIGURE_RAW_REPORT_ONE_SHOT)) {
-        if (interval != CHRE_SENSOR_INTERVAL_DEFAULT
-            || latency != CHRE_SENSOR_LATENCY_DEFAULT)
-            ret = false;
-        else if (sensorGetReqRate(sensorHandle) == SENSOR_RATE_OFF)
+        if (sensorGetReqRate(sensorHandle) == SENSOR_RATE_OFF)
             ret = osEventsSubscribe(2, sensorGetMyEventType(s->si->sensorType), sensorGetMyCfgEventType(s->si->sensorType));
         else
             ret = true;
@@ -421,6 +474,132 @@
         *pHwId = osChreGetPlatformId();
 }
 
+static void osChreEventSendEvent(uintptr_t *retValP, va_list args)
+{
+    uint16_t evtType = va_arg(args, uint32_t); // stored as 32-bit
+    void *evtData = va_arg(args, void *);
+    chreEventCompleteFunction *freeCallback = va_arg(args, chreEventCompleteFunction *);
+    uint32_t toTid = va_arg(args, uint32_t);
+    *retValP = osChreSendEvent(evtType, evtData, freeCallback, toTid);
+}
+
+static void osChreEventSendMessageToHost(uintptr_t *retValP, va_list args)
+{
+    void *message = va_arg(args, void *);
+    uint32_t messageSize = va_arg(args, size_t);
+    uint32_t messageType = va_arg(args, uint32_t);
+    uint16_t hostEndpoint = va_arg(args, uint32_t);
+    chreMessageFreeFunction *freeCallback = va_arg(args, chreMessageFreeFunction *);
+
+    *retValP = osChreSendMessageToHost(message, messageSize, messageType, hostEndpoint, freeCallback);
+}
+
+static bool chreInfoByTid(uint32_t tid, struct chreNanoappInfo *info)
+{
+    struct Task *task = osTaskFindByTid(tid);
+    if (task) {
+        info->appId = task->app->hdr.appId;
+        info->version = task->app->hdr.appVer;
+        info->instanceId = tid;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static void osChreEventInfoByAppId(uintptr_t *retValP, va_list args)
+{
+    uint32_t app_lo = va_arg(args, uint32_t);
+    uint32_t app_hi = va_arg(args, uint32_t);
+    struct chreNanoappInfo *info = va_arg(args, struct chreNanoappInfo *);
+    uint64_t appId = (((uint64_t)app_hi) << 32) | app_lo;
+    uint32_t tid;
+
+    if (osTidById(&appId, &tid))
+        *retValP = chreInfoByTid(tid, info);
+    else
+        *retValP = false;
+}
+
+static void osChreEeventInfoByInstId(uintptr_t *retValP, va_list args)
+{
+    uint32_t tid = va_arg(args, uint32_t);
+    struct chreNanoappInfo *info = va_arg(args, struct chreNanoappInfo *);
+
+    *retValP = chreInfoByTid(tid, info);
+}
+
+static void osChreEventCfgInfo(uintptr_t *retValP, va_list args)
+{
+    bool enable = va_arg(args, int);
+    if (enable)
+        osEventsSubscribe(2, EVT_APP_STARTED, EVT_APP_STOPPED);
+    else
+        osEventsUnsubscribe(2, EVT_APP_STARTED, EVT_APP_STOPPED);
+}
+
+static void osChreDrvGnssGetCap(uintptr_t *retValP, va_list args)
+{
+    *retValP = CHRE_GNSS_CAPABILITIES_NONE;
+}
+
+static void osChreDrvGnssLocStartAsync(uintptr_t *retValP, va_list args)
+{
+    // uint32_t minIntervalMs = va_args(args, uint32_t);
+    // uint32_t minTimeToNextFixMs = va_args(args, uint32_t);
+    // const void *cookie = va_args(args, void *);
+    *retValP = false;
+}
+
+static void osChreDrvGnssLocStopAsync(uintptr_t *retValP, va_list args)
+{
+    // const void *cookie = va_args(args, void *);
+    *retValP = false;
+}
+
+static void osChreDrvGnssMeasStartAsync(uintptr_t *retValP, va_list args)
+{
+    // uint32_t minIntervalMs = va_args(args, uint32_t);
+    // const void *cookie = va_args(args, void *);
+    *retValP = false;
+}
+
+static void osChreDrvGnssMeasStopAsync(uintptr_t *retValP, va_list args)
+{
+    // const void *cookie = va_args(args, void *);
+    *retValP = false;
+}
+
+static void osChreDrvWifiGetCap(uintptr_t *retValP, va_list args)
+{
+    *retValP = CHRE_WIFI_CAPABILITIES_NONE;
+}
+
+static void osChreDrvWifiConfScanMonAsync(uintptr_t *retValP, va_list args)
+{
+    // bool enable = va_args(args, int);
+    // const void *cookie = va_args(args, void *);
+    *retValP = false;
+}
+
+static void osChreDrvWifiReqScanAsync(uintptr_t *retValP, va_list args)
+{
+    // const struct chreWifiScanParams *params = va_args(args, struct chreWifiScanParams *);
+    // const void *cookie = va_args(args, void *);
+    *retValP = false;
+}
+
+static void osChreDrvWwanGetCap(uintptr_t *retValP, va_list args)
+{
+    *retValP = CHRE_WWAN_CAPABILITIES_NONE;
+}
+
+static void osChreDrvWwanGetCallInfoAsync(uintptr_t *retValP, va_list args)
+{
+    // const void *cookie = va_args(args, void *);
+    *retValP = false;
+}
+
 static const struct SyscallTable chreMainApiTable = {
     .numEntries = SYSCALL_CHRE_MAIN_API_LAST,
     .entry = {
@@ -429,15 +608,17 @@
         [SYSCALL_CHRE_MAIN_API_GET_APP_ID]              = { .func = osChreApiGetAppId },
         [SYSCALL_CHRE_MAIN_API_GET_INST_ID]             = { .func = osChreApiGetInstanceId },
         [SYSCALL_CHRE_MAIN_API_GET_TIME]                = { .func = osChreApiGetTime },
+        [SYSCALL_CHRE_MAIN_API_GET_HOST_TIME_OFFSET]    = { .func = osChreApiGetHostTimeOffset },
         [SYSCALL_CHRE_MAIN_API_TIMER_SET]               = { .func = osChreApiTimerSet },
         [SYSCALL_CHRE_MAIN_API_TIMER_CANCEL]            = { .func = osChreApiTimerCancel },
         [SYSCALL_CHRE_MAIN_API_ABORT]                   = { .func = osChreApiAbort },
         [SYSCALL_CHRE_MAIN_API_HEAP_ALLOC]              = { .func = osChreApiHeapAlloc },
         [SYSCALL_CHRE_MAIN_API_HEAP_FREE]               = { .func = osChreApiHeapFree },
-        [SYSCALL_CHRE_MAIN_API_SEND_EVENT]              = { .func = osChreApiSendEvent },
+        [SYSCALL_CHRE_MAIN_API_SEND_EVENT]              = { .func = osChreEventSendEvent },
         [SYSCALL_CHRE_MAIN_API_SEND_MSG]                = { .func = osChreApiSendMessageToHost },
         [SYSCALL_CHRE_MAIN_API_SENSOR_FIND_DEFAULT]     = { .func = osChreApiSensorFindDefault },
-        [SYSCALL_CHRE_MAIN_API_SENSOR_GET_INFO]         = { .func = osChreApiSensorGetInfo },
+        [SYSCALL_CHRE_MAIN_API_SENSOR_GET_INFO_OLD]     = { .func = osChreApiSensorGetInfoOld },
+        [SYSCALL_CHRE_MAIN_API_SENSOR_GET_INFO]     = { .func = osChreApiSensorGetInfo },
         [SYSCALL_CHRE_MAIN_API_SENSOR_GET_STATUS]       = { .func = osChreApiSensorGetStatus },
         [SYSCALL_CHRE_MAIN_API_SENSOR_CONFIG]           = { .func = osChreApiSensorConfig },
         [SYSCALL_CHRE_MAIN_API_GET_OS_API_VERSION]      = { .func = osChreApiChreApiVersion },
@@ -446,10 +627,59 @@
     },
 };
 
+static const struct SyscallTable chreMainEventTable = {
+    .numEntries = SYSCALL_CHRE_MAIN_EVENT_LAST,
+    .entry = {
+        [SYSCALL_CHRE_MAIN_EVENT_SEND_EVENT]           = { .func = osChreEventSendEvent },
+        [SYSCALL_CHRE_MAIN_EVENT_SEND_MSG]             = { .func = osChreEventSendMessageToHost },
+        [SYSCALL_CHRE_MAIN_EVENT_INFO_BY_APP_ID]       = { .func = osChreEventInfoByAppId },
+        [SYSCALL_CHRE_MAIN_EVENT_INFO_BY_INST_ID]      = { .func = osChreEeventInfoByInstId },
+        [SYSCALL_CHRE_MAIN_EVENT_CFG_INFO]             = { .func = osChreEventCfgInfo },
+    },
+};
+
 static const struct SyscallTable chreMainTable = {
     .numEntries = SYSCALL_CHRE_MAIN_LAST,
     .entry = {
         [SYSCALL_CHRE_MAIN_API]     = { .subtable = (struct SyscallTable*)&chreMainApiTable,     },
+        [SYSCALL_CHRE_MAIN_EVENT]   = { .subtable = (struct SyscallTable*)&chreMainEventTable,   },
+    },
+};
+
+static const struct SyscallTable chreDrvGnssTable = {
+    .numEntries = SYSCALL_CHRE_DRV_GNSS_LAST,
+    .entry = {
+        [SYSCALL_CHRE_DRV_GNSS_GET_CAP]                 = { .func = osChreDrvGnssGetCap },
+        [SYSCALL_CHRE_DRV_GNSS_LOC_START_ASYNC]         = { .func = osChreDrvGnssLocStartAsync },
+        [SYSCALL_CHRE_DRV_GNSS_LOC_STOP_ASYNC]          = { .func = osChreDrvGnssLocStopAsync },
+        [SYSCALL_CHRE_DRV_GNSS_MEAS_START_ASYNC]        = { .func = osChreDrvGnssMeasStartAsync },
+        [SYSCALL_CHRE_DRV_GNSS_MEAS_STOP_ASYNC]         = { .func = osChreDrvGnssMeasStopAsync },
+    },
+};
+
+static const struct SyscallTable chreDrvWifiTable = {
+    .numEntries = SYSCALL_CHRE_DRV_WIFI_LAST,
+    .entry = {
+        [SYSCALL_CHRE_DRV_WIFI_GET_CAP]                 = { .func = osChreDrvWifiGetCap },
+        [SYSCALL_CHRE_DRV_WIFI_CONF_SCAN_MON_ASYNC]     = { .func = osChreDrvWifiConfScanMonAsync },
+        [SYSCALL_CHRE_DRV_WIFI_REQ_SCAN_ASYNC]          = { .func = osChreDrvWifiReqScanAsync },
+    },
+};
+
+static const struct SyscallTable chreDrvWwanTable = {
+    .numEntries = SYSCALL_CHRE_DRV_WWAN_LAST,
+    .entry = {
+        [SYSCALL_CHRE_DRV_WWAN_GET_CAP]                 = { .func = osChreDrvWwanGetCap },
+        [SYSCALL_CHRE_DRV_WWAN_GET_CELL_INFO_ASYNC]     = { .func = osChreDrvWwanGetCallInfoAsync },
+    },
+};
+
+static const struct SyscallTable chreDriversTable = {
+    .numEntries = SYSCALL_CHRE_DRV_LAST,
+    .entry = {
+        [SYSCALL_CHRE_DRV_GNSS]     = { .subtable = (struct SyscallTable*)&chreDrvGnssTable,     },
+        [SYSCALL_CHRE_DRV_WIFI]     = { .subtable = (struct SyscallTable*)&chreDrvWifiTable,     },
+        [SYSCALL_CHRE_DRV_WWAN]     = { .subtable = (struct SyscallTable*)&chreDrvWwanTable,     },
     },
 };
 
@@ -457,6 +687,7 @@
     .numEntries = SYSCALL_CHRE_LAST,
     .entry = {
         [SYSCALL_CHRE_MAIN]    = { .subtable = (struct SyscallTable*)&chreMainTable,    },
+        [SYSCALL_CHRE_DRIVERS] = { .subtable = (struct SyscallTable*)&chreDriversTable, },
     },
 };
 
diff --git a/firmware/os/core/osApi.c b/firmware/os/core/osApi.c
index 8361d9a..098e2dc 100644
--- a/firmware/os/core/osApi.c
+++ b/firmware/os/core/osApi.c
@@ -28,6 +28,7 @@
 #include <heap.h>
 #include <i2c.h>
 #include <nanohubCommand.h>
+#include <seos_priv.h>
 
 static struct SlabAllocator *mSlabAllocator;
 
diff --git a/firmware/os/core/sensors.c b/firmware/os/core/sensors.c
index b8caec5..e91b065 100644
--- a/firmware/os/core/sensors.c
+++ b/firmware/os/core/sensors.c
@@ -815,6 +815,20 @@
     return s ? s->currentLatency : SENSOR_LATENCY_INVALID;
 }
 
+uint32_t sensorGetHwRate(uint32_t sensorHandle)
+{
+    struct Sensor* s = sensorFindByHandle(sensorHandle);
+
+    return s ? sensorCalcHwRate(s, 0, 0) : SENSOR_RATE_OFF;
+}
+
+uint64_t sensorGetHwLatency(uint32_t sensorHandle)
+{
+    struct Sensor* s = sensorFindByHandle(sensorHandle);
+
+    return s ? sensorCalcHwLatency(s) : SENSOR_LATENCY_INVALID;
+}
+
 uint32_t sensorGetReqRate(uint32_t sensorHandle)
 {
     struct SensorsClientRequest *req = sensorClientRequestFind(sensorHandle, osGetCurrentTid());
diff --git a/firmware/os/core/seos.c b/firmware/os/core/seos.c
index 52ccf7a..418fe76 100644
--- a/firmware/os/core/seos.c
+++ b/firmware/os/core/seos.c
@@ -97,6 +97,16 @@
     return task && osTaskIsChre(task);
 }
 
+uint32_t osAppChreVersion(uint16_t tid)
+{
+    struct Task *task = osTaskFindByTid(tid);
+
+    if (task)
+        return osTaskChreVersion(task);
+    else
+        return 0;
+}
+
 static inline uint32_t osTaskClrSetFlags(struct Task *task, uint32_t clrMask, uint32_t setMask)
 {
     while (true) {
@@ -290,27 +300,39 @@
 
 static void osTaskRelease(struct Task *task)
 {
-    uint16_t tid = task->tid;
+    uint32_t taskTid = task->tid;
+    uint32_t platErr, sensorErr;
+    int timErr, heapErr;
+    uint64_t appId;
 
-    osSetCurrentTask(mSystemTask);
+    if (task->app)
+        appId = task->app->hdr.appId;
+    else
+        appId = 0;
 
-    platFreeResources(tid); // HW resources cleanup (IRQ, DMA etc)
-    sensorFreeAll(tid);
-    timTimerCancelAll(tid);
-    heapFreeAll(tid);
+    platErr = platFreeResources(taskTid); // HW resources cleanup (IRQ, DMA etc)
+    sensorErr = sensorFreeAll(taskTid);
+    timErr = timTimerCancelAll(taskTid);
+    heapErr = heapFreeAll(taskTid);
+
+    if (platErr || sensorErr || timErr || heapErr)
+        osLog(LOG_WARN, "released app ID 0x%" PRIx64 "; plat:%08" PRIx32 " sensor:%08" PRIx32 " tim:%d heap:%d; TID %04" PRIX32 "\n", appId, platErr, sensorErr, timErr, heapErr, taskTid);
+    else
+        osLog(LOG_INFO, "released app ID 0x%" PRIx64 "; TID %04" PRIX32 "\n", appId, taskTid);
 }
 
 static inline void osTaskEnd(struct Task *task)
 {
-    struct Task *preempted = osSetCurrentTask(task);
-
-    cpuAppEnd(task->app, &task->platInfo);
+    if (!osTaskTestFlags(task, FL_TASK_ABORTED)) {
+        struct Task *preempted = osSetCurrentTask(task);
+        cpuAppEnd(task->app, &task->platInfo);
+        osSetCurrentTask(preempted);
+    }
 
     // task was supposed to release it's resources,
     // but we do our cleanup anyway
-    osTaskRelease(task);
     // NOTE: we don't need to unsubscribe from events
-    osSetCurrentTask(preempted);
+    osTaskRelease(task);
 }
 
 static inline void osTaskHandle(struct Task *task, uint16_t evtType, uint16_t fromTid, const void* evtData)
@@ -711,7 +733,8 @@
 
         // print external NanoApp info to facilitate NanoApp debugging
         if (!(task->app->hdr.fwFlags & FL_APP_HDR_INTERNAL))
-            osLog(LOG_INFO, "loaded app ID 0x%llx at flash base 0x%08x ram base 0x%08x; TID %04X\n",
+            osLog(LOG_INFO,
+                  "loaded app ID 0x%" PRIx64 " at flash base 0x%" PRIxPTR " ram base 0x%" PRIxPTR "; TID %04" PRIX16 "\n",
                   task->app->hdr.appId, (uintptr_t) task->app, (uintptr_t) task->platInfo.data, task->tid);
 
         done = osTaskInit(task);
@@ -721,48 +744,79 @@
             osUnloadApp(task);
         } else {
             osAddTask(task);
+            (void)osEnqueueEvt(EVT_APP_BEGIN, task, NULL);
         }
     }
 
     return done;
 }
 
-static bool osStopTask(struct Task *task)
+static bool osStopTask(struct Task *task, bool abort)
 {
+    struct Task *preempted;
+
     if (!task)
         return false;
 
+    if (osTaskTestFlags(task, FL_TASK_STOPPED))
+        return true;
+
+    preempted = osSetCurrentTask(mSystemTask);
     osRemoveTask(task);
-
-    if (osTaskGetIoCount(task))
-    {
-        osTaskHandle(task, EVT_APP_STOP, OS_SYSTEM_TID, NULL);
-        osEnqueueEvt(EVT_APP_END, task, NULL);
-    } else {
-        osTaskEnd(task); // calls app END() and Release()
-        osUnloadApp(task);
-    }
-
     osTaskClrSetFlags(task, 0, FL_TASK_STOPPED);
+
+    if (abort)
+        osTaskClrSetFlags(task, 0, FL_TASK_ABORTED);
+    else if (osTaskGetIoCount(task))
+        osTaskHandle(task, EVT_APP_STOP, OS_SYSTEM_TID, NULL);
+    osEnqueueEvt(EVT_APP_END, task, NULL);
+
+    osSetCurrentTask(preempted);
+
     return true;
 }
 
 void osTaskAbort(struct Task *task)
 {
-    if (!task)
-        return;
-
-    osRemoveTask(task); // remove from active task list
-    // do not call app END()
-    osTaskRelease(task); // release all system resources
-    osUnloadApp(task); // destroy platform app object in RAM
+    osStopTask(task, true);
 }
 
-static bool osExtAppFind(struct SegmentIterator *it, uint64_t appId)
+static bool matchDelayStart(const void *cookie, const struct AppHdr *app)
 {
-    uint64_t vendor = APP_ID_GET_VENDOR(appId);
-    uint64_t seqId = APP_ID_GET_SEQ_ID(appId);
-    uint64_t curAppId;
+    bool match = (bool)cookie;
+
+    if (app->hdr.fwFlags & FL_APP_HDR_CHRE) {
+        if (app->hdr.chreApiMajor == 0xFF && app->hdr.chreApiMinor == 0xFF)
+            return !match;
+        else if ((app->hdr.chreApiMajor < 0x01) ||
+                 (app->hdr.chreApiMajor == 0x01 && app->hdr.chreApiMinor < 0x01))
+            return !match;
+        else
+            return match;
+    } else {
+        return !match;
+    }
+}
+
+static bool matchAppId(const void *data, const struct AppHdr *app)
+{
+    uint64_t appId, vendor, seqId, curAppId;
+
+    memcpy(&appId, data, sizeof(appId));
+    vendor = APP_ID_GET_VENDOR(appId);
+    seqId = APP_ID_GET_SEQ_ID(appId);
+    curAppId = app->hdr.appId;
+
+    if ((vendor == APP_VENDOR_ANY || vendor == APP_ID_GET_VENDOR(curAppId)) &&
+        (seqId == APP_SEQ_ID_ANY || seqId == APP_ID_GET_SEQ_ID(curAppId))) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool osExtAppFind(struct SegmentIterator *it, appMatchFunc func, const void *data)
+{
     const struct AppHdr *app;
     const struct Segment *seg;
 
@@ -775,17 +829,14 @@
         if (seg->state != SEG_ST_VALID)
             continue;
         app = osSegmentGetData(seg);
-        curAppId = app->hdr.appId;
-
-        if ((vendor == APP_VENDOR_ANY || vendor == APP_ID_GET_VENDOR(curAppId)) &&
-            (seqId == APP_SEQ_ID_ANY || seqId == APP_ID_GET_SEQ_ID(curAppId)))
+        if (func(data, app))
             return true;
     }
 
     return false;
 }
 
-static uint32_t osExtAppStopEraseApps(uint64_t appId, bool doErase)
+static uint32_t osExtAppStopEraseApps(appMatchFunc func, const void *data, bool doErase)
 {
     const struct AppHdr *app;
     int32_t len;
@@ -798,7 +849,7 @@
     struct Task *task;
 
     osSegmentIteratorInit(&it);
-    while (osExtAppFind(&it, appId)) {
+    while (osExtAppFind(&it, func, data)) {
         app = osSegmentGetData(it.seg);
         len = osSegmentGetSize(it.seg);
         if (!osExtAppIsValid(app, len))
@@ -812,7 +863,7 @@
         task = osTaskFindByAppID(app->hdr.appId);
         if (task) {
             taskCount++;
-            if (osStopTask(task))
+            if (osStopTask(task, false))
                stopCount++;
         }
     }
@@ -824,14 +875,14 @@
     return stat.value;
 }
 
-uint32_t osExtAppStopApps(uint64_t appId)
+uint32_t osExtAppStopAppsByAppId(uint64_t appId)
 {
-    return osExtAppStopEraseApps(appId, false);
+    return osExtAppStopEraseApps(matchAppId, &appId, false);
 }
 
-uint32_t osExtAppEraseApps(uint64_t appId)
+uint32_t osExtAppEraseAppsByAppId(uint64_t appId)
 {
-    return osExtAppStopEraseApps(appId, true);
+    return osExtAppStopEraseApps(matchAppId, &appId, true);
 }
 
 static void osScanExternal()
@@ -858,7 +909,7 @@
     }
 }
 
-uint32_t osExtAppStartApps(uint64_t appId)
+static uint32_t osExtAppStartApps(appMatchFunc func, void *data)
 {
     const struct AppHdr *app;
     int32_t len;
@@ -873,7 +924,7 @@
     osScanExternal();
 
     osSegmentIteratorInit(&it);
-    while (osExtAppFind(&it, appId)) {
+    while (osExtAppFind(&it, func, data)) {
         app = osSegmentGetData(it.seg);
         len = osSegmentGetSize(it.seg);
 
@@ -884,7 +935,7 @@
         appCount++;
         checkIt = it;
         // find the most recent copy
-        while (osExtAppFind(&checkIt, app->hdr.appId)) {
+        while (osExtAppFind(&checkIt, matchAppId, &app->hdr.appId)) {
             if (osExtAppErase(app)) // erase the old one, so we skip it next time
                 eraseCount++;
             app = osSegmentGetData(checkIt.seg);
@@ -908,6 +959,16 @@
     return stat.value;
 }
 
+uint32_t osExtAppStartAppsByAppId(uint64_t appId)
+{
+    return osExtAppStartApps(matchAppId, &appId);
+}
+
+uint32_t osExtAppStartAppsDelayed()
+{
+    return osExtAppStartApps(matchDelayStart, (void *)true);
+}
+
 static void osStartTasks(void)
 {
     const struct AppHdr *app;
@@ -958,19 +1019,20 @@
     }
 
     osLog(LOG_DEBUG, "Starting external apps...\n");
-    status = osExtAppStartApps(APP_ID_ANY);
+    status = osExtAppStartApps(matchDelayStart, (void *)false);
     osLog(LOG_DEBUG, "Started %" PRIu32 " internal apps; EXT status: %08" PRIX32 "\n", taskCnt, status);
 }
 
 static void osInternalEvtHandle(uint32_t evtType, void *evtData)
 {
     union SeosInternalSlabData *da = (union SeosInternalSlabData*)evtData;
-    struct Task *task;
+    struct Task *task, *ssTask;
     uint32_t i, j;
     uint16_t tid = EVENT_GET_ORIGIN(evtType);
-    uint16_t evt = EVENT_GET_EVENT(evtType);
+    uint16_t evt = EVENT_GET_EVENT(evtType), newEvt;
     struct Task *srcTask = osTaskFindByTid(tid);
     struct Task *preempted = osSetCurrentTask(srcTask);
+    struct AppEventStartStop ssMsg;
 
     switch (evt) {
     case EVT_SUBSCRIBE_TO_EVT:
@@ -1007,10 +1069,31 @@
         }
         break;
 
+    case EVT_APP_BEGIN:
     case EVT_APP_END:
-        task = evtData;
-        osTaskEnd(task);
-        osUnloadApp(task);
+        ssTask = evtData;
+        ssMsg.appId = ssTask->app->hdr.appId;
+        ssMsg.version = ssTask->app->hdr.appVer;
+        ssMsg.tid = ssTask->tid;
+        if (evt == EVT_APP_BEGIN) {
+            newEvt = EVT_APP_STARTED;
+        } else {
+            newEvt = EVT_APP_STOPPED;
+            osTaskEnd(ssTask);
+            osUnloadApp(ssTask);
+        }
+
+        /* send this event to all tasks who want it */
+        for_each_task(&mTasks, task) {
+            if (task != ssTask) {
+                for (i = 0; i < task->subbedEvtCount; i++) {
+                    if (task->subbedEvents[i] == newEvt) {
+                        osTaskHandle(task, newEvt, OS_SYSTEM_TID, &ssMsg);
+                        break;
+                    }
+                }
+            }
+        }
         break;
 
     case EVT_DEFERRED_CALLBACK:
@@ -1133,13 +1216,22 @@
 
 static bool osEventsSubscribeUnsubscribeV(bool sub, uint32_t numEvts, va_list ap)
 {
-    union SeosInternalSlabData *act = slabAllocatorAlloc(mMiscInternalThingsSlab);
+    struct Task *task = osGetCurrentTask();
+    union SeosInternalSlabData *act;
     int i;
 
-    if (!act || numEvts > MAX_EVT_SUB_CNT)
+    if (!sub && osTaskTestFlags(task, FL_TASK_STOPPED)) // stopping, so this is a no-op
+        return true;
+
+    if (numEvts > MAX_EVT_SUB_CNT)
         return false;
 
-    act->evtSub.tid = osGetCurrentTid();
+    act = slabAllocatorAlloc(mMiscInternalThingsSlab);
+
+    if (!act)
+        return false;
+
+    act->evtSub.tid = task->tid;
     act->evtSub.numEvts = numEvts;
     for (i = 0; i < numEvts; i++)
         act->evtSub.evts[i] = va_arg(ap, uint32_t);
@@ -1202,12 +1294,8 @@
 
     osTaskAddIoCount(task, 1);
 
-    if (osTaskTestFlags(task, FL_TASK_STOPPED)) {
-        handleEventFreeing(evtType, evtData, evtFreeInfo);
-        return true;
-    }
-
-    if (!evtQueueEnqueue(mEvtsInternal, evtType, evtData, evtFreeInfo, urgent)) {
+    if (osTaskTestFlags(task, FL_TASK_STOPPED) ||
+        !evtQueueEnqueue(mEvtsInternal, evtType, evtData, evtFreeInfo, urgent)) {
         osTaskAddIoCount(task, -1);
         return false;
     }
diff --git a/firmware/os/core/timer.c b/firmware/os/core/timer.c
index 76df80b..ace8072 100644
--- a/firmware/os/core/timer.c
+++ b/firmware/os/core/timer.c
@@ -31,6 +31,8 @@
 
 #define MAX_INTERNAL_EVENTS       32 //also used for external app timer() calls
 
+#define MAX_TIMER_ID              0xFF
+
 #define INFO_PRINT(fmt, ...) do { \
         osLog(LOG_INFO, "%s " fmt, "[timer]", ##__VA_ARGS__); \
     } while (0);
@@ -40,7 +42,8 @@
 struct Timer {
     uint64_t      expires; /* time of next expiration */
     uint64_t      period;  /* 0 for oneshot */
-    uint16_t      id;      /* 0 for disabled */
+    uint8_t       id;      /* 0 for disabled */
+    uint8_t       useRtc;  /* 1 for rtc, 0 for tim */
     uint16_t      tid;     /* we need TID always, for system management */
     uint32_t      jitterPpm;
     uint32_t      driftPpm;
@@ -102,7 +105,7 @@
 {
     uint32_t maxDrift = 0, maxJitter = 0, maxErrTotal = 0;
     bool somethingDone, totalSomethingDone = false;
-    uint64_t nextTimer;
+    uint64_t nextTimer, expires;
     uint32_t i;
     struct Timer *tim;
 
@@ -118,7 +121,7 @@
             if (!tim->id)
                 continue;
 
-            if (tim->expires <= timGetTime()) {
+            if ((!tim->useRtc && tim->expires <= timGetTime()) || (tim->useRtc && tim->expires <= rtcGetTime())) {
                 somethingDone = true;
                 if (tim->period) {
                     tim->expires += tim->period;
@@ -136,8 +139,12 @@
                     maxDrift = tim->driftPpm;
                 if (tim->driftPpm + tim->jitterPpm > maxErrTotal)
                     maxErrTotal = tim->driftPpm + tim->jitterPpm;
-                if (!nextTimer || nextTimer > tim->expires)
-                    nextTimer = tim->expires;
+                if (tim->useRtc)
+                    expires = tim->expires - rtcGetTime() + timGetTime();
+                else
+                    expires = tim->expires;
+                if (!nextTimer || nextTimer > expires)
+                    nextTimer = expires;
             }
         }
 
@@ -155,9 +162,9 @@
     return totalSomethingDone;
 }
 
-static uint32_t timTimerSetEx(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TaggedPtr info, void* data, bool oneShot)
+static uint32_t timTimerSetEx(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TaggedPtr info, void* data, bool oneShot, bool useRtc)
 {
-    uint64_t curTime = timGetTime();
+    uint64_t curTime = useRtc ? rtcGetTime() : timGetTime();
     int32_t idx = atomicBitsetFindClearAndSet(mTimersValid);
     struct Timer *t;
     uint16_t timId;
@@ -169,7 +176,7 @@
 
     /* generate next timer ID */
     do {
-        timId = atomicAdd32bits(&mNextTimerId, 1);
+        timId = atomicAdd32bits(&mNextTimerId, 1) & MAX_TIMER_ID;
     } while (!timId || timFindTimerById(timId));
 
     /* grab our struct & fill it in */
@@ -180,10 +187,11 @@
     t->driftPpm = driftPpm;
     t->callInfo = info;
     t->callData = data;
+    t->useRtc = useRtc;
+    t->tid = osGetCurrentTid();
 
     /* as soon as we write timer Id, it becomes valid and might fire */
     t->id = timId;
-    t->tid = osGetCurrentTid();
 
     /* fire as needed & recalc alarms*/
     timFireAsNeededAndUpdateAlarms();
@@ -194,17 +202,17 @@
 
 uint32_t timTimerSet(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TimTimerCbkF cbk, void* data, bool oneShot)
 {
-    return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromPtr(cbk), data, oneShot);
+    return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromPtr(cbk), data, oneShot, false);
 }
 
 uint32_t timTimerSetAsApp(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, uint32_t tid, void* data, bool oneShot)
 {
-    return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromUint(0), data, oneShot);
+    return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromUint(0), data, oneShot, false);
 }
 
 uint32_t timTimerSetNew(uint64_t length, const void* data, bool oneShot)
 {
-    return timTimerSetEx(length, 0, 0, taggedPtrMakeFromUint(0), (void *)data, oneShot);
+    return timTimerSetEx(length, 0, 50, taggedPtrMakeFromUint(0), (void *)data, oneShot, true);
 }
 
 static bool timerEventMatch(uint32_t evtType, const void *evtData, void *context)
diff --git a/firmware/os/drivers/bosch_bmi160/bosch_bmi160.c b/firmware/os/drivers/bosch_bmi160/bosch_bmi160.c
index 513a9c8..1b8fd68 100644
--- a/firmware/os/drivers/bosch_bmi160/bosch_bmi160.c
+++ b/firmware/os/drivers/bosch_bmi160/bosch_bmi160.c
@@ -259,6 +259,18 @@
 
 #define MAX_NUM_COMMS_EVENT_SAMPLES 15
 
+#ifndef BMI160_ACC_SAMPLES
+#define BMI160_ACC_SAMPLES 3000
+#endif
+
+#ifndef BMI160_GYRO_SAMPLES
+#define BMI160_GYRO_SAMPLES 20
+#endif
+
+#ifndef BMI160_MAG_SAMPLES
+#define BMI160_MAG_SAMPLES 600
+#endif
+
 // Default accel range is 8g
 #ifndef BMI160_ACC_RANGE_G
 #define BMI160_ACC_RANGE_G 8
@@ -749,18 +761,19 @@
 {
 #ifdef ACCEL_CAL_ENABLED
     { DEC_INFO_RATE_RAW_BIAS("Accelerometer", AccRates, SENS_TYPE_ACCEL, NUM_AXIS_THREE,
-            NANOHUB_INT_NONWAKEUP, 3000, SENS_TYPE_ACCEL_RAW, 1.0/kScale_acc,
-            SENS_TYPE_ACCEL_BIAS) },
+            NANOHUB_INT_NONWAKEUP, BMI160_ACC_SAMPLES, SENS_TYPE_ACCEL_RAW,
+            1.0/kScale_acc, SENS_TYPE_ACCEL_BIAS) },
 #else
     { DEC_INFO_RATE_RAW("Accelerometer", AccRates, SENS_TYPE_ACCEL, NUM_AXIS_THREE,
-            NANOHUB_INT_NONWAKEUP, 3000, SENS_TYPE_ACCEL_RAW, 1.0/kScale_acc) },
+            NANOHUB_INT_NONWAKEUP, BMI160_ACC_SAMPLES, SENS_TYPE_ACCEL_RAW,
+            1.0/kScale_acc) },
 #endif
     { DEC_INFO_RATE_BIAS("Gyroscope", GyrRates, SENS_TYPE_GYRO, NUM_AXIS_THREE,
-            NANOHUB_INT_NONWAKEUP, 20, SENS_TYPE_GYRO_BIAS) },
+            NANOHUB_INT_NONWAKEUP, BMI160_GYRO_SAMPLES, SENS_TYPE_GYRO_BIAS) },
 #ifdef MAG_SLAVE_PRESENT
     { DEC_INFO_RATE_RAW_BIAS("Magnetometer", MagRates, SENS_TYPE_MAG, NUM_AXIS_THREE,
-            NANOHUB_INT_NONWAKEUP, 600, SENS_TYPE_MAG_RAW, 1.0/kScale_mag,
-            SENS_TYPE_MAG_BIAS) },
+            NANOHUB_INT_NONWAKEUP, BMI160_MAG_SAMPLES, SENS_TYPE_MAG_RAW,
+            1.0/kScale_mag, SENS_TYPE_MAG_BIAS) },
 #endif
     { DEC_INFO("Step Detector", SENS_TYPE_STEP_DETECT, NUM_AXIS_EMBEDDED,
             NANOHUB_INT_NONWAKEUP, 100) },
diff --git a/firmware/os/inc/chreApi.h b/firmware/os/inc/chreApi.h
index f494236..e355ed5 100644
--- a/firmware/os/inc/chreApi.h
+++ b/firmware/os/inc/chreApi.h
@@ -20,6 +20,8 @@
 #include <stdarg.h>
 #include <stdint.h>
 
+#include "util.h"
+
 /* if va_list is passed by value it must fit in 32-bit register */
 #if !defined(SYSCALL_PARAMS_PASSED_AS_PTRS) || !defined(SYSCALL_VARARGS_PARAMS_PASSED_AS_PTRS)
 C_STATIC_ASSERT(va_list_size, sizeof(va_list) == sizeof(uint32_t));
@@ -32,12 +34,17 @@
 C_STATIC_ASSERT(uintptr_size, sizeof(uintptr_t) >= sizeof(uint32_t));
 
 //EXTERNAL API
+//level 1 indices in the CHRE table
 #define SYSCALL_CHRE_MAIN                 0
-#define SYSCALL_CHRE_LAST                 1
+#define SYSCALL_CHRE_DRIVERS              1
+#define SYSCALL_CHRE_LAST                 2 // always last. holes are allowed, but not immediately before this
 
+//level 2 indices in the CHRE.main table
 #define SYSCALL_CHRE_MAIN_API             0
-#define SYSCALL_CHRE_MAIN_LAST            1
+#define SYSCALL_CHRE_MAIN_EVENT           1
+#define SYSCALL_CHRE_MAIN_LAST            2 // always last. holes are allowed, but not immediately before this
 
+//level 3 indices in the CHRE.main.api table
 #define SYSCALL_CHRE_MAIN_API_GET_APP_ID             0 // (void) -> uint64_t
 #define SYSCALL_CHRE_MAIN_API_GET_INST_ID            1 // (void) -> uint32_t
 #define SYSCALL_CHRE_MAIN_API_LOG_OLD                2 // (enum LogLevel, const char *, uintptr_t) -> void
@@ -50,14 +57,49 @@
 #define SYSCALL_CHRE_MAIN_API_SEND_EVENT             9 // (uint32_t, void *, chreEventCompleteFunction*, uint32_t) -> bool
 #define SYSCALL_CHRE_MAIN_API_SEND_MSG              10 // (void *, uint32_t, uint32_t, chreMessageFreeFunction *) -> bool
 #define SYSCALL_CHRE_MAIN_API_SENSOR_FIND_DEFAULT   11 //
-#define SYSCALL_CHRE_MAIN_API_SENSOR_GET_INFO       12 //
+#define SYSCALL_CHRE_MAIN_API_SENSOR_GET_INFO_OLD   12 //
 #define SYSCALL_CHRE_MAIN_API_SENSOR_GET_STATUS     13 //
 #define SYSCALL_CHRE_MAIN_API_SENSOR_CONFIG         14 //
 #define SYSCALL_CHRE_MAIN_API_GET_OS_API_VERSION    15 //
 #define SYSCALL_CHRE_MAIN_API_GET_OS_VERSION        16 //
 #define SYSCALL_CHRE_MAIN_API_GET_PLATFORM_ID       17 //
 #define SYSCALL_CHRE_MAIN_API_LOG                   18 // (enum LogLevel, const char *, uintptr_t) -> void
-#define SYSCALL_CHRE_MAIN_API_LAST                  19 // always last. holes are allowed, but not immediately before this
+#define SYSCALL_CHRE_MAIN_API_SENSOR_GET_INFO       19 //
+#define SYSCALL_CHRE_MAIN_API_GET_HOST_TIME_OFFSET  20 // (void) -> int64_t
+#define SYSCALL_CHRE_MAIN_API_LAST                  21 // always last. holes are allowed, but not immediately before this
+
+//level 3 indices in the CHRE.main.event table
+#define SYSCALL_CHRE_MAIN_EVENT_SEND_EVENT           0 // (uint32_t, void *, chreEventCompleteFunction*, uint32_t) -> bool
+#define SYSCALL_CHRE_MAIN_EVENT_SEND_MSG             1 // (void *, size_t, uint32_t, uint16_t, chreMessageFreeFunction *) -> bool
+#define SYSCALL_CHRE_MAIN_EVENT_INFO_BY_APP_ID       2 // (uint64_t, struct chreNanoappInfo *) -> bool
+#define SYSCALL_CHRE_MAIN_EVENT_INFO_BY_INST_ID      3 // (uint32_t, struct chreNanoappInfo *) -> bool
+#define SYSCALL_CHRE_MAIN_EVENT_CFG_INFO             4 // (bool) -> void
+#define SYSCALL_CHRE_MAIN_EVENT_LAST                 5 // always last. holes are allowed, but not immediately before this
+
+//level 2 indices in the CHRE.drivers table
+#define SYSCALL_CHRE_DRV_GNSS             0
+#define SYSCALL_CHRE_DRV_WIFI             1
+#define SYSCALL_CHRE_DRV_WWAN             2
+#define SYSCALL_CHRE_DRV_LAST             3 // always last. holes are allowed, but not immediately before this
+
+//level 3 indices in the CHRE.drivers.gnss table
+#define SYSCALL_CHRE_DRV_GNSS_GET_CAP               0 // (void) -> uint32_t
+#define SYSCALL_CHRE_DRV_GNSS_LOC_START_ASYNC       1 // (uint32_t, uint32_t const void *) -> bool
+#define SYSCALL_CHRE_DRV_GNSS_LOC_STOP_ASYNC        2 // (const void *) -> bool
+#define SYSCALL_CHRE_DRV_GNSS_MEAS_START_ASYNC      3 // (uint32_t, const void *) -> bool
+#define SYSCALL_CHRE_DRV_GNSS_MEAS_STOP_ASYNC       4 // (const void *) -> bool
+#define SYSCALL_CHRE_DRV_GNSS_LAST                  5 // always last. holes are allowed, but not immediately before this
+
+//level 3 indices in the CHRE.drivers.wifi table
+#define SYSCALL_CHRE_DRV_WIFI_GET_CAP               0 // (void) -> uint32_t
+#define SYSCALL_CHRE_DRV_WIFI_CONF_SCAN_MON_ASYNC   1 // (bool, const void *) -> bool
+#define SYSCALL_CHRE_DRV_WIFI_REQ_SCAN_ASYNC        2 // (const struct chreWifiScanParams *, const void *) -> bool
+#define SYSCALL_CHRE_DRV_WIFI_LAST                  3 // always last. holes are allowed, but not immediately before this
+
+//level 3 indices in the CHRE.drivers.wwan table
+#define SYSCALL_CHRE_DRV_WWAN_GET_CAP               0 // (void) -> uint32_t
+#define SYSCALL_CHRE_DRV_WWAN_GET_CELL_INFO_ASYNC   1 // (const void *cookie) -> bool
+#define SYSCALL_CHRE_DRV_WWAN_LAST                  2 // always last. holes are allowed, but not immediately before this
 
 //called by os entry point to export the api
 void osChreApiExport(void);
diff --git a/firmware/os/inc/eventnums.h b/firmware/os/inc/eventnums.h
index 246587a..5746433 100644
--- a/firmware/os/inc/eventnums.h
+++ b/firmware/os/inc/eventnums.h
@@ -29,8 +29,10 @@
 #define EVT_APP_TO_HOST                  0x00000401    //app data to host. Type is struct HostHubRawPacket
 #define EVT_MARSHALLED_SENSOR_DATA       0x00000402    //marshalled event data. Type is MarshalledUserEventData
 #define EVT_RESET_REASON                 0x00000403    //reset reason to host.
-#define EVT_APP_TO_SENSOR_HAL_DATA       0x00000404    // sensor driver out of band data update to sensor hal
-#define EVT_DEBUG_LOG                    0x00007F01    // send message payload to Linux kernel log
+#define EVT_APP_TO_SENSOR_HAL_DATA       0x00000404    //sensor driver out of band data update to sensor hal
+#define EVT_APP_STARTED                  0x00000405    //sent when a app has successfully started
+#define EVT_APP_STOPPED                  0x00000406    //sent when a app has stopped
+#define EVT_DEBUG_LOG                    0x00007F01    //send message payload to Linux kernel log
 #define EVT_MASK                         0x0000FFFF
 
 // host-side events are 32-bit
@@ -54,9 +56,17 @@
 SET_PACKED_STRUCT_MODE_OFF
 
 SET_PACKED_STRUCT_MODE_ON
+struct NanohubMsgChreHdrV10 {
+    uint8_t size;
+    uint32_t appEvent;
+}ATTRIBUTE_PACKED;
+SET_PACKED_STRUCT_MODE_OFF
+
+SET_PACKED_STRUCT_MODE_ON
 struct NanohubMsgChreHdr {
     uint8_t size;
     uint32_t appEvent;
+    uint16_t endpoint;
 }ATTRIBUTE_PACKED;
 SET_PACKED_STRUCT_MODE_OFF
 
@@ -103,17 +113,18 @@
 //for all apps
 #define EVT_APP_FREE_EVT_DATA            0x000000FF    //sent to an external app when its event has been marked for freeing. Data: struct AppEventFreeData
 // this event is never enqueued; it goes directly to the app.
-// It notifies app that hav outstanding IO, that is is about to end;
+// It notifies app that have outstanding IO, that is is about to end;
 // Expected app behavior is to not send any more events to system;
 // any events sent after this point will be silently ignored by the system;
-// any outstading events will be allowed to proceed to completion. (this is SIG_STOP)
+// any outstanding events will be allowed to proceed to completion. (this is SIG_STOP)
 #define EVT_APP_STOP                     0x000000FE
 // Internal event, with task pointer as event data;
 // system ends the task unconditionally; no further checks performed (this is SIG_KILL)
 #define EVT_APP_END                      0x000000FD
+#define EVT_APP_BEGIN                    0x000000FC
 //for host comms
-#define EVT_APP_FROM_HOST                0x000000F8    //host data to an app. Type is struct HostMsgHdr
 #define EVT_APP_FROM_HOST_CHRE           0x000000F9    //host data to an app. Type is struct HostMsgHdrChre
+#define EVT_APP_FROM_HOST                0x000000F8    //host data to an app. Type is struct HostMsgHdr
 
 //for apps that use I2C
 #define EVT_APP_I2C_CBK                  0x000000F0    //data pointer points to struct I2cEventData
diff --git a/firmware/os/inc/nanohubCommand.h b/firmware/os/inc/nanohubCommand.h
index 0c4c522..408cffd 100644
--- a/firmware/os/inc/nanohubCommand.h
+++ b/firmware/os/inc/nanohubCommand.h
@@ -41,5 +41,6 @@
 
 const struct NanohubHalCommand *nanohubHalFindCommand(uint8_t msg);
 uint64_t hostGetTime(void);
+int64_t hostGetTimeDelta(void);
 
 #endif /* __NANOHUBCOMMAND_H */
diff --git a/firmware/os/inc/osApi.h b/firmware/os/inc/osApi.h
index 77cff48..03f9126 100644
--- a/firmware/os/inc/osApi.h
+++ b/firmware/os/inc/osApi.h
@@ -17,11 +17,8 @@
 #ifndef _OS_API_H_
 #define _OS_API_H_
 
-#include <stdint.h>
 #include <slab.h>
 
-#include <seos_priv.h>
-
 //EXTERNAL API
 //level 1 indices in the OS table
 #define SYSCALL_OS_MAIN                   0
@@ -127,8 +124,5 @@
 //called by os entry point to export the api
 void osApiExport(struct SlabAllocator *mainSlubAllocator);
 
-
-
-
 #endif
 
diff --git a/firmware/os/inc/sensors.h b/firmware/os/inc/sensors.h
index 7074a25..19fd3ec 100644
--- a/firmware/os/inc/sensors.h
+++ b/firmware/os/inc/sensors.h
@@ -281,6 +281,8 @@
 bool sensorCfgData(uint32_t sensorHandle, void* cfgData);
 uint32_t sensorGetCurRate(uint32_t sensorHandle);
 uint64_t sensorGetCurLatency(uint32_t sensorHandle);
+uint32_t sensorGetHwRate(uint32_t sensorHandle);
+uint64_t sensorGetHwLatency(uint32_t sensorHandle);
 uint32_t sensorGetReqRate(uint32_t sensorHandle);
 uint64_t sensorGetReqLatency(uint32_t sensorHandle);
 uint64_t sensorGetTime(void);
diff --git a/firmware/os/inc/sensors_priv.h b/firmware/os/inc/sensors_priv.h
index 956c171..90a4c99 100644
--- a/firmware/os/inc/sensors_priv.h
+++ b/firmware/os/inc/sensors_priv.h
@@ -18,6 +18,7 @@
 #define __SENSORS_PRIV_H__
 
 #include <inttypes.h>
+#include <sensors.h>
 #include <seos.h>
 
 struct Sensor {
diff --git a/firmware/os/inc/seos.h b/firmware/os/inc/seos.h
index 5f3e60f..c66d897 100644
--- a/firmware/os/inc/seos.h
+++ b/firmware/os/inc/seos.h
@@ -126,6 +126,12 @@
     void* evtData;
 };
 
+struct AppEventStartStop {
+    uint64_t appId;
+    uint32_t version;
+    uint16_t tid;
+};
+
 typedef void (*OsDeferCbkF)(void *);
 
 typedef void (*EventFreeF)(void* event);
@@ -263,11 +269,13 @@
 bool osRetainCurrentEvent(TaggedPtr *evtFreeingInfoP); //called from any apps' event handling to retain current event. Only valid for first app that tries. evtFreeingInfoP filled by call and used to free evt later
 void osFreeRetainedEvent(uint32_t evtType, void *evtData, TaggedPtr *evtFreeingInfoP);
 
-uint32_t osExtAppStopApps(uint64_t appId);
-uint32_t osExtAppEraseApps(uint64_t appId);
-uint32_t osExtAppStartApps(uint64_t appId);
+uint32_t osExtAppStopAppsByAppId(uint64_t appId);
+uint32_t osExtAppEraseAppsByAppId(uint64_t appId);
+uint32_t osExtAppStartAppsByAppId(uint64_t appId);
+uint32_t osExtAppStartAppsDelayed();
 
 bool osAppIsChre(uint16_t tid);
+uint32_t osAppChreVersion(uint16_t tid);
 
 /* Logging */
 enum LogLevel {
diff --git a/firmware/os/inc/seos_priv.h b/firmware/os/inc/seos_priv.h
index e2dd764..862d522 100644
--- a/firmware/os/inc/seos_priv.h
+++ b/firmware/os/inc/seos_priv.h
@@ -19,6 +19,7 @@
 
 #include <inttypes.h>
 #include <seos.h>
+#include <chre.h>
 
 #define NO_NODE (TaskIndex)(-1)
 #define for_each_task(listHead, task) for (task = osTaskByIdx((listHead)->next); task; task = osTaskByIdx(task->list.next))
@@ -26,6 +27,7 @@
 #define TID_TO_TASK_IDX(tid) (tid & TASK_TID_IDX_MASK)
 
 #define FL_TASK_STOPPED 1
+#define FL_TASK_ABORTED 2
 
 #define EVT_SUBSCRIBE_TO_EVT         0x00000000
 #define EVT_UNSUBSCRIBE_TO_EVT       0x00000001
@@ -108,6 +110,8 @@
     union OsApiSlabItem osApiItem;
 };
 
+typedef bool (*appMatchFunc)(const void *cookie, const struct AppHdr *);
+
 uint8_t osTaskIndex(struct Task *task);
 struct Task *osGetCurrentTask();
 struct Task *osSetCurrentTask(struct Task *task);
@@ -122,6 +126,19 @@
     return task->app && (task->app->hdr.fwFlags & FL_APP_HDR_CHRE) != 0;
 }
 
+static inline uint32_t osTaskChreVersion(const struct Task *task)
+{
+    if (osTaskIsChre(task)) {
+        // Apps loaded on 1.0 stored 0xFF in both rfu bytes
+        if (task->app->hdr.chreApiMajor == 0xFF && task->app->hdr.chreApiMinor == 0xFF)
+            return CHRE_API_VERSION_1_0;
+        else
+            return task->app->hdr.chreApiMajor << 24 | task->app->hdr.chreApiMinor << 16;
+    } else {
+        return 0;
+    }
+}
+
 static inline void osTaskMakeNewTid(struct Task *task)
 {
     task->tid = ((task->tid + TASK_TID_INCREMENT) & TASK_TID_COUNTER_MASK) |
diff --git a/firmware/os/inc/util.h b/firmware/os/inc/util.h
index 155322b..b8674f4 100644
--- a/firmware/os/inc/util.h
+++ b/firmware/os/inc/util.h
@@ -36,7 +36,7 @@
  */
 #define C_STATIC_ASSERT(name, condition) \
     static const char __attribute__((used, section(".static_assert"))) \
-    static_assert_check_ ## name [(condition) ? 0 : -1]
+    static_assert_check_ ## name [(condition) ? 0 : -1] = {}
 
 #define unlikely(x) (x)
 #define likely(x) (x)
diff --git a/firmware/os/platform/native/inc/plat/app.h b/firmware/os/platform/native/inc/plat/app.h
index 5617672..f72721d 100644
--- a/firmware/os/platform/native/inc/plat/app.h
+++ b/firmware/os/platform/native/inc/plat/app.h
@@ -18,8 +18,7 @@
 #define _PLAT_LNX_APP_H_
 
 struct PlatAppInfo {
-    int dummy;
-    //todo
+    void* data;  // dummy
 };
 
 #endif
diff --git a/firmware/os/platform/native/inc/plat/plat.h b/firmware/os/platform/native/inc/plat/plat.h
index 5cda58f..3e4eb84 100644
--- a/firmware/os/platform/native/inc/plat/plat.h
+++ b/firmware/os/platform/native/inc/plat/plat.h
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <stdint.h>
+
 #ifndef _LINUX_PLAT_H_
 #define _LINUX_PLAT_H_
 
@@ -21,10 +23,20 @@
 extern "C" {
 #endif
 
-static inline void platWake(void)
+const struct AppHdr* platGetInternalAppList(uint32_t *numAppsP);
+
+// External apps not supported
+static inline uint8_t* platGetSharedAreaInfo(uint32_t *areaSzP)
 {
+    // Note: current seos.c code assumes that it will be able to read at least
+    // 4 bytes. This will be addressed, but using this workaround for now.
+    static uint8_t appHdr[4] = {0xff, 0xff, 0xff, 0xff};
+    *areaSzP = 0;
+    return appHdr;
 }
 
+static inline void platWake(void) {}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/firmware/os/platform/native/inc/plat/wdt.h b/firmware/os/platform/native/inc/plat/wdt.h
index 430a385..b28b037 100644
--- a/firmware/os/platform/native/inc/plat/wdt.h
+++ b/firmware/os/platform/native/inc/plat/wdt.h
@@ -22,6 +22,8 @@
 #endif
 
 void wdtInit(){}
+void wdtEnableClk(){}
+void wdtDisableClk(){}
 
 #ifdef __cplusplus
 }
diff --git a/inc/chre.h b/inc/chre.h
deleted file mode 100644
index 5f45498..0000000
--- a/inc/chre.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CHRE_H_
-#define _CHRE_H_
-
-/**
- * This header file includes all the headers which combine to fully defined
- * the interface for the Context Hub Runtime Environment (CHRE).  This is the
- * environment in which a nanoapp runs.
- *
- * This interface is of interest to both implementors of CHREs and
- * authors of nanoapps.  The API documentation attempts to address concerns
- * of both.
- *
- * See individual header files for API specific, and general comments below
- * for overall platform information.
- */
-
-#include <chre/event.h>
-#include <chre/nanoapp.h>
-#include <chre/re.h>
-#include <chre/sensor.h>
-#include <chre/version.h>
-
-
-/**
- * Entry points.
- *
- * The following entry points are required to be handled by the CHRE
- * implementation, and the functions must all be implemented by nanoapps.
- * o nanoappStart function (see chre_nanoapp.h)
- * o nanoappHandleEvent function (see chre_nanoapp.h)
- * o nanoappEnd function (see chre_nanoapp.h)
- * o bss section zeroed out (prior to nanoappStart)
- * o static variables initialized (prior to nanoappStart)
- * o global C++ constructors called (prior to nanoappStart)
- * o global C++ destructors called (after nanoappEnd)
- */
-
-
-/**
- * Threading model.
- *
- * A CHRE implementation is free to chose among many different
- * threading models, including a single threaded system or a multi-threaded
- * system with preemption.  The current platform definition is agnostic to this
- * underlying choice [1].
- *
- * However, the Platform does require that all nanoapps are treated as
- * non-reentrant.  That is, any of the functions of the nanoapp, including
- * the entry points defined above and the memory freeing callbacks defined
- * below, cannot be invoked by the CHRE if a previous invocation
- * hasn't completed.  Note this means no nanoapp function can be invoked
- * from an interrupt context.
- *
- * For example, if a nanoapp is currently in nanoappHandleEvent(), the CHRE is
- * not allowed to call nanoappHandleEvent() again, or to call a memory freeing
- * callback.  Similarly, if a nanoapp is currently in a memory freeing
- * callback, the CHRE is not allowed to call nanoappHandleEvent(), or invoke
- * another memory freeing callback.
- *
- * There are two exceptions to this rule: If an invocation of chreSendEvent()
- * fails (returns 'false'), it is allowed to immediately invoke the memory
- * freeing callback passed into that function.  This is a rare case, and one
- * where otherwise a CHRE implementation is likely to leak memory. Similarly,
- * chreSendMessageToHost() is allowed to invoke the memory freeing callback
- * directly, whether it returns 'true' or 'false'.  This is because the CHRE
- * implementation may copy the message data to its own buffer, and therefore
- * wouldn't need the nanoapp-supplied buffer after chreSendMessageToHost()
- * returns.
- *
- * For a nanoapp author, this means no thought needs to be given to
- * synchronization issues with global objects, as they will, by definition,
- * only be accessed by a single thread at once.
- *
- *
- * [1] Note to CHRE implementors: A future version of the CHRE platform may
- * require multi-threading with preemption.  This is mentioned as a heads up,
- * and to allow implementors deciding between implementation approaches to
- * make the most informed choice.
- */
-
-/**
- * Notes on timing.
- *
- * Nanoapps should expect to be running on a highly constrained system, with
- * little memory and little CPU.  Any single nanoapp should expect to
- * be one of several nanoapps on the system, which also share the CPU with the
- * CHRE and possibly other services as well.
- *
- * Thus, a nanoapp needs to be efficient in its memory and CPU usage.
- * Also, as noted in the Threading Model section, a CHRE implementation may
- * be single threaded.  As a result, all methods invoked in a nanoapp
- * (like nanoappStart, nanoappHandleEvent, memory free callbacks, etc.)
- * must run "quickly".  "Quickly" is difficult to define, as there is a
- * diversity of Context Hub hardware.  For Android N, there is no firm
- * definition of "quickly", but expect this term to gain definition in
- * future releases as we get feedback from partners.
- *
- * In order to write a nanoapp that will be able to adopt to future
- * stricter notions of "quickly", all nanoapp methods should be written so
- * they execute in a small amount of time.  Some nanoapps may have the need
- * to occasionally perform a large block of calculations, which may seem
- * to violate this.  The recommended approach in this case is to
- * split up the large block of calculations into smaller batches.  In one
- * call into the nanoapp, the nanoapp can perform the first batch, and then
- * send an event (chreSendEvent()) to itself indicating which batch should be
- * done next.  This will allow the nanoapp to perform the entire calculation
- * over time, without monopolizing system resources.
- */
-
-/**
- * Floating point support.
- *
- * The C type 'float' is used in this API, and thus a CHRE implementation
- * is required to support 'float's.
- *
- * Support of the C types 'double' and 'long double' is optional for a
- * CHRE implementation.  Note that if a CHRE decides to support them, unlike
- * 'float' support, there is no requirement that this support is particularly
- * efficient.  So nanoapp authors should be aware this may be inefficient.
- *
- * If a CHRE implementation choses not to support 'double' or
- * 'long double', then the build toolchain setup provided needs to set
- * the preprocessor define CHRE_NO_DOUBLE_SUPPORT.
- */
-
-/**
- * CHRE and Nanoapp compatibility.
- *
- * The Android N release introduces the first version of this API.
- * It is anticipated that there will be a lot of feedback from
- * Android partners on this initial API.  To allow more flexibility
- * in addressing that feedback, there is no plan to assure
- * binary compatibility between the Android N and Android O CHRE
- * implementations and nanoapps.
- *
- * That is, a nanoapp built with the Android O version of this
- * API should not expect to run on a CHRE built with
- * the Android N API.  Similarly, a nanoapp build with the
- * Android N API should not expect to run on a CHRE
- * build with the Android O API.  Such a nanoapp will need to
- * recompiled with the appropriate API in order to work.
- */
-
-#endif  /* _CHRE_H_ */
-
diff --git a/inc/chre/event.h b/inc/chre/event.h
deleted file mode 100644
index 0f088bb..0000000
--- a/inc/chre/event.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CHRE_EVENT_H_
-#define _CHRE_EVENT_H_
-
-/**
- * Context Hub Runtime Environment API dealing with events and messages.
- */
-
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * The CHRE implementation is required to provide the following
- * preprocessor defines via the build system.
- *
- * CHRE_MESSAGE_TO_HOST_MAX_SIZE: The maximum size, in bytes, allowed for
- *     a message sent to chreSendMessageToHost().  This must be at least
- *     CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE.
- */
-
-#ifndef CHRE_MESSAGE_TO_HOST_MAX_SIZE
-#error CHRE_MESSAGE_TO_HOST_MAX_SIZE must be defined by the Context Hub Runtime Environment implementation
-#endif
-
-/**
- * The minimum size, in bytes, any CHRE implementation will
- * use for CHRE_MESSAGE_TO_HOST_MAX_SIZE.
- */
-#define CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE 128
-
-#if CHRE_MESSAGE_TO_HOST_MAX_SIZE < CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE
-#error CHRE_MESSAGE_TO_HOST_MAX_SIZE is too small.
-#endif
-
-/**
- * The lowest numerical value legal for a user-defined event.
- *
- * The system reserves all event values from 0 to 0x7FFF, inclusive.
- * User events may use any value in the range 0x8000 to 0xFFFF, inclusive.
- *
- * Note that the same event values might be used by different nanoapps
- * for different meanings.  This is not a concern, as these values only
- * have meaning when paired with the originating nanoapp.
- */
-#define CHRE_EVENT_FIRST_USER_VALUE  UINT16_C(0x8000)
-
-/**
- * nanoappHandleEvent argument: struct chreMessageFromHostData
- *
- * The format of the 'message' part of this structure is left undefined,
- * and it's up to the nanoapp and host to have an established protocol
- * beforehand.
- */
-#define CHRE_EVENT_MESSAGE_FROM_HOST  UINT16_C(0x0001)
-
-/**
- * nanoappHandleEvent argument: 'cookie' given to chreTimerSet() method.
- *
- * Indicates that a timer has elapsed, in accordance with how chreTimerSet() was
- * invoked.
- */
-#define CHRE_EVENT_TIMER  UINT16_C(0x0002)
-
-/**
- * First possible value for CHRE_EVENT_SENSOR events.
- *
- * This allows us to separately define our CHRE_EVENT_SENSOR_* events in
- * chre_sensor.h, without fear of collision with other event values.
- */
-#define CHRE_EVENT_SENSOR_FIRST_EVENT  UINT16_C(0x0100)
-
-/**
- * Last possible value for CHRE_EVENT_SENSOR events.
- *
- * This allows us to separately define our CHRE_EVENT_SENSOR_* events in
- * chre_sensor.h, without fear of collision with other event values.
- */
-#define CHRE_EVENT_SENSOR_LAST_EVENT  UINT16_C(0x02FF)
-
-/**
- * First in a range of values dedicated for internal CHRE implementation usage.
- *
- * If a CHRE wishes to use events internally, any values within this range
- * are assured not to be taken by future CHRE API additions.
- */
-#define CHRE_EVENT_INTERNAL_FIRST_EVENT  UINT16_C(0x7E00)
-
-/**
- * Last in a range of values dedicated for internal CHRE implementation usage.
- *
- * If a CHRE wishes to use events internally, any values within this range
- * are assured not to be taken by future CHRE API additions.
- */
-#define CHRE_EVENT_INTERNAL_LAST_EVENT  UINT16_C(0x7FFF)
-
-
-/**
- * CHRE_EVENT_MESSAGE_FROM_HOST
- */
-struct chreMessageFromHostData {
-    /**
-     * Message type (NOTE: not implemented correctly in the Android N release).
-     *
-     * In future releases, this will be a message type provided by the host.
-     */
-    uint32_t reservedMessageType;
-
-    /**
-     * The size, in bytes of the following 'message'.
-     *
-     * This can be 0.
-     */
-    uint32_t messageSize;
-
-    /**
-     * The message from the host.
-     *
-     * These contents are of a format that the host and nanoapp must have
-     * established beforehand.
-     *
-     * This data is 'messageSize' bytes in length.  Note that if 'messageSize'
-     * is 0, this might be NULL.
-     */
-    const void *message;
-};
-
-/**
- * Callback which frees data associated with an event.
- *
- * This callback is (optionally) provided to the chreSendEvent() method as
- * a means for freeing the event data and performing any other cleanup
- * necessary when the event is completed.  When this callback is invoked,
- * 'eventData' is no longer needed and can be released.
- *
- * @param eventType  The 'eventType' argument from chreSendEvent().
- * @param eventData  The 'eventData' argument from chreSendEvent().
- *
- * @see chreSendEvent
- */
-typedef void (chreEventCompleteFunction)(uint16_t eventType, void *eventData);
-
-/**
- * Callback which frees a message.
- *
- * This callback is (optionally) provided to the chreSendMessageToHost() method
- * as a means for freeing the message.  When this callback is invoked,
- * 'message' is no longer needed and can be released.  Note that this in
- * no way assures that said message did or did not make it to the host, simply
- * that this memory is no longer needed.
- *
- * @param message  The 'message' argument from chreSendMessageToHost().
- * @param messageSize  The 'messageSize' argument from chreSendMessageToHost().
- *
- * @see chreSendMessageToHost
- */
-typedef void (chreMessageFreeFunction)(void *message, size_t messageSize);
-
-
-
-/**
- * Enqueue an event to be sent to another nanoapp.
- *
- * Note: This version of the API does not give an easy means to discover
- * another nanoapp's instance ID.  For now, events will need to be sent to/from
- * the host to initially discover these IDs.
- *
- * @param eventType  This is a user-defined event type, of at least the
- *     value CHRE_EVENT_FIRST_USER_VALUE.  It is illegal to attempt to use any
- *     of the CHRE_EVENT_* values reserved for the CHRE.
- * @param eventData  A pointer value that will be understood by the receiving
- *     app.  Note that NULL is perfectly acceptable.  It also is not required
- *     that this be a valid pointer, although if this nanoapp is intended to
- *     work on arbitrary CHRE implementations, then the size of a
- *     pointer cannot be assumed to be a certain size.  Note that the caller
- *     no longer owns this memory after the call.
- * @param freeCallback  A pointer to a callback function.  After the lifetime
- *     of 'eventData' is over (either through successful delivery or the event
- *     being dropped), this callback will be invoked.  This argument is allowed
- *     to be NULL, in which case no callback will be invoked.
- * @param targetInstanceId  The ID of the instance we're delivering this event
- *     to.  Note that this is allowed to be our own instance.
- * @returns true if the event was enqueued, false otherwise.  Note that even
- *     if this method returns 'false', the 'freeCallback' will be invoked,
- *     if non-NULL.  Note in the 'false' case, the 'freeCallback' may be
- *     invoked directly from within chreSendEvent(), so it's necessary
- *     for nanoapp authors to avoid possible recursion with this.
- *
- * @see chreEventDataFreeFunction
- */
-bool chreSendEvent(uint16_t eventType, void *eventData,
-                   chreEventCompleteFunction *freeCallback,
-                   uint32_t targetInstanceId);
-
-/**
- * Send a message to the host.
- *
- * This message is by definition arbitrarily defined.  Since we're not
- * just a passing a pointer to memory around the system, but need to copy
- * this into various buffers to send it to the host, the CHRE
- * implementation cannot be asked to support an arbitrarily large message
- * size.  As a result, we have the CHRE implementation define
- * CHRE_MESSAGE_TO_HOST_MAX_SIZE.
- *
- * CHRE_MESSAGE_TO_HOST_MAX_SIZE is not given a value by the Platform API.  The
- * Platform API does define CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE, and requires
- * that CHRE_MESSAGE_TO_HOST_MAX_SIZE is at least that value.
- *
- * As a result, if your message sizes are all less than
- * CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE, then you have no concerns on any
- * CHRE implementation.  If your message sizes are larger, you'll need to
- * come up with a strategy for splitting your message across several calls
- * to this method.  As long as that strategy works for
- * CHRE_MESSAGE_TO_HOST_MINIMUM_MAX_SIZE, it will work across all CHRE
- * implementations (although on some implementations less calls to this
- * method may be necessary).
- *
- * @param message  Pointer to a block of memory to send to the host.
- *     NULL is acceptable only if messageSize is 0.  If non-NULL, this
- *     must be a legitimate pointer (that is, unlike chreSendEvent(), a small
- *     integral value cannot be cast to a pointer for this).  Note that the
- *     caller no longer owns this memory after the call.
- * @param messageSize  The size, in bytes, of the given message.
- *     This cannot exceed CHRE_MESSAGE_TO_HOST_MAX_SIZE.
- * @param reservedMessageType  Message type sent to the app on the host.
- *     NOTE: In the N release, there is a bug in some HAL implementations
- *     where this data does not make it to the app running on the host.
- *     Nanoapps cannot trust this across all platforms for N, but that
- *     will be fixed in O.
- * @param freeCallback  A pointer to a callback function.  After the lifetime
- *     of 'message' is over (which does not assure that 'message' made it to
- *     the host, just that the transport layer no longer needs this memory),
- *     this callback will be invoked.  This argument is allowed
- *     to be NULL, in which case no callback will be invoked.
- * @returns true if the message was accepted for transmission, false otherwise.
- *     Note that even if this method returns 'false', the 'freeCallback' will
- *     be invoked, if non-NULL.  In either case, the 'freeCallback' may be
- *     invoked directly from within chreSendMessageToHost(), so it's necessary
- *     for nanoapp authors to avoid possible recursion with this.
- *
- * @see chreMessageFreeFunction
- */
-bool chreSendMessageToHost(void *message, uint32_t messageSize,
-                           uint32_t reservedMessageType,
-                           chreMessageFreeFunction *freeCallback);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  /* _CHRE_EVENT_H_ */
-
diff --git a/inc/chre/nanoapp.h b/inc/chre/nanoapp.h
deleted file mode 100644
index 78a8acc..0000000
--- a/inc/chre/nanoapp.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CHRE_NANOAPP_H_
-#define _CHRE_NANOAPP_H_
-
-/**
- * Methods in the Context Hub Runtime Environment which must be implemented
- * by the nanoapp.
- */
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Method invoked by the CHRE when loading the nanoapp.
- *
- * Every CHRE method is legal to call from this method.
- *
- * @returns  'true' if the nanoapp successfully started.  'false' if the nanoapp
- *     failed to properly initialize itself (for example, could not obtain
- *     sufficient memory from the heap).  If this method returns 'false', the
- *     nanoapp will be unloaded by the CHRE (and nanoappEnd will
- *     _not_ be invoked in that case).
- * @see nanoappEnd
- */
-bool nanoappStart(void);
-
-/**
- * Method invoked by the CHRE when there is an event for this nanoapp.
- *
- * Every CHRE method is legal to call from this method.
- *
- * @param senderInstanceId  The Instance ID for the source of this event.
- *     Note that this may be CHRE_INSTANCE_ID, indicating that the event
- *     was generated by the CHRE.
- * @param eventType  The event type.  This might be one of the CHRE_EVENT_*
- *     types defined in this API.  But it might also be a user-defined event.
- * @param eventData  The associated data, if any, for this specific type of
- *     event.  From the nanoapp's perspective, this eventData's lifetime ends
- *     when this method returns, and thus any data the nanoapp wishes to
- *     retain must be copied.  Note that interpretation of event data is
- *     given by the event type, and for some events may not be a valid
- *     pointer.  See documentation of the specific CHRE_EVENT_* types for how to
- *     interpret this data for those.  Note that for user events, you will
- *     need to establish what this data means.
- */
-void nanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
-                        const void* eventData);
-
-/**
- * Method invoked by the CHRE when unloading the nanoapp.
- *
- * It is not valid to attempt to send events or messages, or to invoke functions
- * which will generate events to this app, within the nanoapp implementation of
- * this function.  That means it is illegal for the nanoapp invoke any of the
- * following:
- * - chreSendEvent()
- * - chreSendMessageToHost()
- * - chreSensorConfigure()
- * - chreSensorConfigureModeOnly()
- * - chreTimerSet()
- *
- * @see nanoappStart
- */
-void nanoappEnd(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  /* _CHRE_NANOAPP_H_ */
diff --git a/inc/chre/re.h b/inc/chre/re.h
deleted file mode 100644
index 31b0ed7..0000000
--- a/inc/chre/re.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CHRE_RE_H_
-#define _CHRE_RE_H_
-
-/**
- * Some of the core Runtime Environment utilities of the Context Hub
- * Runtime Environment.
- *
- * This includes functions for memory allocation, logging, and timers.
- */
-
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * The instance ID for the CHRE.
- *
- * This ID is used to identify events generated by the CHRE (as
- * opposed to events generated by another nanoapp).
- */
-#define CHRE_INSTANCE_ID  UINT32_C(0)
-
-/**
- * A timer ID representing an invalid timer.
- *
- * This valid is returned by chreTimerSet() if a timer cannot be
- * started.
- */
-#define CHRE_TIMER_INVALID  UINT32_C(-1)
-
-
-
-/**
- * Logging levels used to indicate severity level of logging messages.
- *
- * CHRE_LOG_ERROR: Something fatal has happened, i.e. something that will have
- *     user-visible consequences and won't be recoverable without explicitly
- *     deleting some data, uninstalling applications, wiping the data
- *     partitions or reflashing the entire phone (or worse).
- * CHRE_LOG_WARN: Something that will have user-visible consequences but is
- *     likely to be recoverable without data loss by performing some explicit
- *     action, ranging from waiting or restarting an app all the way to
- *     re-downloading a new version of an application or rebooting the device.
- * CHRE_LOG_INFO: Something interesting to most people happened, i.e. when a
- *     situation is detected that is likely to have widespread impact, though
- *     isn't necessarily an error.
- * CHRE_LOG_DEBUG: Used to further note what is happening on the device that
- *     could be relevant to investigate and debug unexpected behaviors. You
- *     should log only what is needed to gather enough information about what
- *     is going on about your component.
- *
- * There is currently no API to turn on/off logging by level, but we anticipate
- * adding such in future releases.
- *
- * @see chreLog
- */
-enum chreLogLevel {
-    CHRE_LOG_ERROR,
-    CHRE_LOG_WARN,
-    CHRE_LOG_INFO,
-    CHRE_LOG_DEBUG
-};
-
-
-
-/**
- * Get the application ID.
- *
- * The application ID is set by the loader of the nanoapp.  This is not
- * assured to be unique among all nanoapps running in the system.
- *
- * @returns The application ID.
- */
-uint64_t chreGetAppId(void);
-
-/**
- * Get the instance ID.
- *
- * The instance ID is the CHRE handle to this nanoapp.  This is assured
- * to be unique among all nanoapps running in the system, and to be
- * different from the CHRE_INSTANCE_ID.  This is the ID used to communicate
- * between nanoapps.
- *
- * @returns The instance ID
- */
-uint32_t chreGetInstanceId(void);
-
-/**
- * A method for logging information about the system.
- *
- * A log entry can have a variety of levels (@see LogLevel).  This function
- * allows a variable number of arguments, in a printf-style format.
- *
- * A nanoapp needs to be able to rely upon consistent printf format
- * recognition across any platform, and thus we establish formats which
- * are required to be handled by every CHRE implementation.  Some of the
- * integral formats may seem obscure, but this API heavily uses types like
- * uint32_t and uint16_t.  The platform independent macros for those printf
- * formats, like PRId32 or PRIx16, end up using some of these "obscure"
- * formats on some platforms, and thus are required.
- *
- * For the initial N release, our emphasis is on correctly getting information
- * into the log, and minimizing the requirements for CHRE implementations
- * beyond that.  We're not as concerned about how the information is visually
- * displayed.  As a result, there are a number of format sub-specifiers which
- * are "OPTIONAL" for the N implementation.  "OPTIONAL" in this context means
- * that a CHRE implementation is allowed to essentially ignore the specifier,
- * but it must understand the specifier enough in order to properly skip it.
- *
- * For a nanoapp author, an OPTIONAL format means you might not get exactly
- * what you want on every CHRE implementation, but you will always get
- * something sane.
- *
- * To be clearer, here's an example with the OPTIONAL 0-padding for integers
- * for different hypothetical CHRE implementations.
- * Compliant, chose to implement OPTIONAL format:
- *   chreLog(level, "%04x", 20) ==> "0014"
- * Compliant, chose not to implement OPTIONAL format:
- *   chreLog(level, "%04x", 20) ==> "14"
- * Non-compliant, discarded format because the '0' was assumed to be incorrect:
- *   chreLog(level, "%04x", 20) ==> ""
- *
- * Note that some of the OPTIONAL specifiers will probably become
- * required in future APIs.
- *
- * We also have NOT_SUPPORTED specifiers.  Nanoapp authors should not use any
- * NOT_SUPPORTED specifiers, as unexpected things could happen on any given
- * CHRE implementation.  A CHRE implementation is allowed to support this
- * (for example, when using shared code which already supports this), but
- * nanoapp authors need to avoid these.
- *
- *
- * Unless specifically noted as OPTIONAL or NOT_SUPPORTED, format
- * (sub-)specifiers listed below are required.
- *
- * OPTIONAL format sub-specifiers:
- * - '-' (left-justify within the given field width)
- * - '+' (preceed the result with a '+' sign if it is positive)
- * - ' ' (preceed the result with a blank space if no sign is going to be
- *        output)
- * - '#' (For 'o', 'x' or 'X', preceed output with "0", "0x" or "0X",
- *        respectively.  For floating point, unconditionally output a decimal
- *        point.)
- * - '0' (left pad the number with zeroes instead of spaces when <width>
- *        needs padding)
- * - <width> (A number representing the minimum number of characters to be
- *            output, left-padding with blank spaces if needed to meet the
- *            minimum)
- * - '.'<precision> (A number which has different meaning depending on context.)
- *    - Integer context: Minimum number of digits to output, padding with
- *          leading zeros if needed to meet the minimum.
- *    - 'f' context: Number of digits to output after the decimal
- *          point (to the right of it).
- *    - 's' context: Maximum number of characters to output.
- *
- * Integral format specifiers:
- * - 'd' (signed)
- * - 'u' (unsigned)
- * - 'o' (octal)
- * - 'x' (hexadecimal, lower case)
- * - 'X' (hexadecimal, upper case)
- *
- * Integral format sub-specifiers (as prefixes to an above integral format):
- * - 'hh' (char)
- * - 'h' (short)
- * - 'l' (long)
- * - 'll' (long long)
- * - 'z' (size_t)
- * - 't' (ptrdiff_t)
- *
- * Other format specifiers:
- * - 'f' (floating point)
- * - 'c' (character)
- * - 's' (character string, terminated by '\0')
- * - 'p' (pointer)
- * - '%' (escaping the percent sign (i.e. "%%" becomes "%"))
- *
- * NOT_SUPPORTED specifiers:
- * - 'n' (output nothing, but fill in a given pointer with the number
- *        of characters written so far)
- * - '*' (indicates that the width/precision value comes from one of the
- *        arguments to the function)
- * - 'e', 'E' (scientific notation output)
- * - 'g', 'G' (Shortest floating point representation)
- *
- * @param level  The severity level for this message.
- * @param formatStr  Either the entirety of the message, or a printf-style
- *     format string of the format documented above.
- * @param ...  A variable number of arguments necessary for the given
- *     'formatStr' (there may be no additional arguments for some 'formatStr's).
- */
-void chreLog(enum chreLogLevel level, const char *formatStr, ...);
-
-/**
- * Get the system time.
- *
- * This returns a time in nanoseconds in reference to some arbitrary
- * time in the past.  This method is only useful for determining timing
- * between events on the system, and is not useful for determining
- * any sort of absolute time.
- *
- * This value must always increase (and must never roll over).  This
- * value has no meaning across CHRE reboots.
- *
- * @returns The system time, in nanoseconds.
- */
-uint64_t chreGetTime(void);
-
-/**
- * Set a timer.
- *
- * When the timer fires, nanoappHandleEvent will be invoked with
- * CHRE_EVENT_TIMER and with the given 'cookie'.
- *
- * A CHRE implementation is required to provide at least 32
- * timers.  However, there's no assurance there will be any available
- * for any given nanoapp (if it's loaded late, etc).
- *
- * @param duration  Time, in nanoseconds, before the timer fires.
- * @param cookie  Argument that will be sent to nanoappHandleEvent upon the
- *     timer firing.  This is allowed to be NULL and does not need to be
- *     a valid pointer (assuming the nanoappHandleEvent code is expecting such).
- * @param oneShot  If true, the timer will just fire once.  If false, the
- *     timer will continue to refire every 'duration', until this timer is
- *     canceled (@see chreTimerCancel).
- *
- * @returns  The timer ID.  If the system is unable to set a timer
- *     (no more available timers, etc.) then CHRE_TIMER_INVALID will
- *     be returned.
- *
- * @see nanoappHandleEvent
- */
-uint32_t chreTimerSet(uint64_t duration, const void* cookie, bool oneShot);
-
-/**
- * Cancel a timer.
- *
- * After this method returns, the CHRE assures there will be no more
- * events sent from this timer, and any enqueued events from this timer
- * will need to be evicted from the queue by the CHRE.
- *
- * @param timerId  A timer ID obtained by this nanoapp via chreTimerSet().
- * @returns true if the timer was cancelled, false otherwise.  We may
- *     fail to cancel the timer if it's a one shot which (just) fired,
- *     or if the given timer ID is not owned by the calling app.
- */
-bool chreTimerCancel(uint32_t timerId);
-
-/**
- * Terminate this nanoapp.
- *
- * This takes effect immediately.
- *
- * The CHRE will no longer execute this nanoapp.  The CHRE will not invoke
- * nanoappEnd(), nor will it call any memory free callbacks in the nanoapp.
- *
- * The CHRE will unload/evict this nanoapp's code.
- *
- * @param abortCode  A value indicating the reason for aborting.  (Note that
- *    in this version of the API, there is no way for anyone to access this
- *    code, but future APIs may expose it.)
- * @returns Never.  This method does not return, as the CHRE stops nanoapp
- *    execution immediately.
- */
-void chreAbort(uint32_t abortCode);
-
-/**
- * Allocate a given number of bytes from the system heap.
- *
- * The nanoapp is required to free this memory via chreHeapFree() prior to
- * the nanoapp ending.
- *
- * While the CHRE implementation is required to free up heap resources of
- * a nanoapp when unloading it, future requirements and tests focused on
- * nanoapps themselves may check for memory leaks, and will require nanoapps
- * to properly manage their heap resources.
- *
- * @param bytes  The number of bytes requested.
- * @returns  A pointer to 'bytes' contiguous bytes of heap memory, or NULL
- *     if the allocation could not be performed.  This pointer must be suitably
- *     aligned for any kind of variable.
- *
- * @see chreHeapFree.
- */
-void* chreHeapAlloc(uint32_t bytes);
-
-/**
- * Free a heap allocation.
- *
- * This allocation must be from a value returned from a chreHeapAlloc() call
- * made by this nanoapp.  In other words, it is illegal to free memory
- * allocated by another nanoapp (or the CHRE).
- *
- * @param ptr  'ptr' is required to be a value returned from chreHeapAlloc().
- *     Note that since chreHeapAlloc can return NULL, CHRE
- *     implementations must safely handle 'ptr' being NULL.
- *
- * @see chreHeapAlloc.
- */
-void chreHeapFree(void* ptr);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  /* _CHRE_RE_H_ */
-
diff --git a/inc/chre/sensor.h b/inc/chre/sensor.h
deleted file mode 100644
index 9e74336..0000000
--- a/inc/chre/sensor.h
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CHRE_SENSOR_H_
-#define _CHRE_SENSOR_H_
-
-/**
- * API dealing with sensor interaction in the Context Hub Runtime
- * Environment.
- *
- * This includes the definition of our sensor types and the ability to
- * configure them for receiving events.
- */
-
-#include <stdbool.h>
-#include <stdint.h>
-
-// For CHRE_EVENT_SENSOR_FIRST_EVENT and CHRE_EVENT_SENSOR_LAST_EVENT
-#include <chre/event.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * The CHRE_SENSOR_TYPE_* defines are the sensor types supported.
- *
- * Unless otherwise noted, each of these sensor types is based off of a
- * corresponding sensor type in the Android API's sensors.h interface.
- * For a given CHRE_SENSOR_TYPE_FOO, it corresponds to the SENSOR_TYPE_FOO in
- * hardware/libhardware/include/hardware/sensors.h of the Android code base.
- *
- * Unless otherwise noted below, a CHRE_SENSOR_TYPE_FOO should be assumed
- * to work the same as the Android SENSOR_TYPE_FOO, as documented in the
- * sensors.h documentation and as detailed within the Android Compatibility
- * Definition Document.
- *
- * Note that every sensor will generate CHRE_EVENT_SENSOR_SAMPLING_CHANGE
- * events, so it is not listed with each individual sensor.
- */
-
-/**
- * Accelerometer.
- *
- * Generates: CHRE_EVENT_SENSOR_ACCELEROMETER_DATA
- *
- * @see CHRE_EVENT_SENSOR_ACCELEROMETER_DATA
- */
-#define CHRE_SENSOR_TYPE_ACCELEROMETER  UINT8_C(1)
-
-/**
- * Instantaneous motion detection.
- *
- * Generates: CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA
- *
- * This is a one-shot sensor.
- *
- * This does not have a direct analogy within sensors.h.  This is similar
- * to SENSOR_TYPE_MOTION_DETECT, but this triggers instantly upon any
- * motion, instead of waiting for a period of continuous motion.
- */
-#define CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT  UINT8_C(2)
-
-/**
- * Stationary detection.
- *
- * Generates: CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA
- *
- * This is a one-shot sensor.
- */
-#define CHRE_SENSOR_TYPE_STATIONARY_DETECT  UINT8_C(3)
-
-/**
- * Gyroscope.
- *
- * Generates: CHRE_EVENT_SENSOR_GYROSCOPE_DATA and
- *     CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO
- *
- * Note that the GYROSCOPE_DATA is always the calibrated data, and not
- * raw data.
- */
-#define CHRE_SENSOR_TYPE_GYROSCOPE  UINT8_C(6)
-
-/**
- * Magnetometer.
- *
- * Generates: CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA and
- *     CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO
- *
- * Note that the GEOMAGNETIC_FIELD_DATA is always the calibrated data, and not
- * raw data.
- */
-#define CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD  UINT8_C(8)
-
-/**
- * Barometric pressure sensor.
- *
- * Generates: CHRE_EVENT_SENSOR_PRESSURE_DATA
- */
-#define CHRE_SENSOR_TYPE_PRESSURE  UINT8_C(10)
-
-/**
- * Ambient light sensor.
- *
- * Generates: CHRE_EVENT_SENSOR_LIGHT_DATA
- */
-#define CHRE_SENSOR_TYPE_LIGHT  UINT8_C(12)
-
-/**
- * Proximity detection.
- *
- * Generates: CHRE_EVENT_SENSOR_PROXIMITY_DATA
- *
- * This is an on-change sensor.
- */
-#define CHRE_SENSOR_TYPE_PROXIMITY  UINT8_C(13)
-
-/**
- * Base value for all of the data events for sensors.
- *
- * The value for a data event FOO is
- * CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_FOO
- *
- * This allows for easy mapping, and also explains why there are gaps
- * in our values since we don't have all possible sensor types assigned.
- */
-#define CHRE_EVENT_SENSOR_DATA_EVENT_BASE  CHRE_EVENT_SENSOR_FIRST_EVENT
-
-/**
- * nanoappHandleEvent argument: struct chreSensorThreeAxisData
- *
- * The data can be interpreted using the 'x', 'y', and 'z' fields within
- * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
- *
- * All values are in SI units (m/s^2) and measure the acceleration of the
- * device minus the force of gravity.
- */
-#define CHRE_EVENT_SENSOR_ACCELEROMETER_DATA \
-    (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_ACCELEROMETER)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorOccurrenceData
- *
- * Since this is a one-shot sensor, after this event is delivered to the
- * nanoapp, the sensor automatically goes into DONE mode.  Sensors of this
- * type must be configured with a ONE_SHOT mode.
- */
-#define CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA \
-    (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorOccurrenceData
- *
- * Since this is a one-shot sensor, after this event is delivered to the
- * nanoapp, the sensor automatically goes into DONE mode.  Sensors of this
- * type must be configured with a ONE_SHOT mode.
- */
-#define CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA \
-    (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_STATIONARY_DETECT)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorThreeAxisData
- *
- * The data can be interpreted using the 'x', 'y', and 'z' fields within
- * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
- *
- * All values are in radians/second and measure the rate of rotation
- * around the X, Y and Z axis.
- */
-#define CHRE_EVENT_SENSOR_GYROSCOPE_DATA \
-    (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_GYROSCOPE)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorThreeAxisData
- *
- * The data can be interpreted using the 'x', 'y', and 'z' fields within
- * 'readings', or by the 3D array 'v' (v[0] == x; v[1] == y; v[2] == z).
- *
- * All values are in micro-Tesla (uT) and measure the geomagnetic
- * field in the X, Y and Z axis.
- */
-#define CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA \
-    (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorFloatData
- *
- * The data can be interpreted using the 'pressure' field within 'readings'.
- * This value is in hectopascals (hPa).
- */
-#define CHRE_EVENT_SENSOR_PRESSURE_DATA \
-    (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_PRESSURE)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorFloatData
- *
- * The data can be interpreted using the 'light' field within 'readings'.
- * This value is in SI lux units.
- */
-#define CHRE_EVENT_SENSOR_LIGHT_DATA \
-    (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_LIGHT)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorByteData
- *
- * The data is interpreted from the following fields in 'readings':
- * o 'isNear': If set to 1, we are nearby (on the order of centimeters);
- *       if set to 0, we are far.
- * o 'invalid': If set to 1, this is not a valid reading of this data.
- *
- * As an on-change sensor, there is an event generated upon configuring
- * this sensor.  This is when we might get an 'invalid' reading.  Thus,
- * this field must be checked on the first event before interpreting 'isNear'.
- */
-#define CHRE_EVENT_SENSOR_PROXIMITY_DATA \
-    (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_PROXIMITY)
-
-
-/**
- * First value for sensor events which are not data from the sensor.
- *
- * Unlike the data event values, these other event values don't have any
- * mapping to sensor types.
- */
-#define CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE \
-    (CHRE_EVENT_SENSOR_FIRST_EVENT + 0x0100)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorSamplingStatusEvent
- *
- * Indicates that the interval and/or the latency which this sensor is
- * sampling at has changed.
- */
-#define CHRE_EVENT_SENSOR_SAMPLING_CHANGE \
-    (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 0)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorThreeAxisData
- *
- * The data can be interpreted using the 'x_bias', 'y_bias', and 'z_bias'
- * field within 'readings', or by the 3D array 'bias' (bias[0] == x_bias;
- * bias[1] == y_bias; bias[2] == z_bias).
- *
- * All values are in radians/second and measure the rate of rotation
- * around the X, Y and Z axis.
- */
-#define CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO \
-    (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 1)
-
-/**
- * nanoappHandleEvent argument: struct chreSensorThreeAxisData
- *
- * The data can be interpreted using the 'x_bias', 'y_bias', and 'z_bias'
- * field within 'readings', or by the 3D array 'bias' (bias[0] == x_bias;
- * bias[1] == y_bias; bias[2] == z_bias).
- *
- * All values are in micro-Tesla (uT) and measure the geomagnetic
- * field in the X, Y and Z axis.
- */
-#define CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO \
-    (CHRE_EVENT_SENSOR_OTHER_EVENTS_BASE + 2)
-
-
-#if CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO > CHRE_EVENT_SENSOR_LAST_EVENT
-#error Too many sensor events.
-#endif
-
-
-/**
- * Value indicating we want the smallest possible latency for a sensor.
- *
- * This literally translates to 0 nanoseconds for the chreSensorConfigure()
- * argument.  While we won't get exactly 0 nanoseconds, the CHRE will
- * queue up this event As Soon As Possible.
- */
-#define CHRE_SENSOR_LATENCY_ASAP  UINT64_C(0)
-
-/**
- * Special value indicating non-importance of the interval.
- *
- * @see chreSensorConfigure
- * @see chreSensorSamplingStatus
- */
-#define CHRE_SENSOR_INTERVAL_DEFAULT  UINT64_C(-1)
-
-/**
- * Special value indicating non-importance of the latency.
- *
- * @see chreSensorConfigure
- * @see chreSensorSamplingStatus
- */
-#define CHRE_SENSOR_LATENCY_DEFAULT  UINT64_C(-1)
-
-
-// This is used to define elements of enum chreSensorConfigureMode.
-#define CHRE_SENSOR_CONFIGURE_RAW_POWER_ON           (1 << 0)
-
-// This is used to define elements of enum chreSensorConfigureMode.
-#define CHRE_SENSOR_CONFIGURE_RAW_REPORT_CONTINUOUS  (1 << 1)
-
-// This is used to define elements of enum chreSensorConfigureMode.
-#define CHRE_SENSOR_CONFIGURE_RAW_REPORT_ONE_SHOT    (2 << 1)
-
-
-
-/**
- * Modes we can configure a sensor to use.
- *
- * Our mode will affect not only how/if we receive events, but
- * also whether or not the sensor will be powered on our behalf.
- *
- * @see chreSensorConfigure
- */
-enum chreSensorConfigureMode {
-    /**
-     * Get events from the sensor.
-     *
-     * Power: Turn on if not already on.
-     * Reporting: Continuous.  Send each new event as it comes (subject to
-     *     batching and latency).
-     */
-    CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS =
-        (CHRE_SENSOR_CONFIGURE_RAW_POWER_ON |
-         CHRE_SENSOR_CONFIGURE_RAW_REPORT_CONTINUOUS),
-
-    /**
-     * Get a single event from the sensor and then become DONE.
-     *
-     * Once the event is sent, the sensor automatically
-     * changes to CHRE_SENSOR_CONFIGURE_MODE_DONE mode.
-     *
-     * Power: Turn on if not already on.
-     * Reporting: One shot.  Send the next event and then be DONE.
-     */
-    CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT =
-        (CHRE_SENSOR_CONFIGURE_RAW_POWER_ON |
-         CHRE_SENSOR_CONFIGURE_RAW_REPORT_ONE_SHOT),
-
-    /**
-     * Get events from a sensor that are generated for other apps.
-     *
-     * This is considered passive because the sensor will not be powered
-     * on for the sake of our nanoapp.  If and only if another app in
-     * the system has requested this sensor power on will we get events.
-     *
-     * This can be useful for something which is interested in seeing data,
-     * but not interested enough to be responsible for powering on the sensor.
-     *
-     * Power: Do not power the sensor on our behalf.
-     * Reporting: Continuous.  Send each event as it comes.
-     */
-    CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_CONTINUOUS =
-        CHRE_SENSOR_CONFIGURE_RAW_REPORT_CONTINUOUS,
-
-    /**
-     * Get a single event from a sensor that is generated for other apps.
-     *
-     * See CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_CONTINUOUS for more details
-     * on what be "passive" means.
-     *
-     * Power: Do not power the sensor on our behalf.
-     * Reporting: One shot.  Send only the next event and then be DONE.
-     */
-    CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_ONE_SHOT =
-        CHRE_SENSOR_CONFIGURE_RAW_REPORT_ONE_SHOT,
-
-    /**
-     * Indicate we are done using this sensor and no longer interested in it.
-     *
-     * See chreSensorConfigure for more details on expressing interest or
-     * lack of interest in a sensor.
-     *
-     * Power: Do not power the sensor on our behalf.
-     * Reporting: None.
-     */
-    CHRE_SENSOR_CONFIGURE_MODE_DONE = 0,
-};
-
-/**
- * A structure containing information about a Sensor.
- *
- * See documentation of individual fields below.
- */
-struct chreSensorInfo {
-    /**
-     * The name of the sensor.
-     *
-     * A text name, useful for logging/debugging, describing the Sensor.  This
-     * is not assured to be unique (i.e. there could be multiple sensors with
-     * the name "Temperature").
-     *
-     * CHRE implementations may not set this as NULL.  An empty
-     * string, while discouraged, is legal.
-     */
-    const char *sensorName;
-
-    /**
-     * One of the CHRE_SENSOR_TYPE_* defines above.
-     */
-    uint8_t sensorType;
-
-    /**
-     * Flag indicating if this sensor is on-change.
-     *
-     * An on-change sensor only generates events when underlying state
-     * changes.  This has the same meaning as on-change does in the Android
-     * Sensors HAL.  See sensors.h for much more details.
-     *
-     * A value of 1 indicates this is on-change.  0 indicates this is not
-     * on-change.
-     */
-    uint8_t isOnChange  : 1;
-
-    /**
-     * Flag indicating if this sensor is one-shot.
-     *
-     * A one-shot sensor only triggers a single event, and then automatically
-     * disables itself.
-     *
-     * A value of 1 indicates this is on-change.  0 indicates this is not
-     * on-change.
-     */
-    uint8_t isOneShot   : 1;
-    uint8_t unusedFlags : 6;
-};
-
-/**
- * Header used in every structure containing batchable data from a sensor.
- *
- * The typical structure for sensor data looks like:
- *
- *   struct chreSensorTypeData {
- *       struct chreSensorDataHeader header;
- *       struct chreSensorTypeSampleData {
- *           uint32_t timestampDelta;
- *           union {
- *               <type> value;
- *               <type> interpretation0;
- *               <type> interpretation1;
- *           };
- *       } readings[1];
- *   };
- *
- * Despite 'readings' being declared as an array of 1 element,
- * an instance of the struct will actually have 'readings' as
- * an array of header.readingCount elements (which may be 1).
- * The 'timestampDelta' is in relation to the previous 'readings' (or
- * the baseTimestamp for readings[0].  So,
- * Timestamp for readings[0] == header.baseTimestamp +
- *     readings[0].timestampDelta.
- * Timestamp for readings[1] == timestamp for readings[0] +
- *     readings[1].timestampDelta.
- * And thus, in order to determine the timestamp for readings[N], it's
- * necessary to process through all of the N-1 readings.  The advantage,
- * though, is that our entire readings can span an arbitrary length of time,
- * just as long as any two consecutive readings differ by no more than
- * 4.295 seconds (timestampDelta, like all time in the CHRE, is in
- * nanoseconds).
- *
- * If a sensor has batched readings where two consecutive readings differ by
- * more than 4.295 seconds, the CHRE will split them across multiple
- * instances of the struct, and send multiple events.
- *
- * The value from the sensor is typically expressed in a union,
- * allowing a generic access to the data ('value'), along with
- * differently named access giving a more natural interpretation
- * of the data for the specific sensor types which use this
- * structure.  This allows, for example, barometer code to
- * reference readings[N].pressure, and an ambient light sensor
- * to reference readings[N].light, while both use the same
- * structure.
- */
-struct chreSensorDataHeader {
-    /**
-     * The base timestamp, in nanoseconds.
-     */
-    uint64_t baseTimestamp;
-
-    /**
-     * The handle of the sensor producing this event.
-     */
-    uint32_t sensorHandle;
-
-    /**
-     * The number elements in the 'readings' array.
-     *
-     * This must be at least 1.
-     */
-    uint16_t readingCount;
-
-    /**
-     * Reserved bytes.
-     *
-     * These must be 0.
-     */
-    uint8_t reserved[2];
-};
-
-/**
- * Data for a sensor which reports on three axes.
- *
- * This is used by CHRE_EVENT_SENSOR_ACCELEROMETER_DATA,
- * CHRE_EVENT_SENSOR_GYROSCOPE_DATA,
- * CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO,
- * CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA, and
- * CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO.
- */
-struct chreSensorThreeAxisData {
-    /**
-     * @see chreSensorDataHeader
-     */
-    struct chreSensorDataHeader header;
-    struct chreSensorThreeAxisSampleData {
-        /**
-         * @see chreSensorDataHeader
-         */
-        uint32_t timestampDelta;
-        union {
-            float values[3];
-            float v[3];
-            struct {
-                float x;
-                float y;
-                float z;
-            };
-            float bias[3];
-            struct {
-                float x_bias;
-                float y_bias;
-                float z_bias;
-            };
-        };
-    } readings[1];
-};
-
-/**
- * Data from a sensor where we only care about a event occurring.
- *
- * This is a bit unusual in that our readings have no data in addition
- * to the timestamp.  But since we only care about the occurrence, we
- * don't need to know anything else.
- *
- * Used by: CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA and
- *     CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA.
- */
-struct chreSensorOccurrenceData {
-    struct chreSensorDataHeader header;
-    struct chreSensorOccurenceSampleData {
-        uint32_t timestampDelta;
-        // This space intentionally left blank.
-        // Only the timestamp is meaningful here, there
-        // is no additional data.
-    } readings[1];
-};
-
-/**
- * CHRE_EVENT_SENSOR_LIGHT_DATA and CHRE_EVENT_SENSOR_PRESSURE_DATA.
- */
-struct chreSensorFloatData {
-    struct chreSensorDataHeader header;
-    struct chreSensorFloatSampleData {
-        uint32_t timestampDelta;
-        union {
-            float value;
-            float light;  // lux
-            float pressure;  // hectopascals (hPa)
-        };
-    } readings[1];
-};
-
-/**
- * CHRE_EVENT_SENSOR_PROXIMITY_DATA.
- */
-struct chreSensorByteData {
-    struct chreSensorDataHeader header;
-    struct chreSensorByteSampleData {
-        uint32_t timestampDelta;
-        union {
-            uint8_t value;
-            struct {
-                uint8_t isNear : 1;
-                uint8_t invalid : 1;
-                uint8_t padding0 : 6;
-            };
-        };
-    } readings[1];
-};
-
-/**
- * The status of a sensor's sampling configuration.
- */
-struct chreSensorSamplingStatus {
-    /**
-     * The interval, in nanoseconds, at which the sensor is now sampling.
-     *
-     * If this is CHRE_SENSOR_INTERVAL_DEFAULT, then a sampling interval
-     * isn't meaningful for this sensor.
-     *
-     * Note that if 'enabled' is false, this value is not meaningful.
-     */
-    uint64_t interval;
-
-    /**
-     * The latency, in nanoseconds, at which the senor is now reporting.
-     *
-     * If this is CHRE_SENSOR_LATENCY_DEFAULT, then a latency
-     * isn't meaningful for this sensor.
-     *
-     * Note that if 'enabled' is false, this value is not meaningful.
-     */
-    uint64_t latency;
-
-    /**
-     * True if the sensor is actively powered and sampling; false otherwise.
-     */
-    bool enabled;
-};
-
-/**
- * The nanoappHandleEvent argument for CHRE_EVENT_SENSOR_SAMPLING_CHANGE.
- *
- * Note that only at least one of 'interval' or 'latency' must be
- * different than it was prior to this event.  Thus, one of these
- * fields may be (but doesn't need to be) the same as before.
- */
-struct chreSensorSamplingStatusEvent {
-    /**
-     * The handle of the sensor which has experienced a change in sampling.
-     */
-    uint32_t sensorHandle;
-
-    /**
-     * The new sampling status.
-     *
-     * At least one of the field in this struct will be different from
-     * the previous sampling status event.
-     */
-    struct chreSensorSamplingStatus status;
-};
-
-
-
-/**
- * Find the default sensor for a given sensor type.
- *
- * @param sensorType One of the CHRE_SENSOR_TYPE_* constants.
- * @param handle  If a sensor is found, then the memory will be filled with
- *     the value for the sensor's handle.  This argument must be non-NULL.
- * @returns true if a sensor was found, false otherwise.
- */
-bool chreSensorFindDefault(uint8_t sensorType, uint32_t *handle);
-
-/**
- * Get the chreSensorInfo struct for a given sensor.
- *
- * @param sensorHandle  The sensor handle, as obtained from
- *     chreSensorFindDefault() or passed to nanoappHandleEvent().
- * @param info  If the sensor is valid, then this memory will be filled with
- *     the SensorInfo contents for this sensor.  This argument must be
- *     non-NULL.
- * @returns true if the senor handle is valid and 'info' was filled in;
- *     false otherwise.
- */
-bool chreGetSensorInfo(uint32_t sensorHandle, struct chreSensorInfo *info);
-
-/**
- * Get the chreSensorSamplingStatus struct for a given sensor.
- *
- * Note that this may be different from what was requested in
- * chreSensorConfigure(), for multiple reasons.  It's possible that the sensor
- * does not exactly support the interval requested in chreSensorConfigure(), so
- * a faster one was chosen.
- *
- * It's also possible that there is another user of this sensor who has
- * requested a faster interval and/or lower latency.  This latter scenario
- * should be noted, because it means the sensor rate can change due to no
- * interaction from this nanoapp.  Note that the
- * CHRE_EVENT_SENSOR_SAMPLING_CHANGE event will trigger in this case, so it's
- * not necessary to poll for such a change.
- *
- * @param sensorHandle  The sensor handle, as obtained from
- *     chreSensorFindDefault() or passed to nanoappHandleEvent().
- * @param status  If the sensor is valid, then this memory will be filled with
- *     the sampling status contents for this sensor.  This argument must be
- *     non-NULL.
- * @returns true if the senor handle is valid and 'status' was filled in;
- *     false otherwise.
- */
-bool chreGetSensorSamplingStatus(uint32_t sensorHandle,
-                                 struct chreSensorSamplingStatus *status);
-
-/**
- * Configures a given sensor at a specific interval and latency and mode.
- *
- * If this sensor's chreSensorInfo has isOneShot set to 1,
- * then the mode must be one of the ONE_SHOT modes, or this method will fail.
- *
- * The CHRE wants to power as few sensors as possible, in keeping with its
- * low power design.  As such, it only turns on sensors when there are clients
- * actively interested in that sensor data, and turns off sensors as soon as
- * there are no clients interested in them.  Calling this method generally
- * indicates an interest, and using CHRE_SENSOR_CONFIGURE_MODE_DONE shows
- * when we are no longer interested.
- *
- * Thus, each initial Configure of a sensor (per nanoapp) needs to eventually
- * have a DONE call made, either directly or on its behalf.  Subsequent calls
- * to a Configure method within the same nanoapp, when there has been no DONE
- * in between, still only require a single DONE call.
- *
- * For example, the following is valid usage:
- * <code>
- *   chreSensorConfigure(myHandle, mode, interval0, latency0);
- *   [...]
- *   chreSensorConfigure(myHandle, mode, interval1, latency0);
- *   [...]
- *   chreSensorConfigure(myHandle, mode, interval1, latency1);
- *   [...]
- *   chreSensorConfigureModeOnly(myHandle, CHRE_SENSOR_CONFIGURE_MODE_DONE);
- * </code>
- *
- * The first call to Configure is the one which creates the requirement
- * to eventually call with DONE.  The subsequent calls are just changing the
- * interval/latency.  They have not changed the fact that this nanoapp is
- * still interested in output from the sensor 'myHandle'.  Thus, only one
- * single call for DONE is needed.
- *
- * There is a special case.  One-shot sensors, sensors which
- * just trigger a single event and never trigger again, implicitly go into
- * DONE mode after that single event triggers.  Thus, the
- * following are legitimate usages:
- * <code>
- *   chreSensorConfigure(myHandle, MODE_ONE_SHOT, rate, latency);
- *   [...]
- *   [myHandle triggers an event]
- *   [no need to configure to DONE].
- * </code>
- *
- * And:
- * <code>
- *   chreSensorConfigure(myHandle, MODE_ONE_SHOT, rate, latency);
- *   [...]
- *   chreSensorConfigureModeOnly(myHandle, MODE_DONE);
- *   [we cancelled myHandle before it ever triggered an event]
- * </code>
- *
- * Note that while PASSIVE modes, by definition, don't express
- * an interest in powering the sensor, DONE is still necessary
- * to silence the event reporting.
- *
- * @param sensorHandle  The handle to the sensor, as obtained from
- *     chreSensorFindDefault().
- * @param mode  The mode to use.  See descriptions within the
- *     chreSensorConfigureMode enum.
- * @param interval  The interval, in nanoseconds, at which we want events from
- *     the sensor.  On success, the sensor will be set to 'interval', or a value
- *     less than 'interval'.  There is a special value
- *     CHRE_SENSOR_INTERVAL_DEFAULT, in which we don't express a preference for
- *     the interval, and allow the sensor to chose what it wants.  Note that
- *     due to batching, we may receive events less frequently than
- *     'interval'.
- * @param latency  The maximum latency, in nanoseconds, allowed before the
- *     CHRE begins delivery of an event.  This will control how many events
- *     can be queued by the sensor before requiring a delivery event.
- *     Latency is defined as the "timestamp when event is queued by the CHRE"
- *     minus "timestamp of oldest unsent data reading".
- *     There is a special value CHRE_SENSOR_LATENCY_DEFAULT, in which we don't
- *     express a preference for the latency, and allow the sensor to chose what
- *     it wants.
- *     Note that there is no assurance of how long it will take an event to
- *     get through a CHRE's queueing system, and thus there is no ability to
- *     request a minimum time from the occurrence of a phenomenon to when the
- *     nanoapp receives the information.  The current CHRE API has no
- *     real-time elements, although future versions may introduce some to
- *     help with this issue.
- * @returns true if the configuration succeeded, false otherwise.
- *
- * @see chreSensorConfigureMode
- * @see chreSensorFindDefault
- * @see chreSensorInfo
- */
-bool chreSensorConfigure(uint32_t sensorHandle,
-                         enum chreSensorConfigureMode mode,
-                         uint64_t interval, uint64_t latency);
-
-/**
- * Short cut for chreSensorConfigure where we only want to change the mode.
- *
- * @see chreSensorConfigure
- */
-static inline bool chreSensorConfigureModeOnly(
-        uint32_t sensorHandle, enum chreSensorConfigureMode mode) {
-    return chreSensorConfigure(sensorHandle,
-                               mode,
-                               CHRE_SENSOR_INTERVAL_DEFAULT,
-                               CHRE_SENSOR_LATENCY_DEFAULT);
-}
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  /* _CHRE_SENSOR_H_ */
-
diff --git a/inc/chre/version.h b/inc/chre/version.h
deleted file mode 100644
index ae6b14c..0000000
--- a/inc/chre/version.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _CHRE_VERSION_H_
-#define _CHRE_VERSION_H_
-
-/**
- * Definitions and methods for the versioning of the Context Hub Runtime
- * Environment.
- *
- * The CHRE API versioning pertains to all the chre_*.h files and chre.h.
- */
-
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/**
- * Value for version 0.1 of the Context Hub Runtime Environment API interface.
- *
- * This is a legacy version.  Version 1.0 is considered the first official
- * version of the API.
- *
- * @see CHRE_API_VERSION
- */
-#define CHRE_API_VERSION_0_1  UINT32_C(0x00010000)
-
-/**
- * Value for version 1.0 of the Context Hub Runtime Environment API interface.
- *
- * The version of the CHRE API which shipped with the Android Nougat release.
- *
- * @see CHRE_API_VERSION
- */
-#define CHRE_API_VERSION_1_0  UINT32_C(0x01000000)
-
-/**
- * Major and Minor Version of this Context Hub Runtime Environment API.
- *
- * The major version changes when there is an incompatible API change.
- *
- * The minor version changes when there is an addition in functionality
- * in a backwards-compatible manner.
- *
- * We define the version number as an unsigned 32-bit value.  The most
- * significant byte is the Major Version.  The second-most significant byte
- * is the Minor Version.  The two least significant bytes are the Patch
- * Version.  The Patch Version is not defined by this header API, but
- * is provided by a specific CHRE implementation (see chreGetVersion()).
- *
- * Note that version numbers can always be numerically compared with
- * expected results, so 1.0.0 < 1.0.4 < 1.1.0 < 2.0.300 < 3.5.0.
- */
-#define CHRE_API_VERSION CHRE_API_VERSION_1_0
-
-
-/**
- * Get the API version the CHRE implementation was compiled against.
- *
- * This is not necessarily the CHRE_API_VERSION in the header the nanoapp was
- * built against, and indeed may not have even appeared in the context_hub_os.h
- * header which this nanoapp was built against.
- *
- * By definition, this will have the two least significant bytes set to 0,
- * and only contain the major and minor version number.
- *
- * @returns The API version.
- */
-uint32_t chreGetApiVersion(void);
-
-/**
- * Get the version of this CHRE implementation.
- *
- * By definition, ((chreGetApiVersion() & UINT32_C(0xFFFF0000)) ==
- *                 (chreGetVersion()    & UINT32_C(0xFFFF0000))).
- *
- * The Patch Version, in the lower two bytes, only have meaning in context
- * of this specific platform ID.  It is increased by the platform every time
- * a backwards-compatible bug fix is released.
- *
- * @returns The version.
- *
- * @see chreGetPlatformId()
- */
-uint32_t chreGetVersion(void);
-
-/**
- * Get the Platform ID of this CHRE.
- *
- * The most significant five bytes are the vendor ID as set out by the
- * NANOAPP_VENDOR convention in context_hub.h, as used by nanoapp IDs.
- *
- * The least significant three bytes are set by the vendor, but must be
- * unique for each different CHRE implementation/hardware that the vendor
- * supplies.
- *
- * The idea is that in the case of known bugs in the field, a new nanoapp could
- * be shipped with a workaround that would use this value, and chreGetVersion(),
- * to have code that can conditionally work around the bug on a buggy version.
- * Thus, we require this uniqueness to allow such a setup to work.
- *
- * @returns The platform ID.
- */
-uint64_t chreGetPlatformId(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  /* _CHRE_VERSION_H_ */
-
diff --git a/lib/include/nanohub/nanohub.h b/lib/include/nanohub/nanohub.h
index 451df9d..61d1dc8 100644
--- a/lib/include/nanohub/nanohub.h
+++ b/lib/include/nanohub/nanohub.h
@@ -55,7 +55,9 @@
     uint32_t app_version;          // Version of the app
     uint32_t flags;                // Signed, encrypted
     uint64_t hw_hub_type;          // which hub type is this compiled for
-    uint32_t reserved[2];          // Should be all zeroes
+    uint8_t  chre_api_major;       // Which CHRE API version this is compiled for
+    uint8_t  chre_api_minor;
+    uint8_t  reserved[6];          // Should be all zeroes
     uint8_t  custom_binary[0];     // start of custom binary data
 };
 
@@ -67,11 +69,19 @@
     uint8_t len;
 } __attribute__((packed));
 
+struct HostMsgHdrChreV10 {
+    uint32_t eventId;
+    uint64_t appId;
+    uint8_t len;
+    uint32_t appEventId;
+} __attribute__((packed));
+
 struct HostMsgHdrChre {
     uint32_t eventId;
     uint64_t appId;
     uint8_t len;
     uint32_t appEventId;
+    uint16_t endpoint;
 } __attribute__((packed));
 
 // we translate AOSP header into FW header: this header is in LE format
@@ -84,7 +94,8 @@
     uint32_t appVer;        // external: copy from AOSP header; internal: defined locally
     uint8_t  payInfoType;   // external: copy ImageLayout::payload; internal: LAYOUT_APP
     uint8_t  payInfoSize;   // sizeof(PayloadInfo) for this payload type
-    uint8_t  rfu[2];        // filled with 0xFF
+    uint8_t  chreApiMajor;  // Chre Api Major Version (or 0xFF for non-chre nanoapps)
+    uint8_t  chreApiMinor;  // Chre Api Minor Version (or 0xFF for non-chre nanoapps)
 };
 
 struct SectInfo {
diff --git a/sensorhal/hubconnection.cpp b/sensorhal/hubconnection.cpp
index c283a81..3af5a60 100644
--- a/sensorhal/hubconnection.cpp
+++ b/sensorhal/hubconnection.cpp
@@ -238,7 +238,6 @@
     mSensorState[COMMS_SENSOR_DOUBLE_TAP].sensorType = SENS_TYPE_DOUBLE_TAP;
     mSensorState[COMMS_SENSOR_DOUBLE_TAP].rate = SENSOR_RATE_ONCHANGE;
     mSensorState[COMMS_SENSOR_WRIST_TILT].sensorType = SENS_TYPE_WRIST_TILT;
-    mSensorState[COMMS_SENSOR_WRIST_TILT].rate = SENSOR_RATE_ONCHANGE;
     mSensorState[COMMS_SENSOR_DOUBLE_TOUCH].sensorType = SENS_TYPE_DOUBLE_TOUCH;
     mSensorState[COMMS_SENSOR_DOUBLE_TOUCH].rate = SENSOR_RATE_ONESHOT;
     mSensorState[COMMS_SENSOR_ACTIVITY_IN_VEHICLE_START].sensorType = SENS_TYPE_ACTIVITY_IN_VEHICLE_START;
diff --git a/util/nanoapp_cmd/nanoapp_cmd.c b/util/nanoapp_cmd/nanoapp_cmd.c
index 5692181..af19386 100644
--- a/util/nanoapp_cmd/nanoapp_cmd.c
+++ b/util/nanoapp_cmd/nanoapp_cmd.c
@@ -45,7 +45,9 @@
 #define MAX_DOWNLOAD_RETRIES    4
 #define UNINSTALL_CMD           "uninstall"
 
-#define NANOHUB_EXT_APP_DELETE  2
+#define NANOHUB_HAL_EXT_APPS_ON     0
+#define NANOHUB_HAL_EXT_APPS_OFF    1
+#define NANOHUB_HAL_EXT_APP_DELETE  2
 
 #define LOGE(fmt, ...) do { \
         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__); \
@@ -72,6 +74,13 @@
     uint8_t data[];
 } __attribute__((packed));
 
+struct HalCmd
+{
+    struct HostMsgHdr hdr;
+    uint8_t cmd;
+    uint64_t appId;
+} __attribute__((packed));
+
 struct App
 {
     uint32_t num;
@@ -238,6 +247,38 @@
     return NULL;
 }
 
+int findAppIdByName(char *name, uint64_t *appId)
+{
+    FILE *fp;
+    char *line = NULL;
+    size_t len;
+    ssize_t numRead;
+    int ret = 0;
+
+    fp = openFile("/vendor/firmware/napp_list.cfg", "r");
+    if (!fp)
+        return -1;
+
+    while ((numRead = getline(&line, &len, fp)) != -1) {
+        char entry[MAX_APP_NAME_LEN+1];
+        uint32_t appVersion;
+
+        sscanf(line, "%" STRINGIFY(MAX_APP_NAME_LEN) "s %" PRIx64 " %" PRIx32 "\n", entry, appId, &appVersion);
+
+        if (strncmp(entry, name, MAX_APP_NAME_LEN) == 0) {
+            ret = 1;
+            break;
+        }
+    }
+
+    fclose(fp);
+
+    if (line)
+        free(line);
+
+    return ret;
+}
+
 int parseConfigAppInfo(int *installCnt, int *uninstallCnt)
 {
     FILE *fp;
@@ -309,23 +350,62 @@
         printf("done\n");
 }
 
+bool sendCmd(uint8_t cmd, uint64_t appId)
+{
+    struct HalCmd msg;
+
+    msg.hdr.eventId = EVT_APP_FROM_HOST;
+    msg.hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
+    msg.hdr.len = sizeof(msg) - sizeof(msg.hdr); // payload length
+    msg.cmd = cmd;
+    memcpy(&msg.appId, &appId, sizeof(uint64_t));
+
+    return fileWriteData("/dev/nanohub", &msg, sizeof(msg));
+}
+
+int halCmd(uint8_t cmd, char *arg)
+{
+    uint64_t appId;
+    char *endptr = arg + strlen(arg);
+
+    if (strcmp(arg, UNINSTALL_CMD) == 0) {
+        printf("%s is not a valid app name\n", arg);
+        return 1;
+    }
+
+    if ((findAppIdByName(arg, &appId) == 1) || (appId = strtoull(arg, &endptr, 16)) > 0) {
+        if (*endptr != '\0') {
+            printf("Couldn't find nanoapp '%s' in napp_list.cfg\n", arg);
+            return 1;
+        } else if (cmd == NANOHUB_HAL_EXT_APPS_ON)
+            printf("Loading ");
+        else if (cmd == NANOHUB_HAL_EXT_APPS_OFF)
+            printf("Unloading ");
+        else if (cmd == NANOHUB_HAL_EXT_APP_DELETE)
+            printf("Deleting ");
+        else {
+            printf("Unrecognized cmd: %d\n", cmd);
+            return 1;
+        }
+        printf("\"0x%016" PRIx64 "\"...", appId);
+        fflush(stdout);
+        if (sendCmd(cmd, appId))
+            printf("done\n");
+        return 0;
+    } else {
+        printf("Couldn't find nanoapp '%s' in napp_list.cfg\n", arg);
+        return 1;
+    }
+}
+
 void removeApps(int updateCnt)
 {
-    uint8_t buffer[sizeof(struct HostMsgHdr) + 1 + sizeof(uint64_t)];
-    struct HostMsgHdr *mHostMsgHdr = (struct HostMsgHdr *)(&buffer[0]);
-    uint8_t *cmd = (uint8_t *)(&buffer[sizeof(struct HostMsgHdr)]);
-    uint64_t *appId = (uint64_t *)(&buffer[sizeof(struct HostMsgHdr) + 1]);
     int i;
 
     for (i = 0; i < updateCnt; i++) {
-        mHostMsgHdr->eventId = EVT_APP_FROM_HOST;
-        mHostMsgHdr->appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
-        mHostMsgHdr->len = 1 + sizeof(uint64_t);
-        *cmd = NANOHUB_EXT_APP_DELETE;
-        memcpy(appId, &appsToUninstall[i], sizeof(uint64_t));
-        printf("Deleting \"%016" PRIx64 "\"...", appsToUninstall[i]);
+        printf("Deleting \"0x%016" PRIx64 "\"...", appsToUninstall[i]);
         fflush(stdout);
-        if (fileWriteData("/dev/nanohub", buffer, sizeof(buffer)))
+        if (sendCmd(NANOHUB_HAL_EXT_APP_DELETE, appsToUninstall[i]))
             printf("done\n");
     }
 }
@@ -372,7 +452,7 @@
 
     if (argc < 3 && (argc < 2 || strcmp(argv[1], "download") != 0)) {
         printf("usage: %s <action> <sensor> <data> -d\n", argv[0]);
-        printf("       action: config|cfgdata|calibrate|flush|download\n");
+        printf("       action: config|cfgdata|calibrate|flush\n");
         printf("       sensor: (uncal_)accel|(uncal_)gyro|(uncal_)mag|als|prox|baro|temp|orien\n");
         printf("               gravity|geomag|linear_acc|rotation|game\n");
         printf("               win_orien|tilt|step_det|step_cnt|double_tap\n");
@@ -383,6 +463,9 @@
         printf("             calibrate: [N.A.]\n");
         printf("             flush: [N.A.]\n");
         printf("       -d: if specified, %s will keep draining /dev/nanohub until cancelled.\n", argv[0]);
+        printf("usage: %s <cmd> [app]\n", argv[0]);
+        printf("       cmd: download|load|unload|delete\n");
+        printf("       app: appId or name from napp_list.cfg\n");
 
         return 1;
     }
@@ -469,6 +552,27 @@
             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
             return 1;
         }
+    } else if (strcmp(argv[1], "load") == 0) {
+        if (argc != 3) {
+            printf("Wrong arg number\n");
+            return 1;
+        }
+
+        return halCmd(NANOHUB_HAL_EXT_APPS_ON, argv[2]);
+    } else if (strcmp(argv[1], "unload") == 0) {
+        if (argc != 3) {
+            printf("Wrong arg number\n");
+            return 1;
+        }
+
+        return halCmd(NANOHUB_HAL_EXT_APPS_OFF, argv[2]);
+    } else if (strcmp(argv[1], "delete") == 0) {
+        if (argc != 3) {
+            printf("Wrong arg number\n");
+            return 1;
+        }
+
+        return halCmd(NANOHUB_HAL_EXT_APP_DELETE, argv[2]);
     } else if (strcmp(argv[1], "download") == 0) {
         int installCnt, uninstallCnt;
 
@@ -496,8 +600,9 @@
 
         if (parseConfigAppInfo(&installCnt, &uninstallCnt) != 0) {
             LOGE("Failed to download all apps!");
+            return 1;
         }
-        return 1;
+        return 0;
     } else {
         printf("Unsupported action: %s\n", argv[1]);
         return 1;
diff --git a/util/nanoapp_postprocess/postprocess_elf.c b/util/nanoapp_postprocess/postprocess_elf.c
index aa0b2ba..b5bf0c0 100644
--- a/util/nanoapp_postprocess/postprocess_elf.c
+++ b/util/nanoapp_postprocess/postprocess_elf.c
@@ -109,6 +109,7 @@
                     "       -n <layout name> : app, os, key\n"
                     "       -i <layout id>   : 1 (app), 2 (key), 3 (os)\n"
                     "       -f <layout flags>: 16-bit hex value, stored as layout-specific flags\n"
+                    "       -c <chre api>    : 16-bit hex value, stored as chre-major + chre-minor\n"
                     "       -a <app ID>      : 64-bit hex number != 0\n"
                     "       -e <app version> : 32-bit hex number\n"
                     "       -k <key ID>      : 64-bit hex number != 0\n"
@@ -225,7 +226,7 @@
     return packedNanoRelocs;
 }
 
-static int finalizeAndWrite(uint8_t *buf, uint32_t bufUsed, uint32_t bufSz, FILE *out, uint32_t layoutFlags, uint64_t appId)
+static int finalizeAndWrite(uint8_t *buf, uint32_t bufUsed, uint32_t bufSz, FILE *out, uint32_t layoutFlags, uint64_t appId, uint32_t chreApi)
 {
     int ret;
     struct AppInfo app;
@@ -238,12 +239,14 @@
             .app_id = appId,
             .app_version = bin->hdr.appVer,
             .flags       = 0, // encrypted (1), signed (2) (will be set by other tools)
+            .chre_api_major = chreApi >> 8,
+            .chre_api_minor = chreApi & 0xFF,
         },
         .layout = (struct ImageLayout) {
             .magic = GOOGLE_LAYOUT_MAGIC,
             .version = 1,
             .payload = LAYOUT_APP,
-            .flags = layoutFlags,
+            .flags = layoutFlags | (chreApi ? 0x0010 : 0x0000),
         },
     };
     uint32_t dataOffset = sizeof(outHeader) + sizeof(app);
@@ -285,7 +288,7 @@
     return ret;
 }
 
-static int handleApp(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, uint32_t appVer, bool verbose)
+static int handleApp(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, uint32_t appVer, uint32_t chreApi, bool verbose)
 {
     uint32_t i, numRelocs, numSyms, outNumRelocs = 0, packedNanoRelocSz;
     struct NanoRelocEntry *nanoRelocs = NULL;
@@ -529,7 +532,7 @@
     sect->rel_start -= FLASH_BASE + BINARY_RELOC_OFFSET;
     sect->rel_end -= FLASH_BASE + BINARY_RELOC_OFFSET;
 
-    ret = finalizeAndWrite(buf, bufUsed, bufSz, out, layoutFlags, appId);
+    ret = finalizeAndWrite(buf, bufUsed, bufSz, out, layoutFlags, appId, chreApi);
 out:
     free(nanoRelocs);
     return ret;
@@ -786,7 +789,7 @@
     return success;
 }
 
-static int handleAppStatic(const char *fileName, FILE *out, uint32_t layoutFlags, uint64_t appId, uint32_t appVer, bool verbose)
+static int handleAppStatic(const char *fileName, FILE *out, uint32_t layoutFlags, uint64_t appId, uint32_t appVer, uint32_t chreApi, bool verbose)
 {
     struct ElfNanoApp app;
 
@@ -823,7 +826,7 @@
     hdr->sect.rel_end = hdr->sect.rel_start + app.packedNanoRelocs.size;
     hdr->hdr.appVer = appVer;
 
-    return finalizeAndWrite(buf, offset, bufSize, out, layoutFlags, appId);
+    return finalizeAndWrite(buf, offset, bufSize, out, layoutFlags, appId, chreApi);
     // TODO: should free all memory we allocated... just letting the OS handle
     // it for now
 }
@@ -896,6 +899,7 @@
     uint64_t appId = 0;
     uint64_t keyId = 0;
     uint32_t appVer = 0;
+    uint32_t chreApi = 0;
     uint32_t layoutId = 0;
     uint32_t layoutFlags = 0;
     int ret = -1;
@@ -923,6 +927,8 @@
                 staticElf = true;
             else if (!strcmp(argv[i], "-a"))
                 u64Arg = &appId;
+            else if (!strcmp(argv[i], "-c"))
+                u32Arg = &chreApi;
             else if (!strcmp(argv[i], "-e"))
                 u32Arg = &appVer;
             else if (!strcmp(argv[i], "-k"))
@@ -1000,9 +1006,9 @@
     switch(layoutId) {
     case LAYOUT_APP:
         if (staticElf) {
-            ret = handleAppStatic(posArg[0], out, layoutFlags, appId, appVer, verbose);
+            ret = handleAppStatic(posArg[0], out, layoutFlags, appId, appVer, chreApi, verbose);
         } else {
-            ret = handleApp(&buf, bufUsed, out, layoutFlags, appId, appVer, verbose);
+            ret = handleApp(&buf, bufUsed, out, layoutFlags, appId, appVer, chreApi, verbose);
         }
         break;
     case LAYOUT_KEY: