HAL: first pass at a nanohub HAL

A few things missing and some optimisations not done, but the
general idea is ok. Will not work will the kernel supports the
proper devnode endpoint for comms.

Change-Id: I90bad17a937363487aa3d1c9d2818d12f8da66fd
diff --git a/HAL/Android.mk b/HAL/Android.mk
new file mode 100644
index 0000000..274b282
--- /dev/null
+++ b/HAL/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH := $(call my-dir)
+
+# HAL module implemenation stored in
+# hw/<CONTEXT_HUB_MODULE_ID>.<ro.hardware>.so
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MULTILIB := both
+LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_SRC_FILES := nanohubhal.c system_comms.c
+LOCAL_MODULE_OWNER := google
+LOCAL_PROPRIETARY_MODULE := true
+
+# Include target-specific files.
+
+ifneq ($(filter bullhead, $(TARGET_DEVICE)),)
+LOCAL_SRC_FILES += nanohubhal_bullhead.c
+endif
+
+ifneq ($(filter angler, $(TARGET_DEVICE)),)
+LOCAL_SRC_FILES += nanohubhal_angler.c
+endif
+
+
+
+LOCAL_MODULE := context_hub.$(TARGET_DEVICE)
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_SHARED_LIBRARY)
diff --git a/HAL/nanohub_perdevice.h b/HAL/nanohub_perdevice.h
new file mode 100644
index 0000000..c47f667
--- /dev/null
+++ b/HAL/nanohub_perdevice.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Google. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef _NANOHUB_PER_DEVICE_H_
+#define _NANOHUB_PER_DEVICE_H_
+
+#include <hardware/context_hub.h>
+
+const struct context_hub_t* get_hub_info(void);
+const char *get_devnode_path(void);
+
+
+#endif
+
diff --git a/HAL/nanohubhal.c b/HAL/nanohubhal.c
new file mode 100644
index 0000000..f4bd87f
--- /dev/null
+++ b/HAL/nanohubhal.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2016, Google. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "NanohubHAL"
+#include <hardware/context_hub.h>
+#include <hardware/hardware.h>
+#include "nanohub_perdevice.h"
+#include "system_comms.h"
+#include "nanohubhal.h"
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+
+
+
+static pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER;
+static context_hub_callback *mMsgCbkFunc = NULL;
+static int mThreadClosingPipe[2], mFd; // [0] is read end
+static void * mMsgCbkData = NULL;
+static pthread_t mWorkerThread;
+
+
+
+static int rwrite(int fd, const void *buf, int len)
+{
+    int ret;
+
+    do {
+        ret = write(fd, buf, len);
+    } while (ret < 0 && errno == EINTR);
+
+    if (ret != len)
+        return errno ? -errno : -EIO;
+
+    return 0;
+}
+
+static int rread(int fd, void *buf, int len)
+{
+    int ret;
+
+    do {
+        ret = read(fd, buf, len);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+
+int hal_hub_do_send_msg(const void *name, uint8_t len, const void *data) //assumes message is not malformed or invalid
+{
+    uint8_t buf[EVENT_ID_LEN + APP_NAME_LEN + 1 + MAX_RX_PACKET];
+    uint32_t event_id = APP_FROM_HOST_EVENT_ID;
+
+    memcpy(buf + 0, &event_id, EVENT_ID_LEN);
+    memcpy(buf + EVENT_ID_LEN, name, APP_NAME_LEN);
+    buf[EVENT_ID_LEN + APP_NAME_LEN] = len;
+    memcpy(buf + EVENT_ID_LEN + APP_NAME_LEN + 1, data, len);
+
+    return rwrite(mFd, buf, EVENT_ID_LEN + APP_NAME_LEN + 1 + len);
+}
+
+void hal_hub_call_rx_msg_f(const void *name, uint32_t typ, uint32_t len, const void *data)
+{
+    struct hub_app_name_t appName = { .app_name_len = APP_NAME_LEN, .app_name = name, };
+    struct hub_message_t msg = { .app = &appName, .message_type = typ, .message_len = len, .message = data, };
+
+    mMsgCbkFunc(0, &msg, mMsgCbkData);
+}
+
+static void* hal_hub_thread(void *unused) //all nanoapp message_type vals are "0" for this hal. apps can send type themselves in payload
+{
+    uint8_t buffer[EVENT_ID_LEN + APP_NAME_LEN + 1 + MAX_RX_PACKET];
+    uint8_t *header = &buffer[EVENT_ID_LEN];
+    uint8_t *packetData = &buffer[EVENT_ID_LEN + APP_NAME_LEN + 1];
+    const int idxNanohub = 0, idxClosePipe = 1;
+    int ret;
+
+    (void)unused;
+    while (1) {
+        struct pollfd myFds[] = { [idxNanohub] = { .fd = mFd, .events = POLLIN, }, [idxClosePipe] = {.fd = mThreadClosingPipe[0], .events = POLLIN, }, };
+
+        ret = poll(myFds, sizeof(myFds) / sizeof(*myFds), -1);
+        if (ret <= 0) {
+            ALOGD("poll is being weird");
+            continue;
+        }
+
+        if (myFds[idxNanohub].revents & POLLIN) { // we have data
+
+            uint32_t len;
+
+            ret = rread(mFd, buffer, sizeof(buffer));
+            if (ret <= 0) {
+                ALOGE("read 1 fails");
+                break;
+            }
+
+            len = header[APP_NAME_LEN];
+
+            if (len > MAX_RX_PACKET) {
+                ALOGE("malformed packet");
+                break;
+            }
+
+            if (ret != EVENT_ID_LEN + APP_NAME_LEN + 1 + len) {
+                ALOGE("read 2 fails");
+                break;
+            }
+
+            ret = system_comms_handle_rx(header, len, packetData);
+            if (!ret)
+                hal_hub_call_rx_msg_f(header, 0, len, packetData);
+        }
+
+        if (myFds[idxClosePipe].revents & POLLIN) { // we have been asked to die
+            ALOGD("thread exiting");
+            break;
+        }
+    }
+
+    close(mFd);
+    return NULL;
+}
+
+static int hal_hub_open(void)
+{
+    int ret = 0;
+
+    mFd = open(get_devnode_path(), O_RDWR);
+    if (mFd < 0) {
+        ALOGE("cannot find hub devnode '%s'", get_devnode_path());
+        ret = -errno;
+        goto fail_open;
+    }
+
+    if (pipe(mThreadClosingPipe)) {
+        ALOGE("failed to create signal pipe");
+        ret = -errno;
+        goto fail_pipe;
+    }
+
+    if (pthread_create(&mWorkerThread, NULL, hal_hub_thread, NULL)) {
+        ALOGE("failed to spawn worker thread");
+        ret = -errno;
+        goto fail_thread;
+    }
+
+    return 0;
+
+fail_thread:
+    close(mThreadClosingPipe[0]);
+    close(mThreadClosingPipe[1]);
+
+fail_pipe:
+    close(mFd);
+
+fail_open:
+    return ret;
+}
+
+static int hal_hub_close(void)
+{
+    char zero = 0;
+
+    //signal
+    while(write(mThreadClosingPipe[1], &zero, 1) != 1);
+
+    //wait
+    (void)pthread_join(mWorkerThread, NULL);
+
+    //cleanup
+    close(mThreadClosingPipe[0]);
+    close(mThreadClosingPipe[1]);
+
+    return 0;
+}
+
+static int hal_hub_subscribe_messages(uint32_t hub_id, context_hub_callback *cbk, void *cookie)
+{
+    int ret = 0;
+
+    if (hub_id)
+        return -ENODEV;
+
+    pthread_mutex_lock(&mLock);
+    if (!mMsgCbkFunc && !cbk) { //we're off and staying off - do nothing
+
+        ALOGD("staying off");
+    }
+    else if (cbk && mMsgCbkFunc) { //new callback but staying on
+
+        ALOGD("staying on");
+    }
+    else if (mMsgCbkFunc) {     //we were on but turning off
+
+        ALOGD("turning off");
+
+        ret = hal_hub_close();
+    }
+    else if (cbk) {             //we're turning on
+
+        ALOGD("turning on");
+        ret = hal_hub_open();
+    }
+
+    mMsgCbkFunc = cbk;
+    mMsgCbkData = cookie;
+
+    pthread_mutex_unlock(&mLock);
+
+    return ret;
+}
+
+static int hal_hub_send_message(uint32_t hub_id, const struct hub_message_t *msg)
+{
+    int ret = 0;
+
+    if (hub_id)
+        return -ENODEV;
+
+    pthread_mutex_lock(&mLock);
+
+    if (!mMsgCbkFunc) {
+
+        ALOGW("refusing to send a message when nobody around to get a reply!");
+        ret = -EIO;
+    }
+    else {
+
+        if (!msg || !msg->app || !msg->app->app_name || msg->app->app_name_len != APP_NAME_LEN || !msg->message) {
+            ALOGW("not sending invalid message 1");
+            ret = -EINVAL;
+        }
+
+        if (!memcmp(get_hub_info()->os_app_name->app_name, msg->app->app_name, APP_NAME_LEN)) { //messages to the "system" app are special - hal handles them
+            ret = system_comms_handle_tx(msg);
+        }
+        else if (msg->message_type || msg->message_len > MAX_RX_PACKET) {
+            ALOGW("not sending invalid message 2");
+            ret = -EINVAL;
+        }
+        else {
+            ret = hal_hub_do_send_msg(msg->app->app_name, msg->message_len, msg->message);
+        }
+    }
+
+    pthread_mutex_unlock(&mLock);
+
+    return ret;
+}
+
+static int hal_get_hubs(struct context_hub_module_t* module, const struct context_hub_t ** list)
+{
+    (void)module;
+
+    *list = get_hub_info();
+
+    return 1; /* we have one hub */
+}
+
+struct context_hub_module_t HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .module_api_version = CONTEXT_HUB_DEVICE_API_VERSION_1_0,
+        .hal_api_version = HARDWARE_HAL_API_VERSION,
+        .id = CONTEXT_HUB_MODULE_ID,
+        .name = "Bullhead nanohub HAL",
+        .author = "Google",
+    },
+
+    .get_hubs = hal_get_hubs,
+    .subscribe_messages = hal_hub_subscribe_messages,
+    .send_message = hal_hub_send_message,
+};
+
diff --git a/HAL/nanohubhal.h b/HAL/nanohubhal.h
new file mode 100644
index 0000000..bb300e8
--- /dev/null
+++ b/HAL/nanohubhal.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, Google. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef _NANOHUB_HAL_H_
+#define _NANOHUB_HAL_H_
+
+#include <hardware/context_hub.h>
+
+
+//as per protocol
+#define APP_NAME_LEN            8
+#define EVENT_ID_LEN            4
+#define MAX_RX_PACKET           128
+#define APP_FROM_HOST_EVENT_ID  0x000000F8
+
+int hal_hub_do_send_msg(const void *name, uint8_t len, const void *data);
+void hal_hub_call_rx_msg_f(const void *name, uint32_t type, uint32_t len, const void *data);
+
+
+#endif
+
diff --git a/HAL/nanohubhal_angler.c b/HAL/nanohubhal_angler.c
new file mode 100644
index 0000000..c18d379
--- /dev/null
+++ b/HAL/nanohubhal_angler.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, Google. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "NanohubHAL"
+#include <hardware/context_hub.h>
+#include "nanohub_perdevice.h"
+#include "nanohubhal.h"
+#include <utils/Log.h>
+
+
+static const uint8_t mOsAppNameArr[APP_NAME_LEN] = {
+    0,
+};
+
+static const struct hub_app_name_t mOsAppName = {
+    .app_name_len = APP_NAME_LEN,
+    .app_name = mOsAppNameArr,
+};
+
+static const struct connected_sensor_t mSensors[] = {
+    {
+        .sensor_id = 123,
+        .physical_sensor = {
+            .name = "some angler sensor thing",
+        },
+    },
+    {
+        .sensor_id = 456,
+        .physical_sensor = {
+            .name = "todo: maybe consider filling this in later possibly, if time allows and the stars align",
+        },
+};
+
+static const struct context_hub_t mHub = {
+    .name = "Google System Nanohub on Angler",
+    .vendor = "Google/StMicro",
+    .toolchain = "gcc-arm-none-eabi",
+    .platform_version = 1,
+    .toolchain_version = 0x04080000, //4.8
+    .hub_id = 0,
+
+    .peak_mips = 16,
+    .stopped_power_draw_mw = .01 * 1.8,
+    .sleep_power_draw_mw = .08 * 1.8,
+    .peak_power_draw_mw = 3 * 1.8,
+
+    .connected_sensors = mSensors,
+    .num_connected_sensors = sizeof(mSensors) / sizeof(*mSensors),
+
+    .max_supported_msg_len = MAX_RX_PACKET,
+    .os_app_name = &mOsAppName,
+};
+
+
+const char *get_devnode_path(void)
+{
+    return "/dev/nanohub_comms";
+}
+
+const struct context_hub_t* get_hub_info(void)
+{
+    return &mHub;
+}
+
+
diff --git a/HAL/nanohubhal_bullhead.c b/HAL/nanohubhal_bullhead.c
new file mode 100644
index 0000000..bae6ea0
--- /dev/null
+++ b/HAL/nanohubhal_bullhead.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016, Google. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "NanohubHAL"
+#include <hardware/context_hub.h>
+#include "nanohub_perdevice.h"
+#include "nanohubhal.h"
+#include <utils/Log.h>
+
+
+static const uint8_t mOsAppNameArr[APP_NAME_LEN] = {
+    0,
+};
+
+static const struct hub_app_name_t mOsAppName = {
+    .app_name_len = APP_NAME_LEN,
+    .app_name = mOsAppNameArr,
+};
+
+static const struct connected_sensor_t mSensors[] = {
+    {
+        .sensor_id = 12345,
+        .physical_sensor = {
+            .name = "i'll get to this later",
+        },
+    },
+    {
+        .sensor_id = 24680,
+        .physical_sensor = {
+            .name = "i'll get to this later as well",
+        },
+    },
+};
+
+static const struct context_hub_t mHub = {
+    .name = "Google System Nanohub on Bullhead",
+    .vendor = "Google/StMicro",
+    .toolchain = "gcc-arm-none-eabi",
+    .platform_version = 1,
+    .toolchain_version = 0x04080000, //4.8
+    .hub_id = 0,
+
+    .peak_mips = 16,
+    .stopped_power_draw_mw = .01 * 1.8,
+    .sleep_power_draw_mw = .08 * 1.8,
+    .peak_power_draw_mw = 3 * 1.8,
+
+    .connected_sensors = mSensors,
+    .num_connected_sensors = sizeof(mSensors) / sizeof(*mSensors),
+
+    .max_supported_msg_len = MAX_RX_PACKET,
+    .os_app_name = &mOsAppName,
+};
+
+
+const char *get_devnode_path(void)
+{
+    return "/dev/nanohub_comms";
+}
+
+const struct context_hub_t* get_hub_info(void)
+{
+    return &mHub;
+}
+
+
diff --git a/HAL/system_comms.c b/HAL/system_comms.c
new file mode 100644
index 0000000..6b72752
--- /dev/null
+++ b/HAL/system_comms.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2016, Google. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "NanohubHAL"
+#include <hardware/context_hub.h>
+#include "nanohub_perdevice.h"
+#include "system_comms.h"
+#include "nanohubhal.h"
+#include <utils/Log.h>
+#include <stdbool.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+
+
+
+static pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER; //protects every global here
+static bool mHaveRsaKeys = false, mAppInfoReqInProgress = false, mUploadingOs, mUploadingStarted = false;
+static uint32_t mRsaOffset, mUploadLen, mUploadPos, mNumRsaKeys, mAppQueryIdx = 0;
+static uint8_t *mUploadData = NULL, *mRsaKeys = NULL;
+static struct NanohubAppInfo *mAppInfo = NULL;
+
+
+
+
+static const uint8_t mHostIfAppNameBuf[APP_NAME_LEN] = {
+    0, 0, 0, 'l', 'g' ,'o', 'o', 'G',
+};
+
+static const struct hub_app_name_t mHostIfAppName = {
+    .app_name_len = APP_NAME_LEN,
+    .app_name = mHostIfAppNameBuf,
+};
+
+static uint32_t leToHost32(uint32_t in)
+{
+    const uint8_t *buf = (const uint8_t*)&in;
+    uint32_t ret = buf[3];
+
+    ret = (ret << 8) + buf[2];
+    ret = (ret << 8) + buf[1];
+    return (ret << 8) + buf[0];
+}
+
+static void send_msg_to_java(uint32_t typ, uint32_t len, const void *data)
+{
+    hal_hub_call_rx_msg_f(get_hub_info()->os_app_name, typ, len, data);
+}
+
+static int system_comms_handle_app_info_query_locked(bool start)
+{
+    if (start) {
+        mAppInfoReqInProgress = true;
+        mAppInfo = NULL;
+        mAppQueryIdx = 0;
+    }
+
+    uint8_t cmd[5] = {NANOHUB_QUERY_APPS, mAppQueryIdx, mAppQueryIdx >> 8, mAppQueryIdx >> 16, mAppQueryIdx >> 24};
+
+    return hal_hub_do_send_msg(mHostIfAppNameBuf, sizeof(cmd), cmd);
+}
+
+static int system_comms_send_app_info_to_java_locked(void)
+{
+    uint32_t infosSz;
+    struct hub_app_name_t *names = (struct hub_app_name_t*)calloc(1, sizeof(struct hub_app_name_t[mAppQueryIdx]));
+    struct mem_range_t *ranges = (struct mem_range_t*)calloc(1, sizeof(struct mem_range_t[mAppQueryIdx * 2]));
+    struct hub_app_info *infos = (struct hub_app_info*)calloc(1, infosSz = sizeof(struct hub_app_info[mAppQueryIdx]));
+    uint8_t *nameBufs = (uint8_t*)calloc(1, mAppQueryIdx * APP_NAME_LEN);
+    uint32_t i, j = 0;
+
+    if (names && ranges && infos && nameBufs) {
+
+        for (i = 0; i < mAppQueryIdx; i++) { //loop over apps
+
+            uint32_t startRange = j;
+
+            //set up name struct
+            names[i].app_name_len = APP_NAME_LEN;
+            names[i].app_name = nameBufs + i * APP_NAME_LEN;
+
+            //set up name itself
+            memcpy(nameBufs + i * APP_NAME_LEN, mAppInfo[i].name, APP_NAME_LEN);
+
+            //copy mem info
+            if (mAppInfo[i].flashUse != NANOHUB_MEM_SZ_UNKNOWN) {
+                ranges[j].type = HUB_MEM_TYPE_MAIN;
+                ranges[j].total_bytes = mAppInfo[i].flashUse;
+                j++;
+            }
+            if (mAppInfo[i].ramUse != NANOHUB_MEM_SZ_UNKNOWN) {
+                ranges[j].type = HUB_MEM_TYPE_RAM;
+                ranges[j].total_bytes = mAppInfo[i].ramUse;
+                j++;
+            }
+
+            //populate app info
+            infos[i].name = names + i;
+            infos[i].version = mAppInfo[i].version;
+            infos[i].num_mem_ranges = j - startRange;
+            infos[i].mem_usage = ranges + startRange;
+        }
+
+        //send
+        send_msg_to_java(CONTEXT_HUB_QUERY_APPS, infosSz, infos);
+    }
+
+    if(names)
+        free(names);
+
+    if(ranges)
+        free(ranges);
+
+    if (infos)
+        free(infos);
+
+    if (nameBufs)
+        free(nameBufs);
+
+    if (mAppInfo)
+        free(mAppInfo);
+    mAppInfo = NULL;
+
+    return 0;
+}
+
+static int system_comms_handle_rx_app_info(uint32_t len, const uint8_t *data)
+{
+    const struct NanohubAppInfo *i = (const struct NanohubAppInfo*)data;
+    int ret = 0;
+    void *tmp;
+
+    pthread_mutex_lock(&mLock);
+
+    if (!mAppInfoReqInProgress) {
+        ALOGW("Unexpected app_info packet RXed. dropping");
+        goto out;
+    }
+
+    if (len == sizeof(struct NanohubAppInfo)) { //proper sized reply is more data
+        tmp = (struct NanohubAppInfo*)realloc(mAppInfo, sizeof(struct NanohubAppInfo[mAppQueryIdx + 1]));
+        if (tmp) {
+            mAppInfo = tmp;
+            memcpy(mAppInfo[mAppQueryIdx].name, i->name, APP_NAME_LEN);
+            mAppInfo[mAppQueryIdx].version = leToHost32(i->version);
+            mAppInfo[mAppQueryIdx].flashUse = leToHost32(i->flashUse);
+            mAppInfo[mAppQueryIdx].ramUse = leToHost32(i->ramUse);
+            mAppQueryIdx++;
+
+            //query next, consider us done if that fails
+            if (!system_comms_handle_app_info_query_locked(false))
+                goto out;
+        }
+    }
+
+    //if we're here, we're done
+    mAppInfoReqInProgress = false;
+    ret = system_comms_send_app_info_to_java_locked();
+
+out:
+    pthread_mutex_unlock(&mLock);
+    return ret;
+}
+
+static int system_comms_handle_rx_mem_info(uint32_t len, const uint8_t *data)
+{
+    int ret = 0;
+
+    if (len != sizeof(struct NanohubMemInfo))
+        ALOGW("Mem info command reply is a weird size");
+    else {
+        const struct NanohubMemInfo *mi = (const struct NanohubMemInfo*)data;
+        struct mem_range_t ranges[4];
+        uint32_t nRanges = 0;
+
+        //calcualte each
+        struct mem_range_t rangeShared = {
+            .type = HUB_MEM_TYPE_MAIN,
+            .total_bytes = leToHost32(mi->sharedSz),
+            .free_bytes = leToHost32(mi->sharedSz) - leToHost32(mi->sharedUse),
+        };
+
+        struct mem_range_t rangeOs = {
+            .type = HUB_MEM_TYPE_OS,
+            .total_bytes = leToHost32(mi->osSz),
+            .free_bytes = leToHost32(mi->osSz) - leToHost32(mi->osUse),
+        };
+
+        struct mem_range_t rangeEe = {
+            .type = HUB_MEM_TYPE_EEDATA,
+            .total_bytes = leToHost32(mi->eeSz),
+            .free_bytes = leToHost32(mi->eeSz) - leToHost32(mi->eeUse),
+        };
+
+        struct mem_range_t rangeRam = {
+            .type = HUB_MEM_TYPE_RAM,
+            .total_bytes = leToHost32(mi->ramSz),
+            .free_bytes = leToHost32(mi->ramSz) - leToHost32(mi->ramUse),
+        };
+
+        //if each is valid, copy to output area
+        if (leToHost32(mi->sharedSz) != NANOHUB_MEM_SZ_UNKNOWN && leToHost32(mi->sharedUse) != NANOHUB_MEM_SZ_UNKNOWN)
+            ranges[nRanges++] = rangeShared;
+
+        if (leToHost32(mi->osSz) != NANOHUB_MEM_SZ_UNKNOWN && leToHost32(mi->osUse) != NANOHUB_MEM_SZ_UNKNOWN)
+            ranges[nRanges++] = rangeOs;
+
+        if (leToHost32(mi->eeSz) != NANOHUB_MEM_SZ_UNKNOWN && leToHost32(mi->eeUse) != NANOHUB_MEM_SZ_UNKNOWN)
+            ranges[nRanges++] = rangeEe;
+
+        if (leToHost32(mi->ramSz) != NANOHUB_MEM_SZ_UNKNOWN && leToHost32(mi->ramUse) != NANOHUB_MEM_SZ_UNKNOWN)
+            ranges[nRanges++] = rangeRam;
+
+        //send it out
+        send_msg_to_java(CONTEXT_HUB_QUERY_MEMORY, sizeof(struct mem_range_t[nRanges]), ranges);
+    }
+
+    return ret;
+}
+
+static int system_comms_handle_upload_piece_locked(void)
+{
+    //are we just starting?
+    if (!mUploadingStarted) {
+        uint8_t msg[6] = {NANOHUB_START_UPLOAD, mUploadingOs, mUploadLen, mUploadLen >> 8, mUploadLen >> 16, mUploadLen >> 24};
+
+        //TODO: future: RSA check here as an optimization
+
+        mUploadingStarted = true;
+        return hal_hub_do_send_msg(mHostIfAppNameBuf, sizeof(msg), msg);
+    }
+
+    //are we just finishing
+    else if (mUploadPos == mUploadLen) {
+        uint8_t msg = NANOHUB_FINISH_UPLOAD;
+
+        return hal_hub_do_send_msg(mHostIfAppNameBuf, 1, &msg);
+    }
+
+    //guess we're in the middle of it - upload NANOHUB_UPLOAD_CHUNK_SZ_MAX bytes or what's left, whichever is smaller
+    else {
+        uint32_t now = mUploadLen - mUploadPos;
+        uint8_t msg[NANOHUB_UPLOAD_CHUNK_SZ_MAX + 5] = {NANOHUB_CONT_UPLOAD, mUploadPos, mUploadPos >> 8, mUploadPos >> 16, mUploadPos >> 24};
+
+        if (now > NANOHUB_UPLOAD_CHUNK_SZ_MAX)
+            now = NANOHUB_UPLOAD_CHUNK_SZ_MAX;
+
+        memcpy(msg + 5, mUploadData + mUploadPos, now);
+        mUploadPos += now;
+
+        return hal_hub_do_send_msg(mHostIfAppNameBuf, now + 5, msg);
+    }
+}
+
+static int system_comms_handle_rx_upload_finish_locked(bool success)
+{
+    uint8_t ret = success ? 1 : 0;
+    uint8_t msg = NANOHUB_REBOOT;
+
+    send_msg_to_java(mUploadingOs ? CONTEXT_HUB_LOAD_OS : CONTEXT_HUB_LOAD_APP, 1, &ret);
+    free(mUploadData);
+    mUploadData = NULL;
+
+    return hal_hub_do_send_msg(mHostIfAppNameBuf, 1, &msg);
+}
+
+static int system_comms_handle_rx_upload_status(uint32_t len, const uint8_t *data, bool fini)
+{
+    int ret = 0;
+
+    pthread_mutex_lock(&mLock);
+
+    if (len != 1 || !*data) {
+        ALOGW("msg len is bad");
+        ret = system_comms_handle_rx_upload_finish_locked(false);
+        goto out;
+    }
+
+    if (fini)
+        ret = system_comms_handle_rx_upload_finish_locked(true);
+    else
+        ret = system_comms_handle_upload_piece_locked();
+
+out:
+    pthread_mutex_unlock(&mLock);
+    return ret;
+}
+
+static int system_comms_handle_rx_upload_start(uint32_t len, const uint8_t *data)
+{
+    return system_comms_handle_rx_upload_status(len, data, false);
+}
+
+static int system_comms_handle_rx_upload_cont(uint32_t len, const uint8_t *data)
+{
+    return system_comms_handle_rx_upload_status(len, data, false);
+}
+
+static int system_comms_handle_rx_upload_fini(uint32_t len, const uint8_t *data)
+{
+    return system_comms_handle_rx_upload_status(len, data, true);
+}
+
+static int system_comms_handle_get_rsa_keys_locked(void)
+{
+    uint8_t msg[5] = {NANOHUB_QUERY_RSA_KEYS, mRsaOffset, mRsaOffset >> 8, mRsaOffset >> 16, mRsaOffset >> 24};
+
+    return hal_hub_do_send_msg(mHostIfAppNameBuf, sizeof(msg), msg);
+}
+
+static int system_comms_handle_rx_rsa_keys(uint32_t len, const uint8_t *data)
+{
+    int ret = 0;
+
+    pthread_mutex_lock(&mLock);
+
+    if (mHaveRsaKeys) {
+        ALOGW("Got RSA keys when they were not expected - dropping");
+        goto out;
+    }
+
+    if (len) { // more key material has arived
+        void *tmp = realloc(mRsaKeys, mRsaOffset + len);
+
+        if (data) { //append and ask for more
+            mRsaKeys = tmp;
+            memcpy(mRsaKeys + mRsaOffset, data, len);
+            mRsaOffset += len;
+            if (!system_comms_handle_get_rsa_keys_locked())
+                goto out;
+        }
+    }
+
+    //if we're here, we're done getting rsa keys - continue whatever upload started all this
+    mHaveRsaKeys = true;
+
+    ret = system_comms_handle_upload_piece_locked();
+
+out:
+    pthread_mutex_unlock(&mLock);
+    return ret;
+}
+
+int system_comms_handle_rx(const void *name, uint32_t len, const void *dataP)
+{
+    const uint8_t *data = (const uint8_t*)dataP;
+    uint8_t msgType;
+
+    //we only care for messages from HostIF
+    if (memcmp(name, mHostIfAppNameBuf, APP_NAME_LEN))
+        return 0;
+
+    //they must all be at least 1 byte long
+    if (len < 1)
+        return -EINVAL;
+
+    len--;
+    switch (msgType = *data++) {
+
+    case NANOHUB_EXT_APPS_ON:
+        if (len != 1)
+            return -EINVAL;
+        send_msg_to_java(CONTEXT_HUB_APPS_ENABLE, 1, data);
+        break;
+
+    case NANOHUB_EXT_APPS_OFF:
+        if (len != 1)
+            return -EINVAL;
+        send_msg_to_java(CONTEXT_HUB_APPS_DISABLE, 1, data);
+        break;
+
+    case NANOHUB_EXT_APP_DELETE:
+        if (len != 1)
+            return -EINVAL;
+        send_msg_to_java(CONTEXT_HUB_UNLOAD_APP, 1, data);
+        break;
+
+    case NANOHUB_QUERY_APPS:
+        return system_comms_handle_rx_app_info(len, data);
+
+    case NANOHUB_QUERY_MEMINFO:
+        return system_comms_handle_rx_mem_info(len, data);
+
+    case NANOHUB_QUERY_RSA_KEYS:
+        return system_comms_handle_rx_rsa_keys(len, data);
+
+    case NANOHUB_START_UPLOAD:
+        return system_comms_handle_rx_upload_start(len, data);
+
+    case NANOHUB_CONT_UPLOAD:
+        return system_comms_handle_rx_upload_cont(len, data);
+
+    case NANOHUB_FINISH_UPLOAD:
+        return system_comms_handle_rx_upload_fini(len, data);
+
+    case NANOHUB_REBOOT:
+        ALOGI("Weird - we got a %u-byte ACK for reboot - ok then, moving on...", len);
+        break;
+
+    dfault:
+        ALOGW("Unknown nanohub reply packet %u ( + %u bytes of data) - dropped", msgType, len);
+        break;
+    }
+
+    return 1;
+}
+
+static int system_comms_handle_upload(const void *data, uint32_t len, bool isOs)
+{
+    int ret;
+
+    pthread_mutex_lock(&mLock);
+
+    if (mUploadData) {    // no concurrent uploads
+        ret = -EBUSY;
+        ALOGW("Refusing to upload while another upload is ongoing");
+        goto out;
+    }
+
+    mUploadData = malloc(len);
+    if (!mUploadData) {
+        ret = -ENOMEM;
+        ALOGW("OOPS OOM");
+        goto out;
+    }
+
+    memcpy(mUploadData, data, len);
+    mUploadLen = len;
+    mUploadPos = 0;
+    mUploadingOs = isOs;
+    mUploadingStarted = false;
+
+    if (!mHaveRsaKeys) { //no keys -> ask for them
+        mRsaOffset = 0;
+        ret = system_comms_handle_get_rsa_keys_locked();
+        goto out;
+    }
+
+    ret = system_comms_handle_upload_piece_locked();
+
+out:
+    pthread_mutex_unlock(&mLock);
+    return ret;
+}
+
+static int system_comms_handle_app_info_query(bool start)
+{
+    int ret;
+
+    pthread_mutex_lock(&mLock);
+
+    ret = mAppInfoReqInProgress ? -EBUSY : system_comms_handle_app_info_query_locked(start);
+
+    pthread_mutex_unlock(&mLock);
+    return ret;
+}
+
+int system_comms_handle_tx(const struct hub_message_t *outMsg)
+{
+    uint8_t cmd[APP_NAME_LEN + 1], len = 1;
+    struct hub_message_t tx = {.app = &mHostIfAppName, .message_len = 1, .message = cmd, };
+
+    switch (outMsg->message_type) {
+
+    case CONTEXT_HUB_APPS_ENABLE:
+        cmd[0] = NANOHUB_EXT_APPS_ON;
+        break;
+
+    case CONTEXT_HUB_APPS_DISABLE:
+        cmd[0] = NANOHUB_EXT_APPS_OFF;
+        break;
+
+    case CONTEXT_HUB_LOAD_APP:
+        return system_comms_handle_upload(outMsg->message, outMsg->message_len, false);
+
+    case CONTEXT_HUB_UNLOAD_APP:
+        if (outMsg->message_len != APP_NAME_LEN)
+            return -EINVAL;
+
+        cmd[0] = NANOHUB_EXT_APP_DELETE;
+        memcpy(cmd + 1, outMsg->message, APP_NAME_LEN);
+        len = 1 + APP_NAME_LEN;
+        break;
+
+    case CONTEXT_HUB_QUERY_APPS:
+        return system_comms_handle_app_info_query(true);
+
+    case CONTEXT_HUB_QUERY_MEMORY:
+        cmd[0] = NANOHUB_QUERY_MEMINFO;
+        break;
+
+    case CONTEXT_HUB_LOAD_OS:
+        return system_comms_handle_upload(outMsg->message, outMsg->message_len, true);
+
+    default:
+        ALOGW("Unknown os message type %u\n", outMsg->message_type);
+        return -EINVAL;
+    }
+
+    return hal_hub_do_send_msg(mHostIfAppNameBuf, len, cmd);
+}
+
+
+
+
+
diff --git a/HAL/system_comms.h b/HAL/system_comms.h
new file mode 100644
index 0000000..cb26691
--- /dev/null
+++ b/HAL/system_comms.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, Google. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef _NANOHUB_SYSTEM_COMMS_H_
+#define _NANOHUB_SYSTEM_COMMS_H_
+
+#include <hardware/context_hub.h>
+#include "nanohubhal.h"
+
+//rx: return 1 if handled, 0 if not handled, else error
+int system_comms_handle_rx(const void *name, uint32_t len, const void *data);
+int system_comms_handle_tx(const struct hub_message_t *outMsg);
+
+
+//messages to the HostIf nanoapp & their replies (mesages and replies both begin with u8 message_type)
+#define NANOHUB_EXT_APPS_ON        0 // () -> (char success)
+#define NANOHUB_EXT_APPS_OFF       1 // () -> (char success)
+#define NANOHUB_EXT_APP_DELETE     2 // (u64 name) -> (char success)    //idempotent
+#define NANOHUB_QUERY_MEMINFO      3 // () -> (mem_info)
+#define NANOHUB_QUERY_APPS         4 // (u32 idxStart) -> (app_info[idxStart] OR EMPTY IF NO MORE)
+#define NANOHUB_QUERY_RSA_KEYS     5 // (u32 byteOffset) -> (u8 data[1 or more bytes] OR EMPTY IF NO MORE)
+#define NANOHUB_START_UPLOAD       6 // (char isOs, u32 totalLenToTx) -> (char success)
+#define NANOHUB_CONT_UPLOAD        7 // (u32 offset, u8 data[]) -> (char success)
+#define NANOHUB_FINISH_UPLOAD      8 // () -> (char success)
+#define NANOHUB_REBOOT             9 // () -> (char success)
+
+
+
+#define NANOHUB_UPLOAD_CHUNK_SZ_MAX 64
+#define NANOHUB_MEM_SZ_UNKNOWN      0xFFFFFFFFUL
+
+struct NanohubAppInfo {
+    uint8_t name[APP_NAME_LEN];
+    uint32_t version, flashUse, ramUse;
+};
+
+struct NanohubMemInfo {
+    //sizes
+    uint32_t flashSz, blSz, osSz, sharedSz, eeSz;
+    uint32_t ramSz;
+
+    //use
+    uint32_t blUse, osUse, sharedUse, eeUse;
+    uint32_t ramUse;
+};
+
+
+
+#endif
+