Home | History | Annotate | Download | only in test
      1 #define LOG_TAG "NanohubHAL_Test"
      2 
      3 #include <cstddef>
      4 #include <cstdint>
      5 #include <functional>
      6 #include <iostream>
      7 #include <iomanip>
      8 #include <map>
      9 #include <memory>
     10 #include <cstddef>
     11 #include <cstdint>
     12 #include <mutex>
     13 #include <vector>
     14 
     15 #include <dlfcn.h>
     16 #include <signal.h>
     17 #include <unistd.h>
     18 
     19 #include <log/log.h>
     20 #include <sys/endian.h>
     21 
     22 #include <hardware/hardware.h>
     23 #include <hardware/context_hub.h>
     24 #include <nanohub/nanoapp.h>
     25 
     26 inline std::ostream &operator << (std::ostream &os, const hub_app_name_t &appId)
     27 {
     28     char vendor[6];
     29     __be64 beAppId = htobe64(appId.id);
     30     uint32_t seqId = appId.id & NANOAPP_VENDOR_ALL_APPS;
     31 
     32     std::ios::fmtflags f(os.flags());
     33     memcpy(vendor, (void*)&beAppId, sizeof(vendor) - 1);
     34     vendor[sizeof(vendor) - 1] = 0;
     35     if (strlen(vendor) == 5)
     36         os << vendor << ", " << std::hex << std::setw(6)  << seqId;
     37     else
     38         os << "#" << std::hex << appId.id;
     39     os.flags(f);
     40 
     41     return os;
     42 }
     43 
     44 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)
     45 {
     46     const uint8_t *p = static_cast<const uint8_t *>(data);
     47     os << pfx << ": [ID=" << appId << "; SZ=" << std::dec << len;
     48     if (evtId)
     49         os << "; EVT=" << std::hex << evtId;
     50     os << "]:" << std::hex;
     51     for (size_t i = 0; i < len; ++i) {
     52         os << " "  << std::setfill('0') << std::setw(2) << (unsigned int)p[i];
     53     }
     54     if (status) {
     55         os << "; status=" << status << " [" << std::setfill('0') << std::setw(8) << status << "]";
     56     }
     57 }
     58 
     59 class CHub
     60 {
     61 public:
     62     class IClient {
     63     public:
     64         virtual void onMessage(const hub_message_t &msg) = 0;
     65         virtual ~IClient(){}
     66     };
     67     class Client : IClient {
     68         CHub *mParent;
     69         const context_hub_t *mHub;
     70         std::function<void(const hub_message_t &)> mHandler;
     71 
     72     public:
     73         explicit Client(const context_hub_t *hub, CHub *parent) {
     74             mHub = hub;
     75             mParent = parent;
     76         }
     77         ~Client() = default;
     78 
     79         void setHandler(std::function<void(const hub_message_t &)> handler) {
     80             mHandler = handler;
     81         }
     82         void onMessage(const hub_message_t &msg) {
     83             if ((bool)mHandler == true) {
     84                 mHandler(msg);
     85             }
     86         }
     87         void sendMessage(const hub_message_t &msg) {
     88             mParent->sendMessage(mHub->hub_id, msg);
     89         }
     90         void sendToSystem(uint32_t typ, void *data, uint32_t len) {
     91             mParent->sendMessage(mHub->hub_id, mHub->os_app_name, typ, data, len);
     92         }
     93         void sendToApp(hub_app_name_t app, void *data, uint32_t len) {
     94             mParent->sendMessage(mHub->hub_id, app, 0, data, len);
     95         }
     96         const hub_app_name_t getSystemApp() const { return mHub->os_app_name; }
     97     };
     98 private:
     99     static int contextHubCallback(uint32_t id, const hub_message_t *msg, void *cookie)
    100     {
    101         CHub *hub = static_cast<CHub*>(cookie);
    102         hub->onMessage(id, msg);
    103         return 0;
    104     }
    105 
    106     CHub() {
    107         hw_get_module(CONTEXT_HUB_MODULE_ID, (const hw_module_t **)&mMod);
    108         if (!mMod)
    109             return;
    110         mMod->subscribe_messages(0, contextHubCallback, this);
    111         mHubArraySize = mMod->get_hubs(mMod, &mHubArray);
    112         for (size_t i = 0; i < mHubArraySize; ++i) {
    113             auto item = &mHubArray[i];
    114             mHubs[item->hub_id] = std::unique_ptr<Client>(new Client(item, this));
    115         }
    116     }
    117 
    118     ~CHub() {
    119         // destroy all clients first
    120         mHubs.clear();
    121         if (mMod != nullptr) {
    122             // unregister from HAL services
    123             mMod->subscribe_messages(0, nullptr, nullptr);
    124             // there is no hw_put_module(); release HAL fd directly
    125             dlclose(mMod->common.dso);
    126             mMod = nullptr;
    127         }
    128     }
    129 
    130     void onMessage(uint32_t hubId, const hub_message_t *msg) {
    131         Client *cli = getClientById(hubId);
    132         if (cli != nullptr && msg != nullptr) {
    133             cli->onMessage(*msg);
    134         }
    135     }
    136 
    137     int sendMessage(uint32_t id, const hub_message_t &msg) {
    138         return  (mMod != nullptr) ? mMod->send_message(id, &msg) : 0;
    139     }
    140 
    141     int sendMessage(uint32_t id, hub_app_name_t app, uint32_t typ, void *data, uint32_t len) {
    142         hub_message_t msg = {
    143             .app_name = app,
    144             .message_type = typ,
    145             .message = data,
    146             .message_len = len,
    147         };
    148         return sendMessage(id, msg);
    149     }
    150 
    151     Client *getClientById(size_t id) { return mHubs.count(id) ? mHubs[id].get() : nullptr; }
    152 
    153     context_hub_module_t *mMod = nullptr;
    154     const context_hub_t  *mHubArray = nullptr;
    155     size_t                mHubArraySize = 0;
    156     std::map <size_t, std::unique_ptr<Client> > mHubs;
    157 
    158 public:
    159     static CHub *instantiate() {
    160         static CHub instance;
    161 
    162         return &instance;
    163     }
    164     Client *getClientByIndex(size_t idx) {
    165         return idx < mHubArraySize && mHubArray != nullptr ?
    166                getClientById(mHubArray[idx].hub_id) : nullptr;
    167     }
    168 };
    169 
    170 class NanoClient
    171 {
    172     CHub::Client *mClient;
    173     std::ostream &log;
    174     std::mutex lock;
    175     void onMessage(const hub_message_t &msg){
    176         std::lock_guard<std::mutex> _l(lock);
    177         dumpBuffer(log, "Rx", msg.app_name, msg.message_type, msg.message, msg.message_len, 0);
    178         log << std::endl;
    179     }
    180 public:
    181     NanoClient(int idx = 0) : log(std::clog) {
    182         CHub *hub = CHub::instantiate();
    183         mClient = hub->getClientByIndex(idx);
    184         if (mClient)
    185             mClient->setHandler(std::function<void(const hub_message_t&)>([this] (const hub_message_t&msg) { onMessage(msg); }));
    186     }
    187     void sendMessage(const hub_message_t &msg) { mClient->sendMessage(msg); }
    188     void sendMessageToSystem(uint32_t cmd, void * data, size_t dataSize) {
    189         hub_message_t msg;
    190         msg.message = data;
    191         msg.message_len = dataSize;
    192         msg.message_type = cmd;
    193         msg.app_name = mClient->getSystemApp();
    194         {
    195             std::lock_guard<std::mutex> _l(lock);
    196             dumpBuffer(log, "TxCmd", msg.app_name, msg.message_type, msg.message, msg.message_len, 0);
    197             log << std::endl;
    198         }
    199         sendMessage(msg);
    200     }
    201     void sendMessageToApp(const hub_app_name_t appName, void * data, size_t dataSize, uint32_t msg_type) {
    202         hub_message_t msg;
    203         msg.message = data;
    204         msg.message_len = dataSize;
    205         msg.message_type = msg_type;
    206         msg.app_name = appName;
    207         {
    208             std::lock_guard<std::mutex> _l(lock);
    209             dumpBuffer(log, "TxMsg", msg.app_name, msg.message_type, msg.message, msg.message_len, 0);
    210             log << std::endl;
    211         }
    212         sendMessage(msg);
    213     }
    214 };
    215 
    216 void sigint_handler(int)
    217 {
    218     exit(0);
    219 }
    220 
    221 int main(int argc, char *argv[])
    222 {
    223     int opt;
    224     long cmd = 0;
    225     unsigned long msg = 0;
    226     uint64_t appId = 0;
    227     const char *appFileName = NULL;
    228     uint32_t fileSize = 0;
    229 
    230     while((opt = getopt(argc, argv, "c:i:a:m:")) != -1) {
    231         char *end = NULL;
    232         switch(opt) {
    233         case 'm':
    234             msg = strtoul(optarg, &end, 16);
    235             break;
    236         case 'c':
    237             cmd = strtol(optarg, &end, 10);
    238             break;
    239         case 'i':
    240             appId = strtoull(optarg, &end, 16);
    241             break;
    242         case 'a':
    243             appFileName = optarg;
    244             break;
    245         }
    246         if (end && *end != '\0') {
    247             std::clog << "Invalid argument: " << optarg << std::endl;
    248             return 1;
    249         }
    250     }
    251 
    252     NanoClient cli;
    253 
    254     std::vector<uint8_t> data;
    255     for (int i = optind; i < argc; ++i) {
    256         char *end;
    257         unsigned long v = strtoul(argv[i], &end, 16);
    258         // ignore any garbage after parsed hex value;
    259         // ignore the fact it may not fit 1 byte;
    260         // we're not testing user's ability to pass valid data,
    261         // we're testing the system ability to transfer data.
    262         data.push_back(v);
    263     }
    264     if (msg != 0) {
    265         // send APP message
    266         const hub_app_name_t app_name = { .id = appId };
    267         cli.sendMessageToApp(app_name, data.data(), data.size(), msg);
    268     } else {
    269         // send HAL command
    270         switch(cmd) {
    271         case CONTEXT_HUB_APPS_ENABLE:
    272         {
    273             apps_enable_request_t req;
    274             req.app_name.id = appId;
    275             cli.sendMessageToSystem(CONTEXT_HUB_APPS_ENABLE, &req, sizeof(req));
    276         }
    277         break;
    278         case CONTEXT_HUB_APPS_DISABLE:
    279         {
    280             apps_disable_request_t req;
    281             req.app_name.id = appId;
    282             cli.sendMessageToSystem(CONTEXT_HUB_APPS_DISABLE, &req, sizeof(req));
    283         }
    284         break;
    285         case CONTEXT_HUB_LOAD_APP:
    286         {
    287             load_app_request_t *req = NULL;
    288             if (appFileName)
    289                 req = (load_app_request_t *)loadFile(appFileName, &fileSize);
    290             if (!req || fileSize < sizeof(*req) || req->app_binary.magic != NANOAPP_MAGIC) {
    291                 std::clog << "Invalid nanoapp image: " <<
    292                              (appFileName != nullptr ? appFileName : "<NULL>") << std::endl;
    293                 return 1;
    294             }
    295             cli.sendMessageToSystem(CONTEXT_HUB_LOAD_APP, req, fileSize);
    296             free(req);
    297         }
    298         break;
    299         case CONTEXT_HUB_UNLOAD_APP:
    300         {
    301             unload_app_request_t req;
    302             req.app_name.id = appId;
    303             cli.sendMessageToSystem(CONTEXT_HUB_UNLOAD_APP, &req, sizeof(req));
    304         }
    305         break;
    306         case CONTEXT_HUB_QUERY_APPS:
    307         {
    308             query_apps_request_t req;
    309             req.app_name.id = appId;
    310             cli.sendMessageToSystem(CONTEXT_HUB_QUERY_APPS, &req, sizeof(req));
    311         }
    312         break;
    313         case CONTEXT_HUB_QUERY_MEMORY:
    314         default:
    315             std::clog << "Unknown command: " << cmd << std::endl;
    316             break;
    317         }
    318     }
    319 
    320     signal(SIGINT, sigint_handler);
    321     while(1) {
    322         sleep(1);
    323     }
    324     return 0;
    325 }
    326