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*)∈
+ 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
+