Branch data Line data Source code
1 : : #include <mutex>
2 : : #include <condition_variable>
3 : : #include <queue>
4 : : #include <chrono>
5 : : #include <napi.h>
6 : : #include <lora_comms_int.h>
7 : :
8 : : using namespace std::chrono_literals;
9 : :
10 : : class LoRaComms : public Napi::ObjectWrap<LoRaComms>
11 : : {
12 : : public:
13 : : LoRaComms(const Napi::CallbackInfo& info);
14 : :
15 : : static Napi::Object Initialize(Napi::Env env, Napi::Object exports);
16 : :
17 : : private:
18 : : static void Start(const Napi::CallbackInfo& info);
19 : : static void Stop(const Napi::CallbackInfo& info);
20 : : static void Reset(const Napi::CallbackInfo& info);
21 : :
22 : : static void RecvFrom(const Napi::CallbackInfo& info);
23 : : static void SendTo(const Napi::CallbackInfo& info);
24 : :
25 : : static void SetGWSendHWM(const Napi::CallbackInfo& info);
26 : : static void SetGWSendTimeout(const Napi::CallbackInfo& info);
27 : : static void SetGWRecvTimeout(const Napi::CallbackInfo& info);
28 : :
29 : : static void StartLogging(const Napi::CallbackInfo& info);
30 : : static void StopLogging(const Napi::CallbackInfo& info);
31 : : static void ResetLogging(const Napi::CallbackInfo& info);
32 : : static void GetLogInfoMessage(const Napi::CallbackInfo& info);
33 : : static void GetLogErrorMessage(const Napi::CallbackInfo& info);
34 : : static void SetLogWriteHWM(const Napi::CallbackInfo& info);
35 : : static void SetLogWriteTimeout(const Napi::CallbackInfo& info);
36 : : static void SetLogMaxMessageSize(const Napi::CallbackInfo& info);
37 : : static Napi::Value GetLogMaxMessageSize(const Napi::CallbackInfo& info);
38 : :
39 : : static struct timeval TimeVal(const Napi::CallbackInfo& info,
40 : : const uint32_t arg);
41 : : static enum comm_link CommLink(const Napi::CallbackInfo& info,
42 : : const uint32_t arg);
43 : : };
44 : :
45 : : // LoRaComms has no instance methods so we never create an instance
46 : : //LCOV_EXCL_START
47 : : LoRaComms::LoRaComms(const Napi::CallbackInfo& info) :
48 : : Napi::ObjectWrap<LoRaComms>(info)
49 : : {
50 : : }
51 : : //LCOV_EXCL_STOP
52 : :
53 : 57 : Napi::Error ErrnoError(const Napi::Env& env, const int errnum)
54 : : {
55 : 57 : char buf[1024] = {0};
56 : 57 : auto errmsg = strerror_r(errnum, buf, sizeof(buf));
57 : : static_assert(std::is_same<decltype(errmsg), char*>::value,
58 : : "strerror_r must return char*");
59 : 114 : Napi::Error err = Napi::Error::New(env, errmsg ? errmsg : std::to_string(errnum));
60 : 57 : err.Set("errno", Napi::Number::New(env, errnum));
61 : 114 : return err;
62 : : // Bug in lcov/gcc: For some reason the closing brace below is uncovered
63 : : // even though the return above is covered.
64 : : //LCOV_EXCL_START
65 : : }
66 : : //LCOV_EXCL_STOP
67 : :
68 : : class StartAsyncWorker : public Napi::AsyncWorker
69 : : {
70 : : public:
71 : 16 : StartAsyncWorker(const Napi::Function& callback,
72 : 16 : const Napi::String& cfg_dir) :
73 : : Napi::AsyncWorker(callback),
74 : 16 : cfg_dir(cfg_dir.Utf8Value())
75 : : {
76 : 16 : }
77 : :
78 : : protected:
79 : 16 : void Execute() override
80 : : {
81 : 16 : if (start(cfg_dir.empty() ? nullptr : cfg_dir.c_str()) != EXIT_SUCCESS)
82 : : {
83 : 1 : SetError("failed");
84 : : }
85 : :
86 : 16 : close_log_queues(false);
87 : 16 : }
88 : :
89 : : private:
90 : : std::string cfg_dir;
91 : : };
92 : :
93 : 16 : void LoRaComms::Start(const Napi::CallbackInfo& info)
94 : : {
95 : 16 : (new StartAsyncWorker(info[1].As<Napi::Function>(),
96 : 16 : info[0].As<Napi::String>()))
97 : 16 : ->Queue();
98 : 16 : }
99 : :
100 : 15 : void LoRaComms::Stop(const Napi::CallbackInfo& info)
101 : : {
102 : 15 : stop();
103 : 15 : }
104 : :
105 : 15 : void LoRaComms::Reset(const Napi::CallbackInfo& info)
106 : : {
107 : 15 : reset();
108 : 15 : }
109 : :
110 : : class CommsAsyncWorker : public Napi::AsyncWorker
111 : : {
112 : : public:
113 : 111 : CommsAsyncWorker(const Napi::Function& callback,
114 : : const Napi::Buffer<uint8_t>& buffer,
115 : 111 : const struct timeval& timeout) :
116 : : Napi::AsyncWorker(callback),
117 : 222 : buf(buffer.Data()),
118 : 111 : len(buffer.Length()),
119 : 111 : timeout(timeout),
120 : 222 : buffer_ref(Napi::Persistent(buffer))
121 : : {
122 : 111 : }
123 : :
124 : : // Two versions of this are present in coverage, ~CommsAsyncWorker and
125 : : // ~CommsAsyncWorker.2. Only the latter gets called which leaves the former
126 : : // uncovered. The child classes' destructors are called (both versions).
127 : : //LCOV_EXCL_START
128 : : ~CommsAsyncWorker()
129 : : {
130 : : }
131 : : //LCOV_EXCL_STOP
132 : :
133 : : protected:
134 : : virtual ssize_t Communicate() = 0;
135 : :
136 : 111 : void Execute() override
137 : : {
138 : 111 : result = Communicate();
139 : 111 : if (result < 0)
140 : : {
141 : 57 : errnum = errno;
142 : : }
143 : 111 : }
144 : :
145 : 111 : void OnOK() override
146 : : {
147 : 111 : Napi::Env env = Env();
148 : 444 : Callback().MakeCallback(
149 : 111 : Receiver().Value(),
150 : : {
151 : 168 : result < 0 ? ErrnoError(env, errnum).Value() : env.Null(),
152 : 222 : Napi::Number::New(env, result)
153 : : });
154 : 111 : }
155 : :
156 : : void *buf;
157 : : size_t len;
158 : : struct timeval timeout;
159 : :
160 : : private:
161 : : Napi::Reference<Napi::Buffer<uint8_t>> buffer_ref;
162 : : ssize_t result;
163 : : int errnum;
164 : : };
165 : :
166 : : class LinkAsyncWorker : public CommsAsyncWorker
167 : : {
168 : : public:
169 : 65 : LinkAsyncWorker(const Napi::Function& callback,
170 : : const int link,
171 : : const Napi::Buffer<uint8_t>& buffer,
172 : 65 : const struct timeval& timeout) :
173 : : CommsAsyncWorker(callback, buffer, timeout),
174 : 65 : link(static_cast<enum comm_link>(link))
175 : : {
176 : 65 : }
177 : :
178 : : // Two versions of this are present in coverage, ~LinkAsyncWorker and
179 : : // ~LinkAsyncWorker.2. Only the latter gets called which leaves the former
180 : : // uncovered. The child classes' destructors are called (both versions).
181 : : //LCOV_EXCL_START
182 : : ~LinkAsyncWorker()
183 : : {
184 : : }
185 : : //LCOV_EXCL_STOP
186 : :
187 : : protected:
188 : : enum comm_link link;
189 : : };
190 : :
191 : : class RecvFromAsyncWorker : public LinkAsyncWorker
192 : : {
193 : : public:
194 : 37 : RecvFromAsyncWorker(const Napi::Function& callback,
195 : : const int link,
196 : : const Napi::Buffer<uint8_t>& buffer,
197 : 37 : const struct timeval& timeout) :
198 : 37 : LinkAsyncWorker(callback, link, buffer, timeout)
199 : : {
200 : 37 : }
201 : :
202 : : protected:
203 : 37 : ssize_t Communicate() override
204 : : {
205 : 37 : return recv_from(link, buf, len, &timeout);
206 : : }
207 : : };
208 : :
209 : 37 : void LoRaComms::RecvFrom(const Napi::CallbackInfo& info)
210 : : {
211 : 37 : (new RecvFromAsyncWorker(info[4].As<Napi::Function>(),
212 : 37 : info[0].As<Napi::Number>(),
213 : 37 : info[1].As<Napi::Buffer<uint8_t>>(),
214 : 74 : TimeVal(info, 2)))
215 : 37 : ->Queue();
216 : 37 : }
217 : :
218 : : class SendToAsyncWorker : public LinkAsyncWorker
219 : : {
220 : : public:
221 : 28 : SendToAsyncWorker(const Napi::Function& callback,
222 : : const int link,
223 : : const Napi::Buffer<uint8_t>& buffer,
224 : : ssize_t hwm,
225 : 28 : const struct timeval& timeout) :
226 : : LinkAsyncWorker(callback, link, buffer, timeout),
227 : 28 : hwm(hwm)
228 : : {
229 : 28 : }
230 : :
231 : : protected:
232 : 28 : ssize_t Communicate() override
233 : : {
234 : 28 : return send_to(link, buf, len, hwm, &timeout);
235 : : }
236 : :
237 : : private:
238 : : ssize_t hwm;
239 : : };
240 : :
241 : 28 : void LoRaComms::SendTo(const Napi::CallbackInfo& info)
242 : : {
243 : 28 : (new SendToAsyncWorker(info[5].As<Napi::Function>(),
244 : 28 : info[0].As<Napi::Number>(),
245 : 28 : info[1].As<Napi::Buffer<uint8_t>>(),
246 : 28 : info[2].As<Napi::Number>(),
247 : 56 : TimeVal(info, 3)))
248 : 28 : ->Queue();
249 : 28 : }
250 : :
251 : 2 : void LoRaComms::SetGWSendHWM(const Napi::CallbackInfo& info)
252 : : {
253 : 2 : set_gw_send_hwm(CommLink(info, 0), info[1].As<Napi::Number>());
254 : 2 : }
255 : :
256 : 2 : void LoRaComms::SetGWSendTimeout(const Napi::CallbackInfo& info)
257 : : {
258 : 2 : struct timeval tv = TimeVal(info, 1);
259 : 2 : set_gw_send_timeout(CommLink(info, 0), &tv);
260 : 2 : }
261 : :
262 : 2 : void LoRaComms::SetGWRecvTimeout(const Napi::CallbackInfo& info)
263 : : {
264 : 2 : struct timeval tv = TimeVal(info, 1);
265 : 2 : set_gw_recv_timeout(CommLink(info, 0), &tv);
266 : 2 : }
267 : :
268 : 16 : void LoRaComms::StartLogging(const Napi::CallbackInfo& info)
269 : : {
270 : 16 : set_logger(log_to_queues);
271 : 16 : }
272 : :
273 : 1 : void LoRaComms::StopLogging(const Napi::CallbackInfo& info)
274 : : {
275 : 1 : set_logger(nullptr);
276 : 1 : close_log_queues(true);
277 : 1 : }
278 : :
279 : 15 : void LoRaComms::ResetLogging(const Napi::CallbackInfo& info)
280 : : {
281 : 15 : reset_log_queues();
282 : 15 : }
283 : :
284 : : class LogAsyncWorker : public CommsAsyncWorker
285 : : {
286 : : public:
287 : 46 : LogAsyncWorker(const Napi::Function& callback,
288 : : get_log_message_fn get_log_message,
289 : : const Napi::Buffer<uint8_t>& buffer,
290 : 46 : const struct timeval& timeout) :
291 : : CommsAsyncWorker(callback, buffer, timeout),
292 : 46 : get_log_message(get_log_message)
293 : : {
294 : 46 : }
295 : :
296 : : protected:
297 : 46 : ssize_t Communicate() override
298 : : {
299 : 46 : return get_log_message(static_cast<char*>(buf), len, &timeout);
300 : : }
301 : :
302 : : private:
303 : : get_log_message_fn get_log_message;
304 : : };
305 : :
306 : 29 : void LoRaComms::GetLogInfoMessage(const Napi::CallbackInfo& info)
307 : : {
308 : 29 : (new LogAsyncWorker(info[3].As<Napi::Function>(),
309 : : get_log_info_message,
310 : 29 : info[0].As<Napi::Buffer<uint8_t>>(),
311 : 29 : TimeVal(info, 1)))
312 : 29 : ->Queue();
313 : 29 : }
314 : :
315 : 17 : void LoRaComms::GetLogErrorMessage(const Napi::CallbackInfo& info)
316 : : {
317 : 17 : (new LogAsyncWorker(info[3].As<Napi::Function>(),
318 : : get_log_error_message,
319 : 17 : info[0].As<Napi::Buffer<uint8_t>>(),
320 : 17 : TimeVal(info, 1)))
321 : 17 : ->Queue();
322 : 17 : }
323 : :
324 : 1 : void LoRaComms::SetLogWriteHWM(const Napi::CallbackInfo& info)
325 : : {
326 : 1 : set_log_write_hwm(info[0].As<Napi::Number>());
327 : 1 : }
328 : :
329 : 1 : void LoRaComms::SetLogWriteTimeout(const Napi::CallbackInfo& info)
330 : : {
331 : 1 : struct timeval tv = TimeVal(info, 0);
332 : 1 : set_log_write_timeout(&tv);
333 : 1 : }
334 : :
335 : 1 : void LoRaComms::SetLogMaxMessageSize(const Napi::CallbackInfo& info)
336 : : {
337 : 1 : set_log_max_msg_size(static_cast<uint32_t>(info[0].As<Napi::Number>()));
338 : 1 : }
339 : :
340 : 47 : Napi::Value LoRaComms::GetLogMaxMessageSize(const Napi::CallbackInfo& info)
341 : : {
342 : 47 : return Napi::Number::New(info.Env(), get_log_max_msg_size());
343 : : }
344 : :
345 : : typedef std::conditional<sizeof(time_t) == 8, int64_t, int32_t>::type tm_t;
346 : :
347 : 116 : struct timeval LoRaComms::TimeVal(const Napi::CallbackInfo& info,
348 : : const uint32_t arg)
349 : : {
350 : : struct timeval tv;
351 : 116 : tv.tv_sec = static_cast<tm_t>(info[arg].As<Napi::Number>());
352 : 116 : tv.tv_usec = static_cast<tm_t>(info[arg+1].As<Napi::Number>());
353 : 116 : return tv;
354 : : }
355 : :
356 : 6 : enum comm_link LoRaComms::CommLink(const Napi::CallbackInfo& info,
357 : : const uint32_t arg)
358 : : {
359 : 6 : return static_cast<enum comm_link>(info[arg].As<Napi::Number>().Int32Value());
360 : : }
361 : :
362 : 1 : Napi::Object LoRaComms::Initialize(Napi::Env env, Napi::Object exports)
363 : : {
364 : 1 : exports.Set("LoRaComms", DefineClass(env, "LoRaComms",
365 : : {
366 : 1 : StaticMethod<&Start>("start"),
367 : 1 : StaticMethod<&Stop>("stop"),
368 : 1 : StaticMethod<&Reset>("reset"),
369 : :
370 : 1 : StaticMethod<&RecvFrom>("recv_from"),
371 : 1 : StaticMethod<&SendTo>("send_to"),
372 : :
373 : 1 : StaticValue("uplink", Napi::Number::New(env, uplink)),
374 : 1 : StaticValue("downlink", Napi::Number::New(env, downlink)),
375 : :
376 : 1 : StaticMethod<&SetGWSendHWM>("set_gw_send_hwm"),
377 : 1 : StaticMethod<&SetGWSendTimeout>("set_gw_send_timeout"),
378 : 1 : StaticMethod<&SetGWRecvTimeout>("set_gw_recv_timeout"),
379 : :
380 : 1 : StaticMethod<&StartLogging>("start_logging"),
381 : 1 : StaticMethod<&StopLogging>("stop_logging"),
382 : 1 : StaticMethod<&ResetLogging>("reset_logging"),
383 : 1 : StaticMethod<&GetLogInfoMessage>("get_log_info_message"),
384 : 1 : StaticMethod<&GetLogErrorMessage>("get_log_error_message"),
385 : 1 : StaticMethod<&SetLogWriteHWM>("set_log_write_hwm"),
386 : 1 : StaticMethod<&SetLogWriteTimeout>("set_log_write_timeout"),
387 : 1 : StaticMethod<&SetLogMaxMessageSize>("set_log_max_msg_size"),
388 : 1 : StaticMethod<&GetLogMaxMessageSize>("get_log_max_msg_size"),
389 : :
390 : 1 : StaticValue("EBADF", Napi::Number::New(env, EBADF)),
391 : 1 : StaticValue("EAGAIN", Napi::Number::New(env, EAGAIN)),
392 : 1 : StaticValue("EINVAL", Napi::Number::New(env, EINVAL)),
393 : :
394 : 1 : StaticValue("recv_from_buflen", Napi::Number::New(env, recv_from_buflen)),
395 : 1 : StaticValue("send_to_buflen", Napi::Number::New(env, send_to_buflen))
396 : : }));
397 : :
398 : 1 : return exports;
399 : : }
400 : :
401 : 1 : Napi::Object Initialize(Napi::Env env, Napi::Object exports)
402 : : {
403 : 1 : return LoRaComms::Initialize(env, exports);
404 : : }
405 : :
406 : 2 : NODE_API_MODULE(lora_comms, Initialize)
|