#define LOG_TAG "NanohubHAL_Test" #include <cstddef> #include <cstdint> #include <functional> #include <iostream> #include <iomanip> #include <map> #include <memory> #include <cstddef> #include <cstdint> #include <mutex> #include <vector> #include <dlfcn.h> #include <signal.h> #include <unistd.h> #include <log/log.h> #include <sys/endian.h> #include <hardware/hardware.h> #include <hardware/context_hub.h> #include <nanohub/nanoapp.h> inline std::ostream &operator << (std::ostream &os, const hub_app_name_t &appId) { char vendor[6]; __be64 beAppId = htobe64(appId.id); uint32_t seqId = appId.id & NANOAPP_VENDOR_ALL_APPS; std::ios::fmtflags f(os.flags()); memcpy(vendor, (void*)&beAppId, sizeof(vendor) - 1); vendor[sizeof(vendor) - 1] = 0; if (strlen(vendor) == 5) os << vendor << ", " << std::hex << std::setw(6) << seqId; else os << "#" << std::hex << appId.id; os.flags(f); return os; } void dumpBuffer(std::ostream &os, const char *pfx, const hub_app_name_t &appId, uint32_t evtId, const void *data, size_t len, int status) { const uint8_t *p = static_cast<const uint8_t *>(data); os << pfx << ": [ID=" << appId << "; SZ=" << std::dec << len; if (evtId) os << "; EVT=" << std::hex << evtId; os << "]:" << std::hex; for (size_t i = 0; i < len; ++i) { os << " " << std::setfill('0') << std::setw(2) << (unsigned int)p[i]; } if (status) { os << "; status=" << status << " [" << std::setfill('0') << std::setw(8) << status << "]"; } } class CHub { public: class IClient { public: virtual void onMessage(const hub_message_t &msg) = 0; virtual ~IClient(){} }; class Client : IClient { CHub *mParent; const context_hub_t *mHub; std::function<void(const hub_message_t &)> mHandler; public: explicit Client(const context_hub_t *hub, CHub *parent) { mHub = hub; mParent = parent; } ~Client() = default; void setHandler(std::function<void(const hub_message_t &)> handler) { mHandler = handler; } void onMessage(const hub_message_t &msg) { if ((bool)mHandler == true) { mHandler(msg); } } void sendMessage(const hub_message_t &msg) { mParent->sendMessage(mHub->hub_id, msg); } void sendToSystem(uint32_t typ, void *data, uint32_t len) { mParent->sendMessage(mHub->hub_id, mHub->os_app_name, typ, data, len); } void sendToApp(hub_app_name_t app, void *data, uint32_t len) { mParent->sendMessage(mHub->hub_id, app, 0, data, len); } const hub_app_name_t getSystemApp() const { return mHub->os_app_name; } }; private: static int contextHubCallback(uint32_t id, const hub_message_t *msg, void *cookie) { CHub *hub = static_cast<CHub*>(cookie); hub->onMessage(id, msg); return 0; } CHub() { hw_get_module(CONTEXT_HUB_MODULE_ID, (const hw_module_t **)&mMod); if (!mMod) return; mMod->subscribe_messages(0, contextHubCallback, this); mHubArraySize = mMod->get_hubs(mMod, &mHubArray); for (size_t i = 0; i < mHubArraySize; ++i) { auto item = &mHubArray[i]; mHubs[item->hub_id] = std::unique_ptr<Client>(new Client(item, this)); } } ~CHub() { // destroy all clients first mHubs.clear(); if (mMod != nullptr) { // unregister from HAL services mMod->subscribe_messages(0, nullptr, nullptr); // there is no hw_put_module(); release HAL fd directly dlclose(mMod->common.dso); mMod = nullptr; } } void onMessage(uint32_t hubId, const hub_message_t *msg) { Client *cli = getClientById(hubId); if (cli != nullptr && msg != nullptr) { cli->onMessage(*msg); } } int sendMessage(uint32_t id, const hub_message_t &msg) { return (mMod != nullptr) ? mMod->send_message(id, &msg) : 0; } int sendMessage(uint32_t id, hub_app_name_t app, uint32_t typ, void *data, uint32_t len) { hub_message_t msg = { .app_name = app, .message_type = typ, .message = data, .message_len = len, }; return sendMessage(id, msg); } Client *getClientById(size_t id) { return mHubs.count(id) ? mHubs[id].get() : nullptr; } context_hub_module_t *mMod = nullptr; const context_hub_t *mHubArray = nullptr; size_t mHubArraySize = 0; std::map <size_t, std::unique_ptr<Client> > mHubs; public: static CHub *instantiate() { static CHub instance; return &instance; } Client *getClientByIndex(size_t idx) { return idx < mHubArraySize && mHubArray != nullptr ? getClientById(mHubArray[idx].hub_id) : nullptr; } }; class NanoClient { CHub::Client *mClient; std::ostream &log; std::mutex lock; void onMessage(const hub_message_t &msg){ std::lock_guard<std::mutex> _l(lock); dumpBuffer(log, "Rx", msg.app_name, msg.message_type, msg.message, msg.message_len, 0); log << std::endl; } public: NanoClient(int idx = 0) : log(std::clog) { CHub *hub = CHub::instantiate(); mClient = hub->getClientByIndex(idx); if (mClient) mClient->setHandler(std::function<void(const hub_message_t&)>([this] (const hub_message_t&msg) { onMessage(msg); })); } void sendMessage(const hub_message_t &msg) { mClient->sendMessage(msg); } void sendMessageToSystem(uint32_t cmd, void * data, size_t dataSize) { hub_message_t msg; msg.message = data; msg.message_len = dataSize; msg.message_type = cmd; msg.app_name = mClient->getSystemApp(); { std::lock_guard<std::mutex> _l(lock); dumpBuffer(log, "TxCmd", msg.app_name, msg.message_type, msg.message, msg.message_len, 0); log << std::endl; } sendMessage(msg); } void sendMessageToApp(const hub_app_name_t appName, void * data, size_t dataSize, uint32_t msg_type) { hub_message_t msg; msg.message = data; msg.message_len = dataSize; msg.message_type = msg_type; msg.app_name = appName; { std::lock_guard<std::mutex> _l(lock); dumpBuffer(log, "TxMsg", msg.app_name, msg.message_type, msg.message, msg.message_len, 0); log << std::endl; } sendMessage(msg); } }; void sigint_handler(int) { exit(0); } int main(int argc, char *argv[]) { int opt; long cmd = 0; unsigned long msg = 0; uint64_t appId = 0; const char *appFileName = NULL; uint32_t fileSize = 0; while((opt = getopt(argc, argv, "c:i:a:m:")) != -1) { char *end = NULL; switch(opt) { case 'm': msg = strtoul(optarg, &end, 16); break; case 'c': cmd = strtol(optarg, &end, 10); break; case 'i': appId = strtoull(optarg, &end, 16); break; case 'a': appFileName = optarg; break; } if (end && *end != '\0') { std::clog << "Invalid argument: " << optarg << std::endl; return 1; } } NanoClient cli; std::vector<uint8_t> data; for (int i = optind; i < argc; ++i) { char *end; unsigned long v = strtoul(argv[i], &end, 16); // ignore any garbage after parsed hex value; // ignore the fact it may not fit 1 byte; // we're not testing user's ability to pass valid data, // we're testing the system ability to transfer data. data.push_back(v); } if (msg != 0) { // send APP message const hub_app_name_t app_name = { .id = appId }; cli.sendMessageToApp(app_name, data.data(), data.size(), msg); } else { // send HAL command switch(cmd) { case CONTEXT_HUB_APPS_ENABLE: { apps_enable_request_t req; req.app_name.id = appId; cli.sendMessageToSystem(CONTEXT_HUB_APPS_ENABLE, &req, sizeof(req)); } break; case CONTEXT_HUB_APPS_DISABLE: { apps_disable_request_t req; req.app_name.id = appId; cli.sendMessageToSystem(CONTEXT_HUB_APPS_DISABLE, &req, sizeof(req)); } break; case CONTEXT_HUB_LOAD_APP: { load_app_request_t *req = NULL; if (appFileName) req = (load_app_request_t *)loadFile(appFileName, &fileSize); if (!req || fileSize < sizeof(*req) || req->app_binary.magic != NANOAPP_MAGIC) { std::clog << "Invalid nanoapp image: " << (appFileName != nullptr ? appFileName : "<NULL>") << std::endl; return 1; } cli.sendMessageToSystem(CONTEXT_HUB_LOAD_APP, req, fileSize); free(req); } break; case CONTEXT_HUB_UNLOAD_APP: { unload_app_request_t req; req.app_name.id = appId; cli.sendMessageToSystem(CONTEXT_HUB_UNLOAD_APP, &req, sizeof(req)); } break; case CONTEXT_HUB_QUERY_APPS: { query_apps_request_t req; req.app_name.id = appId; cli.sendMessageToSystem(CONTEXT_HUB_QUERY_APPS, &req, sizeof(req)); } break; case CONTEXT_HUB_QUERY_MEMORY: default: std::clog << "Unknown command: " << cmd << std::endl; break; } } signal(SIGINT, sigint_handler); while(1) { sleep(1); } return 0; }