hamlib 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -1
- package/binding.gyp +1 -0
- package/index.d.ts +112 -4
- package/lib/index.js +145 -6
- package/lib/index.mjs +3 -3
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/libhamlib.4.dylib +0 -0
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/darwin-x64/libhamlib.4.dylib +0 -0
- package/prebuilds/darwin-x64/node.napi.node +0 -0
- package/prebuilds/linux-arm64/libhamlib.so +0 -0
- package/prebuilds/linux-arm64/libhamlib.so.4 +0 -0
- package/prebuilds/linux-arm64/libhamlib.so.4.0.7 +0 -0
- package/prebuilds/linux-arm64/node.napi.node +0 -0
- package/prebuilds/linux-x64/libhamlib.so +0 -0
- package/prebuilds/linux-x64/libhamlib.so.4 +0 -0
- package/prebuilds/linux-x64/libhamlib.so.4.0.7 +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/prebuilds/win32-x64/hamlib_shim.dll +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/src/addon.cpp +5 -1
- package/src/hamlib.cpp +54 -12
- package/src/node_rotator.cpp +1309 -0
- package/src/node_rotator.h +62 -0
- package/src/shim/hamlib_shim.c +403 -0
- package/src/shim/hamlib_shim.h +117 -2
|
@@ -0,0 +1,1309 @@
|
|
|
1
|
+
#include "node_rotator.h"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cstdio>
|
|
5
|
+
#include <cstring>
|
|
6
|
+
#include <limits>
|
|
7
|
+
#include <string>
|
|
8
|
+
#include <vector>
|
|
9
|
+
|
|
10
|
+
#define CHECK_ROT_VALID() \
|
|
11
|
+
do { \
|
|
12
|
+
if (!rotator_instance_ || !rotator_instance_->my_rot) { \
|
|
13
|
+
result_code_ = SHIM_RIG_EINVAL; \
|
|
14
|
+
error_message_ = "Rotator is not initialized or has been destroyed"; \
|
|
15
|
+
return; \
|
|
16
|
+
} \
|
|
17
|
+
} while (0)
|
|
18
|
+
|
|
19
|
+
#define RETURN_NULL_IF_ROT_HANDLE_INVALID() \
|
|
20
|
+
do { \
|
|
21
|
+
if (!my_rot) { \
|
|
22
|
+
Napi::Error::New(env, "Rotator is not initialized or has been destroyed").ThrowAsJavaScriptException(); \
|
|
23
|
+
return env.Null(); \
|
|
24
|
+
} \
|
|
25
|
+
} while (0)
|
|
26
|
+
|
|
27
|
+
namespace {
|
|
28
|
+
|
|
29
|
+
struct RotatorListData {
|
|
30
|
+
std::vector<Napi::Object> rotators;
|
|
31
|
+
Napi::Env env;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
struct RotatorConfigFieldDescriptor {
|
|
35
|
+
int token;
|
|
36
|
+
std::string name;
|
|
37
|
+
std::string label;
|
|
38
|
+
std::string tooltip;
|
|
39
|
+
std::string defaultValue;
|
|
40
|
+
int type;
|
|
41
|
+
double numericMin;
|
|
42
|
+
double numericMax;
|
|
43
|
+
double numericStep;
|
|
44
|
+
std::vector<std::string> options;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
struct RotatorConfigSchemaData {
|
|
48
|
+
std::vector<RotatorConfigFieldDescriptor> fields;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const char* publicConfTypeName(int type) {
|
|
52
|
+
switch (type) {
|
|
53
|
+
case 0:
|
|
54
|
+
return "string";
|
|
55
|
+
case 1:
|
|
56
|
+
return "combo";
|
|
57
|
+
case 2:
|
|
58
|
+
return "numeric";
|
|
59
|
+
case 3:
|
|
60
|
+
return "checkbutton";
|
|
61
|
+
case 4:
|
|
62
|
+
return "button";
|
|
63
|
+
case 5:
|
|
64
|
+
return "binary";
|
|
65
|
+
case 6:
|
|
66
|
+
return "int";
|
|
67
|
+
default:
|
|
68
|
+
return "unknown";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
bool hasPositiveValue(int value) {
|
|
73
|
+
return value > 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Napi::Array buildStatusArray(Napi::Env env, int mask) {
|
|
77
|
+
static const int kStatuses[] = {
|
|
78
|
+
SHIM_ROT_STATUS_BUSY,
|
|
79
|
+
SHIM_ROT_STATUS_MOVING,
|
|
80
|
+
SHIM_ROT_STATUS_MOVING_AZ,
|
|
81
|
+
SHIM_ROT_STATUS_MOVING_LEFT,
|
|
82
|
+
SHIM_ROT_STATUS_MOVING_RIGHT,
|
|
83
|
+
SHIM_ROT_STATUS_MOVING_EL,
|
|
84
|
+
SHIM_ROT_STATUS_MOVING_UP,
|
|
85
|
+
SHIM_ROT_STATUS_MOVING_DOWN,
|
|
86
|
+
SHIM_ROT_STATUS_LIMIT_UP,
|
|
87
|
+
SHIM_ROT_STATUS_LIMIT_DOWN,
|
|
88
|
+
SHIM_ROT_STATUS_LIMIT_LEFT,
|
|
89
|
+
SHIM_ROT_STATUS_LIMIT_RIGHT,
|
|
90
|
+
SHIM_ROT_STATUS_OVERLAP_UP,
|
|
91
|
+
SHIM_ROT_STATUS_OVERLAP_DOWN,
|
|
92
|
+
SHIM_ROT_STATUS_OVERLAP_LEFT,
|
|
93
|
+
SHIM_ROT_STATUS_OVERLAP_RIGHT,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
Napi::Array result = Napi::Array::New(env);
|
|
97
|
+
uint32_t index = 0;
|
|
98
|
+
for (int status : kStatuses) {
|
|
99
|
+
if ((mask & status) == status) {
|
|
100
|
+
const char* name = shim_rot_strstatus(status);
|
|
101
|
+
if (name && name[0] != '\0') {
|
|
102
|
+
result[index++] = Napi::String::New(env, name);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
Napi::Array buildSettingArrayFromMask(
|
|
110
|
+
Napi::Env env,
|
|
111
|
+
uint64_t mask,
|
|
112
|
+
const char* (*name_fn)(uint64_t)) {
|
|
113
|
+
Napi::Array result = Napi::Array::New(env);
|
|
114
|
+
uint32_t index = 0;
|
|
115
|
+
|
|
116
|
+
for (uint64_t bit = 1; bit != 0; bit <<= 1) {
|
|
117
|
+
if ((mask & bit) == 0) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const char* name = name_fn(bit);
|
|
122
|
+
if (name && name[0] != '\0') {
|
|
123
|
+
result[index++] = Napi::String::New(env, name);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
int parseRotDirection(Napi::Env env, const Napi::Value& value) {
|
|
131
|
+
if (value.IsNumber()) {
|
|
132
|
+
return value.As<Napi::Number>().Int32Value();
|
|
133
|
+
}
|
|
134
|
+
if (!value.IsString()) {
|
|
135
|
+
Napi::TypeError::New(env, "Expected direction as string or number").ThrowAsJavaScriptException();
|
|
136
|
+
return std::numeric_limits<int>::min();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const std::string direction = value.As<Napi::String>().Utf8Value();
|
|
140
|
+
if (direction == "UP") return SHIM_ROT_MOVE_UP;
|
|
141
|
+
if (direction == "DOWN") return SHIM_ROT_MOVE_DOWN;
|
|
142
|
+
if (direction == "LEFT" || direction == "CCW") return SHIM_ROT_MOVE_LEFT;
|
|
143
|
+
if (direction == "RIGHT" || direction == "CW") return SHIM_ROT_MOVE_RIGHT;
|
|
144
|
+
if (direction == "UP_LEFT" || direction == "UP_CCW") return SHIM_ROT_MOVE_UP_LEFT;
|
|
145
|
+
if (direction == "UP_RIGHT" || direction == "UP_CW") return SHIM_ROT_MOVE_UP_RIGHT;
|
|
146
|
+
if (direction == "DOWN_LEFT" || direction == "DOWN_CCW") return SHIM_ROT_MOVE_DOWN_LEFT;
|
|
147
|
+
if (direction == "DOWN_RIGHT" || direction == "DOWN_CW") return SHIM_ROT_MOVE_DOWN_RIGHT;
|
|
148
|
+
|
|
149
|
+
Napi::TypeError::New(env, "Invalid rotator direction").ThrowAsJavaScriptException();
|
|
150
|
+
return std::numeric_limits<int>::min();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
int parseRotReset(Napi::Env env, const Napi::Value& value) {
|
|
154
|
+
if (value.IsNumber()) {
|
|
155
|
+
return value.As<Napi::Number>().Int32Value();
|
|
156
|
+
}
|
|
157
|
+
if (!value.IsString()) {
|
|
158
|
+
Napi::TypeError::New(env, "Expected reset type as string or number").ThrowAsJavaScriptException();
|
|
159
|
+
return std::numeric_limits<int>::min();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const std::string reset = value.As<Napi::String>().Utf8Value();
|
|
163
|
+
if (reset == "ALL") return SHIM_ROT_RESET_ALL;
|
|
164
|
+
|
|
165
|
+
Napi::TypeError::New(env, "Invalid rotator reset type").ThrowAsJavaScriptException();
|
|
166
|
+
return std::numeric_limits<int>::min();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
uint64_t parseRotLevel(Napi::Env env, const Napi::Value& value) {
|
|
170
|
+
if (!value.IsString()) {
|
|
171
|
+
Napi::TypeError::New(env, "Expected level name as string").ThrowAsJavaScriptException();
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
const std::string name = value.As<Napi::String>().Utf8Value();
|
|
175
|
+
const uint64_t level = shim_rot_parse_level(name.c_str());
|
|
176
|
+
if (level == 0) {
|
|
177
|
+
Napi::Error::New(env, "Invalid rotator level: " + name).ThrowAsJavaScriptException();
|
|
178
|
+
}
|
|
179
|
+
return level;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
uint64_t parseRotFunc(Napi::Env env, const Napi::Value& value) {
|
|
183
|
+
if (!value.IsString()) {
|
|
184
|
+
Napi::TypeError::New(env, "Expected function name as string").ThrowAsJavaScriptException();
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
const std::string name = value.As<Napi::String>().Utf8Value();
|
|
188
|
+
const uint64_t func = shim_rot_parse_func(name.c_str());
|
|
189
|
+
if (func == 0) {
|
|
190
|
+
Napi::Error::New(env, "Invalid rotator function: " + name).ThrowAsJavaScriptException();
|
|
191
|
+
}
|
|
192
|
+
return func;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
uint64_t parseRotParm(Napi::Env env, const Napi::Value& value) {
|
|
196
|
+
if (!value.IsString()) {
|
|
197
|
+
Napi::TypeError::New(env, "Expected parameter name as string").ThrowAsJavaScriptException();
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
const std::string name = value.As<Napi::String>().Utf8Value();
|
|
201
|
+
const uint64_t parm = shim_rot_parse_parm(name.c_str());
|
|
202
|
+
if (parm == 0) {
|
|
203
|
+
Napi::Error::New(env, "Invalid rotator parameter: " + name).ThrowAsJavaScriptException();
|
|
204
|
+
}
|
|
205
|
+
return parm;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
} // namespace
|
|
209
|
+
|
|
210
|
+
class RotatorAsyncWorker : public Napi::AsyncWorker {
|
|
211
|
+
public:
|
|
212
|
+
RotatorAsyncWorker(Napi::Env env, NodeRotator* rotator_instance)
|
|
213
|
+
: Napi::AsyncWorker(env),
|
|
214
|
+
rotator_instance_(rotator_instance),
|
|
215
|
+
result_code_(0),
|
|
216
|
+
deferred_(Napi::Promise::Deferred::New(env)) {}
|
|
217
|
+
|
|
218
|
+
Napi::Promise GetPromise() { return deferred_.Promise(); }
|
|
219
|
+
|
|
220
|
+
protected:
|
|
221
|
+
NodeRotator* rotator_instance_;
|
|
222
|
+
int result_code_;
|
|
223
|
+
std::string error_message_;
|
|
224
|
+
Napi::Promise::Deferred deferred_;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
Napi::FunctionReference NodeRotator::constructor;
|
|
228
|
+
|
|
229
|
+
class RotatorOpenAsyncWorker : public RotatorAsyncWorker {
|
|
230
|
+
public:
|
|
231
|
+
RotatorOpenAsyncWorker(Napi::Env env, NodeRotator* rotator_instance)
|
|
232
|
+
: RotatorAsyncWorker(env, rotator_instance) {}
|
|
233
|
+
|
|
234
|
+
void Execute() override {
|
|
235
|
+
CHECK_ROT_VALID();
|
|
236
|
+
result_code_ = shim_rot_open(rotator_instance_->my_rot);
|
|
237
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
238
|
+
error_message_ = shim_rigerror(result_code_);
|
|
239
|
+
} else {
|
|
240
|
+
rotator_instance_->rot_is_open = true;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
void OnOK() override {
|
|
245
|
+
if (!error_message_.empty()) {
|
|
246
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
class RotatorCloseAsyncWorker : public RotatorAsyncWorker {
|
|
254
|
+
public:
|
|
255
|
+
RotatorCloseAsyncWorker(Napi::Env env, NodeRotator* rotator_instance)
|
|
256
|
+
: RotatorAsyncWorker(env, rotator_instance) {}
|
|
257
|
+
|
|
258
|
+
void Execute() override {
|
|
259
|
+
CHECK_ROT_VALID();
|
|
260
|
+
result_code_ = shim_rot_close(rotator_instance_->my_rot);
|
|
261
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
262
|
+
error_message_ = shim_rigerror(result_code_);
|
|
263
|
+
} else {
|
|
264
|
+
rotator_instance_->rot_is_open = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
void OnOK() override {
|
|
269
|
+
if (!error_message_.empty()) {
|
|
270
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
class RotatorDestroyAsyncWorker : public RotatorAsyncWorker {
|
|
278
|
+
public:
|
|
279
|
+
RotatorDestroyAsyncWorker(Napi::Env env, NodeRotator* rotator_instance)
|
|
280
|
+
: RotatorAsyncWorker(env, rotator_instance) {}
|
|
281
|
+
|
|
282
|
+
void Execute() override {
|
|
283
|
+
CHECK_ROT_VALID();
|
|
284
|
+
if (rotator_instance_->rot_is_open) {
|
|
285
|
+
shim_rot_close(rotator_instance_->my_rot);
|
|
286
|
+
rotator_instance_->rot_is_open = false;
|
|
287
|
+
}
|
|
288
|
+
result_code_ = shim_rot_cleanup(rotator_instance_->my_rot);
|
|
289
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
290
|
+
error_message_ = shim_rigerror(result_code_);
|
|
291
|
+
} else {
|
|
292
|
+
rotator_instance_->my_rot = nullptr;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
void OnOK() override {
|
|
297
|
+
if (!error_message_.empty()) {
|
|
298
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
class RotatorSetPositionAsyncWorker : public RotatorAsyncWorker {
|
|
306
|
+
public:
|
|
307
|
+
RotatorSetPositionAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, double azimuth, double elevation)
|
|
308
|
+
: RotatorAsyncWorker(env, rotator_instance), azimuth_(azimuth), elevation_(elevation) {}
|
|
309
|
+
|
|
310
|
+
void Execute() override {
|
|
311
|
+
CHECK_ROT_VALID();
|
|
312
|
+
result_code_ = shim_rot_set_position(rotator_instance_->my_rot, azimuth_, elevation_);
|
|
313
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
314
|
+
error_message_ = shim_rigerror(result_code_);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
void OnOK() override {
|
|
319
|
+
if (!error_message_.empty()) {
|
|
320
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private:
|
|
327
|
+
double azimuth_;
|
|
328
|
+
double elevation_;
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
class RotatorGetPositionAsyncWorker : public RotatorAsyncWorker {
|
|
332
|
+
public:
|
|
333
|
+
RotatorGetPositionAsyncWorker(Napi::Env env, NodeRotator* rotator_instance)
|
|
334
|
+
: RotatorAsyncWorker(env, rotator_instance), azimuth_(0), elevation_(0) {}
|
|
335
|
+
|
|
336
|
+
void Execute() override {
|
|
337
|
+
CHECK_ROT_VALID();
|
|
338
|
+
result_code_ = shim_rot_get_position(rotator_instance_->my_rot, &azimuth_, &elevation_);
|
|
339
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
340
|
+
error_message_ = shim_rigerror(result_code_);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
void OnOK() override {
|
|
345
|
+
if (!error_message_.empty()) {
|
|
346
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
Napi::Object result = Napi::Object::New(Env());
|
|
350
|
+
result.Set("azimuth", Napi::Number::New(Env(), azimuth_));
|
|
351
|
+
result.Set("elevation", Napi::Number::New(Env(), elevation_));
|
|
352
|
+
deferred_.Resolve(result);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
private:
|
|
356
|
+
double azimuth_;
|
|
357
|
+
double elevation_;
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
class RotatorMoveAsyncWorker : public RotatorAsyncWorker {
|
|
361
|
+
public:
|
|
362
|
+
RotatorMoveAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, int direction, int speed)
|
|
363
|
+
: RotatorAsyncWorker(env, rotator_instance), direction_(direction), speed_(speed) {}
|
|
364
|
+
|
|
365
|
+
void Execute() override {
|
|
366
|
+
CHECK_ROT_VALID();
|
|
367
|
+
result_code_ = shim_rot_move(rotator_instance_->my_rot, direction_, speed_);
|
|
368
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
369
|
+
error_message_ = shim_rigerror(result_code_);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
void OnOK() override {
|
|
374
|
+
if (!error_message_.empty()) {
|
|
375
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private:
|
|
382
|
+
int direction_;
|
|
383
|
+
int speed_;
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
class RotatorSimpleAsyncWorker : public RotatorAsyncWorker {
|
|
387
|
+
public:
|
|
388
|
+
typedef int (*OpFn)(hamlib_shim_handle_t);
|
|
389
|
+
|
|
390
|
+
RotatorSimpleAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, OpFn fn)
|
|
391
|
+
: RotatorAsyncWorker(env, rotator_instance), fn_(fn) {}
|
|
392
|
+
|
|
393
|
+
void Execute() override {
|
|
394
|
+
CHECK_ROT_VALID();
|
|
395
|
+
result_code_ = fn_(rotator_instance_->my_rot);
|
|
396
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
397
|
+
error_message_ = shim_rigerror(result_code_);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
void OnOK() override {
|
|
402
|
+
if (!error_message_.empty()) {
|
|
403
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private:
|
|
410
|
+
OpFn fn_;
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
class RotatorResetAsyncWorker : public RotatorAsyncWorker {
|
|
414
|
+
public:
|
|
415
|
+
RotatorResetAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, int reset_type)
|
|
416
|
+
: RotatorAsyncWorker(env, rotator_instance), reset_type_(reset_type) {}
|
|
417
|
+
|
|
418
|
+
void Execute() override {
|
|
419
|
+
CHECK_ROT_VALID();
|
|
420
|
+
result_code_ = shim_rot_reset(rotator_instance_->my_rot, reset_type_);
|
|
421
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
422
|
+
error_message_ = shim_rigerror(result_code_);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
void OnOK() override {
|
|
427
|
+
if (!error_message_.empty()) {
|
|
428
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private:
|
|
435
|
+
int reset_type_;
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
class RotatorGetInfoAsyncWorker : public RotatorAsyncWorker {
|
|
439
|
+
public:
|
|
440
|
+
RotatorGetInfoAsyncWorker(Napi::Env env, NodeRotator* rotator_instance)
|
|
441
|
+
: RotatorAsyncWorker(env, rotator_instance) {}
|
|
442
|
+
|
|
443
|
+
void Execute() override {
|
|
444
|
+
CHECK_ROT_VALID();
|
|
445
|
+
info_ = shim_rot_get_info(rotator_instance_->my_rot);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
void OnOK() override {
|
|
449
|
+
deferred_.Resolve(Napi::String::New(Env(), info_));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
private:
|
|
453
|
+
std::string info_;
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
class RotatorGetStatusAsyncWorker : public RotatorAsyncWorker {
|
|
457
|
+
public:
|
|
458
|
+
RotatorGetStatusAsyncWorker(Napi::Env env, NodeRotator* rotator_instance)
|
|
459
|
+
: RotatorAsyncWorker(env, rotator_instance), status_(0) {}
|
|
460
|
+
|
|
461
|
+
void Execute() override {
|
|
462
|
+
CHECK_ROT_VALID();
|
|
463
|
+
result_code_ = shim_rot_get_status(rotator_instance_->my_rot, &status_);
|
|
464
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
465
|
+
error_message_ = shim_rigerror(result_code_);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
void OnOK() override {
|
|
470
|
+
if (!error_message_.empty()) {
|
|
471
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
Napi::Object result = Napi::Object::New(Env());
|
|
475
|
+
result.Set("mask", Napi::Number::New(Env(), status_));
|
|
476
|
+
result.Set("flags", buildStatusArray(Env(), status_));
|
|
477
|
+
deferred_.Resolve(result);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
private:
|
|
481
|
+
int status_;
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
class RotatorSetConfAsyncWorker : public RotatorAsyncWorker {
|
|
485
|
+
public:
|
|
486
|
+
RotatorSetConfAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, std::string name, std::string value)
|
|
487
|
+
: RotatorAsyncWorker(env, rotator_instance), name_(std::move(name)), value_(std::move(value)) {}
|
|
488
|
+
|
|
489
|
+
void Execute() override {
|
|
490
|
+
CHECK_ROT_VALID();
|
|
491
|
+
result_code_ = shim_rot_set_conf(rotator_instance_->my_rot, name_.c_str(), value_.c_str());
|
|
492
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
493
|
+
error_message_ = shim_rigerror(result_code_);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
void OnOK() override {
|
|
498
|
+
if (!error_message_.empty()) {
|
|
499
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
private:
|
|
506
|
+
std::string name_;
|
|
507
|
+
std::string value_;
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
class RotatorGetConfAsyncWorker : public RotatorAsyncWorker {
|
|
511
|
+
public:
|
|
512
|
+
RotatorGetConfAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, std::string name)
|
|
513
|
+
: RotatorAsyncWorker(env, rotator_instance), name_(std::move(name)) {
|
|
514
|
+
memset(buf_, 0, sizeof(buf_));
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
void Execute() override {
|
|
518
|
+
CHECK_ROT_VALID();
|
|
519
|
+
result_code_ = shim_rot_get_conf(rotator_instance_->my_rot, name_.c_str(), buf_, sizeof(buf_));
|
|
520
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
521
|
+
error_message_ = shim_rigerror(result_code_);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
void OnOK() override {
|
|
526
|
+
if (!error_message_.empty()) {
|
|
527
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
deferred_.Resolve(Napi::String::New(Env(), buf_));
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
private:
|
|
534
|
+
std::string name_;
|
|
535
|
+
char buf_[256];
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
class RotatorSetLevelAsyncWorker : public RotatorAsyncWorker {
|
|
539
|
+
public:
|
|
540
|
+
RotatorSetLevelAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, uint64_t level, double value)
|
|
541
|
+
: RotatorAsyncWorker(env, rotator_instance), level_(level), value_(value) {}
|
|
542
|
+
|
|
543
|
+
void Execute() override {
|
|
544
|
+
CHECK_ROT_VALID();
|
|
545
|
+
if (level_ == SHIM_ROT_LEVEL_SPEED) {
|
|
546
|
+
result_code_ = shim_rot_set_level_i(rotator_instance_->my_rot, level_, static_cast<int>(value_));
|
|
547
|
+
} else {
|
|
548
|
+
result_code_ = shim_rot_set_level_f(rotator_instance_->my_rot, level_, static_cast<float>(value_));
|
|
549
|
+
}
|
|
550
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
551
|
+
error_message_ = shim_rigerror(result_code_);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
void OnOK() override {
|
|
556
|
+
if (!error_message_.empty()) {
|
|
557
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
private:
|
|
564
|
+
uint64_t level_;
|
|
565
|
+
double value_;
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
class RotatorGetLevelAsyncWorker : public RotatorAsyncWorker {
|
|
569
|
+
public:
|
|
570
|
+
RotatorGetLevelAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, uint64_t level)
|
|
571
|
+
: RotatorAsyncWorker(env, rotator_instance), level_(level), value_(0) {}
|
|
572
|
+
|
|
573
|
+
void Execute() override {
|
|
574
|
+
CHECK_ROT_VALID();
|
|
575
|
+
result_code_ = shim_rot_get_level_auto(rotator_instance_->my_rot, level_, &value_);
|
|
576
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
577
|
+
error_message_ = shim_rigerror(result_code_);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
void OnOK() override {
|
|
582
|
+
if (!error_message_.empty()) {
|
|
583
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
deferred_.Resolve(Napi::Number::New(Env(), value_));
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
private:
|
|
590
|
+
uint64_t level_;
|
|
591
|
+
double value_;
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
class RotatorSetFunctionAsyncWorker : public RotatorAsyncWorker {
|
|
595
|
+
public:
|
|
596
|
+
RotatorSetFunctionAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, uint64_t func, int enable)
|
|
597
|
+
: RotatorAsyncWorker(env, rotator_instance), func_(func), enable_(enable) {}
|
|
598
|
+
|
|
599
|
+
void Execute() override {
|
|
600
|
+
CHECK_ROT_VALID();
|
|
601
|
+
result_code_ = shim_rot_set_func(rotator_instance_->my_rot, func_, enable_);
|
|
602
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
603
|
+
error_message_ = shim_rigerror(result_code_);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
void OnOK() override {
|
|
608
|
+
if (!error_message_.empty()) {
|
|
609
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private:
|
|
616
|
+
uint64_t func_;
|
|
617
|
+
int enable_;
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
class RotatorGetFunctionAsyncWorker : public RotatorAsyncWorker {
|
|
621
|
+
public:
|
|
622
|
+
RotatorGetFunctionAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, uint64_t func)
|
|
623
|
+
: RotatorAsyncWorker(env, rotator_instance), func_(func), state_(0) {}
|
|
624
|
+
|
|
625
|
+
void Execute() override {
|
|
626
|
+
CHECK_ROT_VALID();
|
|
627
|
+
result_code_ = shim_rot_get_func(rotator_instance_->my_rot, func_, &state_);
|
|
628
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
629
|
+
error_message_ = shim_rigerror(result_code_);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
void OnOK() override {
|
|
634
|
+
if (!error_message_.empty()) {
|
|
635
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
deferred_.Resolve(Napi::Boolean::New(Env(), state_ != 0));
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
private:
|
|
642
|
+
uint64_t func_;
|
|
643
|
+
int state_;
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
class RotatorSetParmAsyncWorker : public RotatorAsyncWorker {
|
|
647
|
+
public:
|
|
648
|
+
RotatorSetParmAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, uint64_t parm, double value)
|
|
649
|
+
: RotatorAsyncWorker(env, rotator_instance), parm_(parm), value_(value) {}
|
|
650
|
+
|
|
651
|
+
void Execute() override {
|
|
652
|
+
CHECK_ROT_VALID();
|
|
653
|
+
result_code_ = shim_rot_set_parm_f(rotator_instance_->my_rot, parm_, static_cast<float>(value_));
|
|
654
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
655
|
+
error_message_ = shim_rigerror(result_code_);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
void OnOK() override {
|
|
660
|
+
if (!error_message_.empty()) {
|
|
661
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
deferred_.Resolve(Napi::Number::New(Env(), result_code_));
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
private:
|
|
668
|
+
uint64_t parm_;
|
|
669
|
+
double value_;
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
class RotatorGetParmAsyncWorker : public RotatorAsyncWorker {
|
|
673
|
+
public:
|
|
674
|
+
RotatorGetParmAsyncWorker(Napi::Env env, NodeRotator* rotator_instance, uint64_t parm)
|
|
675
|
+
: RotatorAsyncWorker(env, rotator_instance), parm_(parm), value_(0) {}
|
|
676
|
+
|
|
677
|
+
void Execute() override {
|
|
678
|
+
CHECK_ROT_VALID();
|
|
679
|
+
float raw = 0;
|
|
680
|
+
result_code_ = shim_rot_get_parm_f(rotator_instance_->my_rot, parm_, &raw);
|
|
681
|
+
value_ = raw;
|
|
682
|
+
if (result_code_ != SHIM_RIG_OK) {
|
|
683
|
+
error_message_ = shim_rigerror(result_code_);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
void OnOK() override {
|
|
688
|
+
if (!error_message_.empty()) {
|
|
689
|
+
deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
deferred_.Resolve(Napi::Number::New(Env(), value_));
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
private:
|
|
696
|
+
uint64_t parm_;
|
|
697
|
+
double value_;
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
bool NodeRotator::isNetworkAddress(const char* path) {
|
|
701
|
+
if (path == nullptr) {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
const char* colon = strchr(path, ':');
|
|
706
|
+
return colon != nullptr && strlen(colon + 1) > 0;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
NodeRotator::NodeRotator(const Napi::CallbackInfo& info) : ObjectWrap(info), my_rot(nullptr) {
|
|
710
|
+
Napi::Env env = info.Env();
|
|
711
|
+
|
|
712
|
+
if (info.Length() < 1 || !info[0].IsNumber()) {
|
|
713
|
+
Napi::TypeError::New(env, "Invalid rotator model").ThrowAsJavaScriptException();
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
bool has_port = false;
|
|
718
|
+
port_path[0] = '\0';
|
|
719
|
+
if (info.Length() >= 2 && info[1].IsString()) {
|
|
720
|
+
const std::string port = info[1].As<Napi::String>().Utf8Value();
|
|
721
|
+
if (!port.empty()) {
|
|
722
|
+
strncpy(port_path, port.c_str(), SHIM_HAMLIB_FILPATHLEN - 1);
|
|
723
|
+
port_path[SHIM_HAMLIB_FILPATHLEN - 1] = '\0';
|
|
724
|
+
has_port = true;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
unsigned int model = info[0].As<Napi::Number>().Uint32Value();
|
|
729
|
+
original_model = model;
|
|
730
|
+
is_network_rot = isNetworkAddress(port_path);
|
|
731
|
+
if (is_network_rot) {
|
|
732
|
+
model = 2; // ROT_MODEL_NETROTCTL
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
my_rot = shim_rot_init(model);
|
|
736
|
+
if (!my_rot) {
|
|
737
|
+
Napi::TypeError::New(env, "Unable to initialize rotator").ThrowAsJavaScriptException();
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (has_port) {
|
|
742
|
+
shim_rot_set_port_path(my_rot, port_path);
|
|
743
|
+
shim_rot_set_port_type(my_rot, is_network_rot ? SHIM_RIG_PORT_NETWORK : SHIM_RIG_PORT_SERIAL);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
NodeRotator::~NodeRotator() {
|
|
748
|
+
if (my_rot) {
|
|
749
|
+
if (rot_is_open) {
|
|
750
|
+
shim_rot_close(my_rot);
|
|
751
|
+
rot_is_open = false;
|
|
752
|
+
}
|
|
753
|
+
shim_rot_cleanup(my_rot);
|
|
754
|
+
my_rot = nullptr;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
Napi::Value NodeRotator::Open(const Napi::CallbackInfo& info) {
|
|
759
|
+
auto* worker = new RotatorOpenAsyncWorker(info.Env(), this);
|
|
760
|
+
worker->Queue();
|
|
761
|
+
return worker->GetPromise();
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
Napi::Value NodeRotator::Close(const Napi::CallbackInfo& info) {
|
|
765
|
+
auto* worker = new RotatorCloseAsyncWorker(info.Env(), this);
|
|
766
|
+
worker->Queue();
|
|
767
|
+
return worker->GetPromise();
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
Napi::Value NodeRotator::Destroy(const Napi::CallbackInfo& info) {
|
|
771
|
+
auto* worker = new RotatorDestroyAsyncWorker(info.Env(), this);
|
|
772
|
+
worker->Queue();
|
|
773
|
+
return worker->GetPromise();
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
Napi::Value NodeRotator::GetConnectionInfo(const Napi::CallbackInfo& info) {
|
|
777
|
+
Napi::Env env = info.Env();
|
|
778
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
779
|
+
obj.Set("connectionType", Napi::String::New(env, is_network_rot ? "network" : "serial"));
|
|
780
|
+
obj.Set("portPath", Napi::String::New(env, port_path));
|
|
781
|
+
obj.Set("isOpen", Napi::Boolean::New(env, rot_is_open));
|
|
782
|
+
obj.Set("originalModel", Napi::Number::New(env, original_model));
|
|
783
|
+
obj.Set("currentModel", Napi::Number::New(env, is_network_rot ? 2 : original_model));
|
|
784
|
+
return obj;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
Napi::Value NodeRotator::SetPosition(const Napi::CallbackInfo& info) {
|
|
788
|
+
Napi::Env env = info.Env();
|
|
789
|
+
if (!rot_is_open) {
|
|
790
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
791
|
+
return env.Null();
|
|
792
|
+
}
|
|
793
|
+
if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsNumber()) {
|
|
794
|
+
Napi::TypeError::New(env, "Expected (azimuth: number, elevation: number)").ThrowAsJavaScriptException();
|
|
795
|
+
return env.Null();
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
auto* worker = new RotatorSetPositionAsyncWorker(
|
|
799
|
+
env,
|
|
800
|
+
this,
|
|
801
|
+
info[0].As<Napi::Number>().DoubleValue(),
|
|
802
|
+
info[1].As<Napi::Number>().DoubleValue());
|
|
803
|
+
worker->Queue();
|
|
804
|
+
return worker->GetPromise();
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
Napi::Value NodeRotator::GetPosition(const Napi::CallbackInfo& info) {
|
|
808
|
+
Napi::Env env = info.Env();
|
|
809
|
+
if (!rot_is_open) {
|
|
810
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
811
|
+
return env.Null();
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
auto* worker = new RotatorGetPositionAsyncWorker(env, this);
|
|
815
|
+
worker->Queue();
|
|
816
|
+
return worker->GetPromise();
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
Napi::Value NodeRotator::Move(const Napi::CallbackInfo& info) {
|
|
820
|
+
Napi::Env env = info.Env();
|
|
821
|
+
if (!rot_is_open) {
|
|
822
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
823
|
+
return env.Null();
|
|
824
|
+
}
|
|
825
|
+
if (info.Length() < 2) {
|
|
826
|
+
Napi::TypeError::New(env, "Expected (direction: string|number, speed: number)").ThrowAsJavaScriptException();
|
|
827
|
+
return env.Null();
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
const int direction = parseRotDirection(env, info[0]);
|
|
831
|
+
if (direction == std::numeric_limits<int>::min()) {
|
|
832
|
+
return env.Null();
|
|
833
|
+
}
|
|
834
|
+
if (!info[1].IsNumber()) {
|
|
835
|
+
Napi::TypeError::New(env, "Expected speed as number").ThrowAsJavaScriptException();
|
|
836
|
+
return env.Null();
|
|
837
|
+
}
|
|
838
|
+
const int speed = info[1].As<Napi::Number>().Int32Value();
|
|
839
|
+
|
|
840
|
+
auto* worker = new RotatorMoveAsyncWorker(env, this, direction, speed);
|
|
841
|
+
worker->Queue();
|
|
842
|
+
return worker->GetPromise();
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
Napi::Value NodeRotator::Stop(const Napi::CallbackInfo& info) {
|
|
846
|
+
Napi::Env env = info.Env();
|
|
847
|
+
if (!rot_is_open) {
|
|
848
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
849
|
+
return env.Null();
|
|
850
|
+
}
|
|
851
|
+
auto* worker = new RotatorSimpleAsyncWorker(env, this, shim_rot_stop);
|
|
852
|
+
worker->Queue();
|
|
853
|
+
return worker->GetPromise();
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
Napi::Value NodeRotator::Park(const Napi::CallbackInfo& info) {
|
|
857
|
+
Napi::Env env = info.Env();
|
|
858
|
+
if (!rot_is_open) {
|
|
859
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
860
|
+
return env.Null();
|
|
861
|
+
}
|
|
862
|
+
auto* worker = new RotatorSimpleAsyncWorker(env, this, shim_rot_park);
|
|
863
|
+
worker->Queue();
|
|
864
|
+
return worker->GetPromise();
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
Napi::Value NodeRotator::Reset(const Napi::CallbackInfo& info) {
|
|
868
|
+
Napi::Env env = info.Env();
|
|
869
|
+
if (!rot_is_open) {
|
|
870
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
871
|
+
return env.Null();
|
|
872
|
+
}
|
|
873
|
+
if (info.Length() < 1) {
|
|
874
|
+
Napi::TypeError::New(env, "Expected reset type").ThrowAsJavaScriptException();
|
|
875
|
+
return env.Null();
|
|
876
|
+
}
|
|
877
|
+
const int reset = parseRotReset(env, info[0]);
|
|
878
|
+
if (reset == std::numeric_limits<int>::min()) {
|
|
879
|
+
return env.Null();
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
auto* worker = new RotatorResetAsyncWorker(env, this, reset);
|
|
883
|
+
worker->Queue();
|
|
884
|
+
return worker->GetPromise();
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
Napi::Value NodeRotator::GetInfo(const Napi::CallbackInfo& info) {
|
|
888
|
+
Napi::Env env = info.Env();
|
|
889
|
+
if (!rot_is_open) {
|
|
890
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
891
|
+
return env.Null();
|
|
892
|
+
}
|
|
893
|
+
auto* worker = new RotatorGetInfoAsyncWorker(env, this);
|
|
894
|
+
worker->Queue();
|
|
895
|
+
return worker->GetPromise();
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
Napi::Value NodeRotator::GetStatus(const Napi::CallbackInfo& info) {
|
|
899
|
+
Napi::Env env = info.Env();
|
|
900
|
+
if (!rot_is_open) {
|
|
901
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
902
|
+
return env.Null();
|
|
903
|
+
}
|
|
904
|
+
auto* worker = new RotatorGetStatusAsyncWorker(env, this);
|
|
905
|
+
worker->Queue();
|
|
906
|
+
return worker->GetPromise();
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
Napi::Value NodeRotator::SetConf(const Napi::CallbackInfo& info) {
|
|
910
|
+
Napi::Env env = info.Env();
|
|
911
|
+
RETURN_NULL_IF_ROT_HANDLE_INVALID();
|
|
912
|
+
if (info.Length() < 2 || !info[0].IsString() || !info[1].IsString()) {
|
|
913
|
+
Napi::TypeError::New(env, "Expected (name: string, value: string)").ThrowAsJavaScriptException();
|
|
914
|
+
return env.Null();
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
auto* worker = new RotatorSetConfAsyncWorker(
|
|
918
|
+
env,
|
|
919
|
+
this,
|
|
920
|
+
info[0].As<Napi::String>().Utf8Value(),
|
|
921
|
+
info[1].As<Napi::String>().Utf8Value());
|
|
922
|
+
worker->Queue();
|
|
923
|
+
return worker->GetPromise();
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
Napi::Value NodeRotator::GetConf(const Napi::CallbackInfo& info) {
|
|
927
|
+
Napi::Env env = info.Env();
|
|
928
|
+
RETURN_NULL_IF_ROT_HANDLE_INVALID();
|
|
929
|
+
if (info.Length() < 1 || !info[0].IsString()) {
|
|
930
|
+
Napi::TypeError::New(env, "Expected (name: string)").ThrowAsJavaScriptException();
|
|
931
|
+
return env.Null();
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
auto* worker = new RotatorGetConfAsyncWorker(env, this, info[0].As<Napi::String>().Utf8Value());
|
|
935
|
+
worker->Queue();
|
|
936
|
+
return worker->GetPromise();
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
int NodeRotator::rot_config_callback(const shim_confparam_info_t* info, void* data) {
|
|
940
|
+
auto* schema_data = static_cast<RotatorConfigSchemaData*>(data);
|
|
941
|
+
if (!schema_data || !info) {
|
|
942
|
+
return 0;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
RotatorConfigFieldDescriptor field;
|
|
946
|
+
field.token = info->token;
|
|
947
|
+
field.name = info->name;
|
|
948
|
+
field.label = info->label;
|
|
949
|
+
field.tooltip = info->tooltip;
|
|
950
|
+
field.defaultValue = info->dflt;
|
|
951
|
+
field.type = info->type;
|
|
952
|
+
field.numericMin = info->numeric_min;
|
|
953
|
+
field.numericMax = info->numeric_max;
|
|
954
|
+
field.numericStep = info->numeric_step;
|
|
955
|
+
for (int i = 0; i < info->combo_count; ++i) {
|
|
956
|
+
field.options.emplace_back(info->combo_options[i]);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
schema_data->fields.push_back(field);
|
|
960
|
+
return 1;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
Napi::Value NodeRotator::GetConfigSchema(const Napi::CallbackInfo& info) {
|
|
964
|
+
Napi::Env env = info.Env();
|
|
965
|
+
RETURN_NULL_IF_ROT_HANDLE_INVALID();
|
|
966
|
+
|
|
967
|
+
RotatorConfigSchemaData schemaData{};
|
|
968
|
+
const int result = shim_rot_cfgparams_foreach(my_rot, rot_config_callback, &schemaData);
|
|
969
|
+
if (result != SHIM_RIG_OK) {
|
|
970
|
+
Napi::Error::New(env, shim_rigerror(result)).ThrowAsJavaScriptException();
|
|
971
|
+
return env.Null();
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
Napi::Array schemaArray = Napi::Array::New(env, schemaData.fields.size());
|
|
975
|
+
for (size_t i = 0; i < schemaData.fields.size(); ++i) {
|
|
976
|
+
const RotatorConfigFieldDescriptor& descriptor = schemaData.fields[i];
|
|
977
|
+
Napi::Object field = Napi::Object::New(env);
|
|
978
|
+
field.Set("token", Napi::Number::New(env, descriptor.token));
|
|
979
|
+
field.Set("name", Napi::String::New(env, descriptor.name));
|
|
980
|
+
field.Set("label", Napi::String::New(env, descriptor.label));
|
|
981
|
+
field.Set("tooltip", Napi::String::New(env, descriptor.tooltip));
|
|
982
|
+
field.Set("defaultValue", Napi::String::New(env, descriptor.defaultValue));
|
|
983
|
+
field.Set("type", Napi::String::New(env, publicConfTypeName(descriptor.type)));
|
|
984
|
+
|
|
985
|
+
if (descriptor.type == 2 || descriptor.type == 6) {
|
|
986
|
+
Napi::Object numeric = Napi::Object::New(env);
|
|
987
|
+
numeric.Set("min", Napi::Number::New(env, descriptor.numericMin));
|
|
988
|
+
numeric.Set("max", Napi::Number::New(env, descriptor.numericMax));
|
|
989
|
+
numeric.Set("step", Napi::Number::New(env, descriptor.numericStep));
|
|
990
|
+
field.Set("numeric", numeric);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (!descriptor.options.empty()) {
|
|
994
|
+
Napi::Array options = Napi::Array::New(env, descriptor.options.size());
|
|
995
|
+
for (size_t optionIndex = 0; optionIndex < descriptor.options.size(); ++optionIndex) {
|
|
996
|
+
options[static_cast<uint32_t>(optionIndex)] =
|
|
997
|
+
Napi::String::New(env, descriptor.options[optionIndex]);
|
|
998
|
+
}
|
|
999
|
+
field.Set("options", options);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
schemaArray[static_cast<uint32_t>(i)] = field;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
return schemaArray;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
Napi::Value NodeRotator::GetPortCaps(const Napi::CallbackInfo& info) {
|
|
1009
|
+
Napi::Env env = info.Env();
|
|
1010
|
+
RETURN_NULL_IF_ROT_HANDLE_INVALID();
|
|
1011
|
+
|
|
1012
|
+
shim_rig_port_caps_t caps{};
|
|
1013
|
+
const int result = shim_rot_get_port_caps(my_rot, &caps);
|
|
1014
|
+
if (result != SHIM_RIG_OK) {
|
|
1015
|
+
Napi::Error::New(env, shim_rigerror(result)).ThrowAsJavaScriptException();
|
|
1016
|
+
return env.Null();
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
Napi::Object portCaps = Napi::Object::New(env);
|
|
1020
|
+
portCaps.Set("portType", Napi::String::New(env, caps.port_type));
|
|
1021
|
+
portCaps.Set("writeDelay", Napi::Number::New(env, caps.write_delay));
|
|
1022
|
+
portCaps.Set("postWriteDelay", Napi::Number::New(env, caps.post_write_delay));
|
|
1023
|
+
portCaps.Set("timeout", Napi::Number::New(env, caps.timeout));
|
|
1024
|
+
portCaps.Set("retry", Napi::Number::New(env, caps.retry));
|
|
1025
|
+
|
|
1026
|
+
if (hasPositiveValue(caps.serial_rate_min)) {
|
|
1027
|
+
portCaps.Set("serialRateMin", Napi::Number::New(env, caps.serial_rate_min));
|
|
1028
|
+
}
|
|
1029
|
+
if (hasPositiveValue(caps.serial_rate_max)) {
|
|
1030
|
+
portCaps.Set("serialRateMax", Napi::Number::New(env, caps.serial_rate_max));
|
|
1031
|
+
}
|
|
1032
|
+
if (hasPositiveValue(caps.serial_data_bits)) {
|
|
1033
|
+
portCaps.Set("serialDataBits", Napi::Number::New(env, caps.serial_data_bits));
|
|
1034
|
+
}
|
|
1035
|
+
if (hasPositiveValue(caps.serial_stop_bits)) {
|
|
1036
|
+
portCaps.Set("serialStopBits", Napi::Number::New(env, caps.serial_stop_bits));
|
|
1037
|
+
}
|
|
1038
|
+
if (caps.serial_parity[0] != '\0' && std::string(caps.serial_parity) != "Unknown") {
|
|
1039
|
+
portCaps.Set("serialParity", Napi::String::New(env, caps.serial_parity));
|
|
1040
|
+
}
|
|
1041
|
+
if (caps.serial_handshake[0] != '\0' && std::string(caps.serial_handshake) != "Unknown") {
|
|
1042
|
+
portCaps.Set("serialHandshake", Napi::String::New(env, caps.serial_handshake));
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
return portCaps;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
Napi::Value NodeRotator::GetRotatorCaps(const Napi::CallbackInfo& info) {
|
|
1049
|
+
Napi::Env env = info.Env();
|
|
1050
|
+
RETURN_NULL_IF_ROT_HANDLE_INVALID();
|
|
1051
|
+
|
|
1052
|
+
shim_rot_caps_t caps{};
|
|
1053
|
+
const int result = shim_rot_get_caps(my_rot, &caps);
|
|
1054
|
+
if (result != SHIM_RIG_OK) {
|
|
1055
|
+
Napi::Error::New(env, shim_rigerror(result)).ThrowAsJavaScriptException();
|
|
1056
|
+
return env.Null();
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
Napi::Object rotCaps = Napi::Object::New(env);
|
|
1060
|
+
rotCaps.Set("rotType", Napi::String::New(env, shim_rot_type_str(caps.rot_type)));
|
|
1061
|
+
rotCaps.Set("rotTypeMask", Napi::Number::New(env, caps.rot_type));
|
|
1062
|
+
rotCaps.Set("minAz", Napi::Number::New(env, caps.min_az));
|
|
1063
|
+
rotCaps.Set("maxAz", Napi::Number::New(env, caps.max_az));
|
|
1064
|
+
rotCaps.Set("minEl", Napi::Number::New(env, caps.min_el));
|
|
1065
|
+
rotCaps.Set("maxEl", Napi::Number::New(env, caps.max_el));
|
|
1066
|
+
rotCaps.Set("supportedStatuses", buildStatusArray(env, caps.has_status));
|
|
1067
|
+
return rotCaps;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
Napi::Value NodeRotator::SetLevel(const Napi::CallbackInfo& info) {
|
|
1071
|
+
Napi::Env env = info.Env();
|
|
1072
|
+
if (!rot_is_open) {
|
|
1073
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
1074
|
+
return env.Null();
|
|
1075
|
+
}
|
|
1076
|
+
if (info.Length() < 2 || !info[1].IsNumber()) {
|
|
1077
|
+
Napi::TypeError::New(env, "Expected (level: string, value: number)").ThrowAsJavaScriptException();
|
|
1078
|
+
return env.Null();
|
|
1079
|
+
}
|
|
1080
|
+
const uint64_t level = parseRotLevel(env, info[0]);
|
|
1081
|
+
if (level == 0) return env.Null();
|
|
1082
|
+
|
|
1083
|
+
auto* worker = new RotatorSetLevelAsyncWorker(env, this, level, info[1].As<Napi::Number>().DoubleValue());
|
|
1084
|
+
worker->Queue();
|
|
1085
|
+
return worker->GetPromise();
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
Napi::Value NodeRotator::GetLevel(const Napi::CallbackInfo& info) {
|
|
1089
|
+
Napi::Env env = info.Env();
|
|
1090
|
+
if (!rot_is_open) {
|
|
1091
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
1092
|
+
return env.Null();
|
|
1093
|
+
}
|
|
1094
|
+
if (info.Length() < 1) {
|
|
1095
|
+
Napi::TypeError::New(env, "Expected level name").ThrowAsJavaScriptException();
|
|
1096
|
+
return env.Null();
|
|
1097
|
+
}
|
|
1098
|
+
const uint64_t level = parseRotLevel(env, info[0]);
|
|
1099
|
+
if (level == 0) return env.Null();
|
|
1100
|
+
|
|
1101
|
+
auto* worker = new RotatorGetLevelAsyncWorker(env, this, level);
|
|
1102
|
+
worker->Queue();
|
|
1103
|
+
return worker->GetPromise();
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
Napi::Value NodeRotator::GetSupportedLevels(const Napi::CallbackInfo& info) {
|
|
1107
|
+
Napi::Env env = info.Env();
|
|
1108
|
+
RETURN_NULL_IF_ROT_HANDLE_INVALID();
|
|
1109
|
+
const uint64_t levels = shim_rot_get_caps_has_get_level(my_rot) | shim_rot_get_caps_has_set_level(my_rot);
|
|
1110
|
+
return buildSettingArrayFromMask(env, levels, shim_rot_strlevel);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
Napi::Value NodeRotator::SetFunction(const Napi::CallbackInfo& info) {
|
|
1114
|
+
Napi::Env env = info.Env();
|
|
1115
|
+
if (!rot_is_open) {
|
|
1116
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
1117
|
+
return env.Null();
|
|
1118
|
+
}
|
|
1119
|
+
if (info.Length() < 2 || !info[1].IsBoolean()) {
|
|
1120
|
+
Napi::TypeError::New(env, "Expected (function: string, enable: boolean)").ThrowAsJavaScriptException();
|
|
1121
|
+
return env.Null();
|
|
1122
|
+
}
|
|
1123
|
+
const uint64_t func = parseRotFunc(env, info[0]);
|
|
1124
|
+
if (func == 0) return env.Null();
|
|
1125
|
+
|
|
1126
|
+
auto* worker = new RotatorSetFunctionAsyncWorker(env, this, func, info[1].As<Napi::Boolean>().Value() ? 1 : 0);
|
|
1127
|
+
worker->Queue();
|
|
1128
|
+
return worker->GetPromise();
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
Napi::Value NodeRotator::GetFunction(const Napi::CallbackInfo& info) {
|
|
1132
|
+
Napi::Env env = info.Env();
|
|
1133
|
+
if (!rot_is_open) {
|
|
1134
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
1135
|
+
return env.Null();
|
|
1136
|
+
}
|
|
1137
|
+
if (info.Length() < 1) {
|
|
1138
|
+
Napi::TypeError::New(env, "Expected function name").ThrowAsJavaScriptException();
|
|
1139
|
+
return env.Null();
|
|
1140
|
+
}
|
|
1141
|
+
const uint64_t func = parseRotFunc(env, info[0]);
|
|
1142
|
+
if (func == 0) return env.Null();
|
|
1143
|
+
|
|
1144
|
+
auto* worker = new RotatorGetFunctionAsyncWorker(env, this, func);
|
|
1145
|
+
worker->Queue();
|
|
1146
|
+
return worker->GetPromise();
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
Napi::Value NodeRotator::GetSupportedFunctions(const Napi::CallbackInfo& info) {
|
|
1150
|
+
Napi::Env env = info.Env();
|
|
1151
|
+
RETURN_NULL_IF_ROT_HANDLE_INVALID();
|
|
1152
|
+
const uint64_t funcs = shim_rot_get_caps_has_get_func(my_rot) | shim_rot_get_caps_has_set_func(my_rot);
|
|
1153
|
+
return buildSettingArrayFromMask(env, funcs, shim_rot_strfunc);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
Napi::Value NodeRotator::SetParm(const Napi::CallbackInfo& info) {
|
|
1157
|
+
Napi::Env env = info.Env();
|
|
1158
|
+
if (!rot_is_open) {
|
|
1159
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
1160
|
+
return env.Null();
|
|
1161
|
+
}
|
|
1162
|
+
if (info.Length() < 2 || !info[1].IsNumber()) {
|
|
1163
|
+
Napi::TypeError::New(env, "Expected (parameter: string, value: number)").ThrowAsJavaScriptException();
|
|
1164
|
+
return env.Null();
|
|
1165
|
+
}
|
|
1166
|
+
const uint64_t parm = parseRotParm(env, info[0]);
|
|
1167
|
+
if (parm == 0) return env.Null();
|
|
1168
|
+
|
|
1169
|
+
auto* worker = new RotatorSetParmAsyncWorker(env, this, parm, info[1].As<Napi::Number>().DoubleValue());
|
|
1170
|
+
worker->Queue();
|
|
1171
|
+
return worker->GetPromise();
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
Napi::Value NodeRotator::GetParm(const Napi::CallbackInfo& info) {
|
|
1175
|
+
Napi::Env env = info.Env();
|
|
1176
|
+
if (!rot_is_open) {
|
|
1177
|
+
Napi::TypeError::New(env, "Rotator is not open!").ThrowAsJavaScriptException();
|
|
1178
|
+
return env.Null();
|
|
1179
|
+
}
|
|
1180
|
+
if (info.Length() < 1) {
|
|
1181
|
+
Napi::TypeError::New(env, "Expected parameter name").ThrowAsJavaScriptException();
|
|
1182
|
+
return env.Null();
|
|
1183
|
+
}
|
|
1184
|
+
const uint64_t parm = parseRotParm(env, info[0]);
|
|
1185
|
+
if (parm == 0) return env.Null();
|
|
1186
|
+
|
|
1187
|
+
auto* worker = new RotatorGetParmAsyncWorker(env, this, parm);
|
|
1188
|
+
worker->Queue();
|
|
1189
|
+
return worker->GetPromise();
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
Napi::Value NodeRotator::GetSupportedParms(const Napi::CallbackInfo& info) {
|
|
1193
|
+
Napi::Env env = info.Env();
|
|
1194
|
+
RETURN_NULL_IF_ROT_HANDLE_INVALID();
|
|
1195
|
+
const uint64_t parms = shim_rot_get_caps_has_get_parm(my_rot) | shim_rot_get_caps_has_set_parm(my_rot);
|
|
1196
|
+
return buildSettingArrayFromMask(env, parms, shim_rot_strparm);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
int NodeRotator::rot_list_callback(const shim_rot_info_t* info, void* data) {
|
|
1200
|
+
auto* rot_data = static_cast<RotatorListData*>(data);
|
|
1201
|
+
Napi::Object rotInfo = Napi::Object::New(rot_data->env);
|
|
1202
|
+
rotInfo.Set("rotModel", Napi::Number::New(rot_data->env, info->rot_model));
|
|
1203
|
+
rotInfo.Set("modelName", Napi::String::New(rot_data->env, info->model_name ? info->model_name : ""));
|
|
1204
|
+
rotInfo.Set("mfgName", Napi::String::New(rot_data->env, info->mfg_name ? info->mfg_name : ""));
|
|
1205
|
+
rotInfo.Set("version", Napi::String::New(rot_data->env, info->version ? info->version : ""));
|
|
1206
|
+
rotInfo.Set("status", Napi::String::New(rot_data->env, shim_rig_strstatus(info->status)));
|
|
1207
|
+
rotInfo.Set("rotType", Napi::String::New(rot_data->env, shim_rot_type_str(info->rot_type)));
|
|
1208
|
+
rotInfo.Set("rotTypeMask", Napi::Number::New(rot_data->env, info->rot_type));
|
|
1209
|
+
rot_data->rotators.push_back(rotInfo);
|
|
1210
|
+
return 1;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
Napi::Value NodeRotator::GetSupportedRotators(const Napi::CallbackInfo& info) {
|
|
1214
|
+
Napi::Env env = info.Env();
|
|
1215
|
+
shim_rot_load_all_backends();
|
|
1216
|
+
|
|
1217
|
+
RotatorListData rotData{std::vector<Napi::Object>(), env};
|
|
1218
|
+
const int result = shim_rot_list_foreach(rot_list_callback, &rotData);
|
|
1219
|
+
if (result != SHIM_RIG_OK) {
|
|
1220
|
+
Napi::Error::New(env, "Failed to retrieve supported rotator list").ThrowAsJavaScriptException();
|
|
1221
|
+
return env.Null();
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
Napi::Array rotArray = Napi::Array::New(env, rotData.rotators.size());
|
|
1225
|
+
for (size_t i = 0; i < rotData.rotators.size(); ++i) {
|
|
1226
|
+
rotArray[static_cast<uint32_t>(i)] = rotData.rotators[i];
|
|
1227
|
+
}
|
|
1228
|
+
return rotArray;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
Napi::Value NodeRotator::GetHamlibVersion(const Napi::CallbackInfo& info) {
|
|
1232
|
+
return Napi::String::New(info.Env(), shim_rig_get_version());
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
Napi::Value NodeRotator::SetDebugLevel(const Napi::CallbackInfo& info) {
|
|
1236
|
+
Napi::Env env = info.Env();
|
|
1237
|
+
if (info.Length() < 1 || !info[0].IsNumber()) {
|
|
1238
|
+
Napi::TypeError::New(env, "Debug level (number) required").ThrowAsJavaScriptException();
|
|
1239
|
+
return env.Undefined();
|
|
1240
|
+
}
|
|
1241
|
+
const int level = info[0].As<Napi::Number>().Int32Value();
|
|
1242
|
+
if (level < 0 || level > 5) {
|
|
1243
|
+
Napi::RangeError::New(env, "Debug level must be between 0 (NONE) and 5 (TRACE)").ThrowAsJavaScriptException();
|
|
1244
|
+
return env.Undefined();
|
|
1245
|
+
}
|
|
1246
|
+
shim_rig_set_debug(level);
|
|
1247
|
+
return env.Undefined();
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
Napi::Value NodeRotator::GetDebugLevel(const Napi::CallbackInfo& info) {
|
|
1251
|
+
Napi::Env env = info.Env();
|
|
1252
|
+
Napi::Error::New(
|
|
1253
|
+
env,
|
|
1254
|
+
"Getting debug level is not supported by Hamlib API. "
|
|
1255
|
+
"Please track the debug level you set using setDebugLevel().")
|
|
1256
|
+
.ThrowAsJavaScriptException();
|
|
1257
|
+
return env.Undefined();
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
Napi::Value NodeRotator::GetCopyright(const Napi::CallbackInfo& info) {
|
|
1261
|
+
return Napi::String::New(info.Env(), shim_rig_copyright());
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
Napi::Value NodeRotator::GetLicense(const Napi::CallbackInfo& info) {
|
|
1265
|
+
return Napi::String::New(info.Env(), shim_rig_license());
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
Napi::Function NodeRotator::GetClass(Napi::Env env) {
|
|
1269
|
+
auto klass = DefineClass(
|
|
1270
|
+
env,
|
|
1271
|
+
"Rotator",
|
|
1272
|
+
{
|
|
1273
|
+
InstanceMethod("open", &NodeRotator::Open),
|
|
1274
|
+
InstanceMethod("close", &NodeRotator::Close),
|
|
1275
|
+
InstanceMethod("destroy", &NodeRotator::Destroy),
|
|
1276
|
+
InstanceMethod("getConnectionInfo", &NodeRotator::GetConnectionInfo),
|
|
1277
|
+
InstanceMethod("setPosition", &NodeRotator::SetPosition),
|
|
1278
|
+
InstanceMethod("getPosition", &NodeRotator::GetPosition),
|
|
1279
|
+
InstanceMethod("move", &NodeRotator::Move),
|
|
1280
|
+
InstanceMethod("stop", &NodeRotator::Stop),
|
|
1281
|
+
InstanceMethod("park", &NodeRotator::Park),
|
|
1282
|
+
InstanceMethod("reset", &NodeRotator::Reset),
|
|
1283
|
+
InstanceMethod("getInfo", &NodeRotator::GetInfo),
|
|
1284
|
+
InstanceMethod("getStatus", &NodeRotator::GetStatus),
|
|
1285
|
+
InstanceMethod("setConf", &NodeRotator::SetConf),
|
|
1286
|
+
InstanceMethod("getConf", &NodeRotator::GetConf),
|
|
1287
|
+
InstanceMethod("getConfigSchema", &NodeRotator::GetConfigSchema),
|
|
1288
|
+
InstanceMethod("getPortCaps", &NodeRotator::GetPortCaps),
|
|
1289
|
+
InstanceMethod("getRotatorCaps", &NodeRotator::GetRotatorCaps),
|
|
1290
|
+
InstanceMethod("setLevel", &NodeRotator::SetLevel),
|
|
1291
|
+
InstanceMethod("getLevel", &NodeRotator::GetLevel),
|
|
1292
|
+
InstanceMethod("getSupportedLevels", &NodeRotator::GetSupportedLevels),
|
|
1293
|
+
InstanceMethod("setFunction", &NodeRotator::SetFunction),
|
|
1294
|
+
InstanceMethod("getFunction", &NodeRotator::GetFunction),
|
|
1295
|
+
InstanceMethod("getSupportedFunctions", &NodeRotator::GetSupportedFunctions),
|
|
1296
|
+
InstanceMethod("setParm", &NodeRotator::SetParm),
|
|
1297
|
+
InstanceMethod("getParm", &NodeRotator::GetParm),
|
|
1298
|
+
InstanceMethod("getSupportedParms", &NodeRotator::GetSupportedParms),
|
|
1299
|
+
StaticMethod("getSupportedRotators", &NodeRotator::GetSupportedRotators),
|
|
1300
|
+
StaticMethod("getHamlibVersion", &NodeRotator::GetHamlibVersion),
|
|
1301
|
+
StaticMethod("setDebugLevel", &NodeRotator::SetDebugLevel),
|
|
1302
|
+
StaticMethod("getDebugLevel", &NodeRotator::GetDebugLevel),
|
|
1303
|
+
StaticMethod("getCopyright", &NodeRotator::GetCopyright),
|
|
1304
|
+
StaticMethod("getLicense", &NodeRotator::GetLicense),
|
|
1305
|
+
});
|
|
1306
|
+
constructor = Napi::Persistent(klass);
|
|
1307
|
+
constructor.SuppressDestruct();
|
|
1308
|
+
return klass;
|
|
1309
|
+
}
|