1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef _NANOHUB_HAL_H_
18 #define _NANOHUB_HAL_H_
19 
20 #include <mutex>
21 #include <thread>
22 #include <list>
23 
24 #include <hardware/context_hub.h>
25 
26 #include <nanohub/nanohub.h>
27 
28 //as per protocol
29 #define MAX_RX_PACKET               128
30 #define MAX_TX_PACKET               128
31 #define APP_FROM_HOST_EVENT_ID      0x000000F8
32 #define APP_FROM_HOST_CHRE_EVENT_ID 0x000000F9
33 
34 #define ENDPOINT_UNSPECIFIED        0xFFFE
35 #define ENDPOINT_BROADCAST          0xFFFF
36 
37 namespace android {
38 
39 namespace nanohub {
40 
41 void dumpBuffer(const char *pfx, const hub_app_name_t &appId, uint32_t evtId, uint16_t endpoint, const void *data, size_t len, int status = 0);
42 
43 struct nano_message_chre {
44     HostMsgHdrChre hdr;
45     uint8_t data[MAX_RX_PACKET];
46 } __attribute__((packed));
47 
48 struct nano_message_raw {
49     HostMsgHdr hdr;
50     uint8_t data[MAX_RX_PACKET];
51 } __attribute__((packed));
52 
53 union nano_message {
54     struct nano_message_chre chre;
55     struct nano_message_raw raw;
56 } __attribute__((packed));
57 
58 class HubMessage : public hub_message_t {
59     std::unique_ptr<uint8_t> data_;
60 public:
61     uint32_t message_transaction_id;
62     uint16_t message_endpoint;
63     HubMessage(const HubMessage &other) = delete;
64     HubMessage &operator = (const HubMessage &other) = delete;
65 
HubMessage(const hub_app_name_t * name,uint32_t typ,uint32_t transaction_id,uint16_t endpoint,const void * data,uint32_t len)66     HubMessage(const hub_app_name_t *name, uint32_t typ, uint32_t transaction_id,
67             uint16_t endpoint, const void *data, uint32_t len) {
68         app_name = *name;
69         message_type = typ;
70         message_len = len;
71         message = data;
72         message_transaction_id = transaction_id;
73         message_endpoint = endpoint;
74         if (len > 0 && data != nullptr) {
75             data_ = std::unique_ptr<uint8_t>(new uint8_t[len]);
76             memcpy(data_.get(), data, len);
77             message = data_.get();
78         }
79     }
80 
HubMessage(const hub_app_name_t * name,uint32_t typ,uint16_t endpoint,const void * data,uint32_t len)81     HubMessage(const hub_app_name_t *name, uint32_t typ, uint16_t endpoint, const void *data,
82             uint32_t len) : HubMessage(name, typ, 0, endpoint, data, len) { }
83 
HubMessage(const hub_message_t * msg,uint32_t transaction_id,uint16_t endpoint)84     HubMessage(const hub_message_t *msg, uint32_t transaction_id, uint16_t endpoint) {
85         app_name = msg->app_name;
86         message_type = msg->message_type;
87         message_len = msg->message_len;
88         message = msg->message;
89         message_transaction_id = transaction_id;
90         message_endpoint = endpoint;
91         if (msg->message_len > 0 && msg->message != nullptr) {
92             data_ = std::unique_ptr<uint8_t>(new uint8_t[msg->message_len]);
93             memcpy(data_.get(), msg->message, msg->message_len);
94             message = data_.get();
95         }
96     }
97 
HubMessage(HubMessage && other)98     HubMessage(HubMessage &&other) {
99         *this = (HubMessage &&)other;
100     }
101 
102     HubMessage &operator = (HubMessage &&other) {
103         *static_cast<hub_message_t *>(this) = static_cast<hub_message_t>(other);
104         message_transaction_id = other.message_transaction_id;
105         message_endpoint = other.message_endpoint;
106         data_ = std::move(other.data_);
107         other.message = nullptr;
108         other.message_len = 0;
109         return *this;
110     }
111 };
112 
113 typedef int Contexthub_callback(uint32_t hub_id, const HubMessage &rxed_msg, void *cookie);
114 
115 class NanoHub {
116     std::mutex mLock;
117     bool mAppQuit;
118     std::mutex mAppTxLock;
119     std::condition_variable mAppTxCond;
120     std::list<HubMessage> mAppTxQueue;
121     std::thread mPollThread;
122     std::thread mAppThread;
123     Contexthub_callback *mMsgCbkFunc;
124     int mThreadClosingPipe[2];
125     int mFd; // [0] is read end
126     void * mMsgCbkData;
127 
128     NanoHub();
129     ~NanoHub();
130 
reset()131     void reset() {
132         mThreadClosingPipe[0] = -1;
133         mThreadClosingPipe[1] = -1;
134         mFd = -1;
135         mMsgCbkData = nullptr;
136         mMsgCbkFunc = nullptr;
137         mAppQuit = false;
138     }
139 
140     void* runAppTx();
141     void* runDeviceRx();
142 
143     int openHub();
144     int closeHub();
145 
hubInstance()146     static NanoHub *hubInstance() {
147         static NanoHub theHub;
148         return &theHub;
149     }
150 
151     int doSubscribeMessages(uint32_t hub_id, Contexthub_callback *cbk, void *cookie);
152     int doSendToNanohub(uint32_t hub_id, const hub_message_t *msg,
153             uint32_t transaction_id, uint16_t endpoint);
154     int doSendToDevice(const hub_app_name_t name, const void *data, uint32_t len,
155             uint32_t messageType = 0, uint16_t endpoint = ENDPOINT_UNSPECIFIED);
156     void doSendToApp(HubMessage &&msg);
157     void doDumpAppInfo(std::string &result);
158 
159     static constexpr unsigned int FL_MESSAGE_TRACING = 1;
160 
161     unsigned int mFlags = 0;
162 
163 public:
164 
165     // debugging interface
166 
messageTracingEnabled()167     static bool messageTracingEnabled() {
168         return hubInstance()->mFlags & FL_MESSAGE_TRACING;
169     }
getDebugFlags()170     static unsigned int getDebugFlags() {
171         return hubInstance()->mFlags;
172     }
setDebugFlags(unsigned int flags)173     static void setDebugFlags(unsigned int flags) {
174         hubInstance()->mFlags = flags;
175     }
dumpAppInfo(std::string & result)176     static void dumpAppInfo(std::string &result) {
177         hubInstance()->doDumpAppInfo(result);
178     }
179 
180     // messaging interface
181 
182     // define callback to invoke for APP messages
subscribeMessages(uint32_t hub_id,Contexthub_callback * cbk,void * cookie)183     static int subscribeMessages(uint32_t hub_id, Contexthub_callback *cbk, void *cookie) {
184         return hubInstance()->doSubscribeMessages(hub_id, cbk, cookie);
185     }
186     // all messages from APP go here
sendToNanohub(uint32_t hub_id,const hub_message_t * msg,uint32_t transaction_id,uint16_t endpoint)187     static int sendToNanohub(uint32_t hub_id, const hub_message_t *msg,
188             uint32_t transaction_id, uint16_t endpoint) {
189         return hubInstance()->doSendToNanohub(hub_id, msg, transaction_id, endpoint);
190     }
191     // passes message to kernel driver directly
sendToDevice(const hub_app_name_t * name,const void * data,uint32_t len,uint32_t transactionId)192     static int sendToDevice(const hub_app_name_t *name, const void *data, uint32_t len,
193             uint32_t transactionId) {
194         return hubInstance()->doSendToDevice(*name, data, len, transactionId, ENDPOINT_UNSPECIFIED);
195     }
196     // passes message to APP via callback
sendToApp(HubMessage && msg)197     static void sendToApp(HubMessage &&msg) {
198         hubInstance()->doSendToApp((HubMessage &&)msg);
199     }
200 };
201 
202 }; // namespace nanohub
203 
204 }; // namespace android
205 
206 #endif
207