@jason2866/serialport-bindings-cpp 0.0.0-development
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/LICENSE +21 -0
- package/README.md +95 -0
- package/binding.gyp +80 -0
- package/package.json +113 -0
- package/src/darwin_list.cpp +317 -0
- package/src/darwin_list.h +68 -0
- package/src/poller.cpp +166 -0
- package/src/poller.h +35 -0
- package/src/serialport.cpp +342 -0
- package/src/serialport.h +202 -0
- package/src/serialport_linux.cpp +76 -0
- package/src/serialport_linux.h +10 -0
- package/src/serialport_unix.cpp +482 -0
- package/src/serialport_unix.h +7 -0
- package/src/serialport_win.cpp +989 -0
- package/src/serialport_win.h +93 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#ifndef PACKAGES_SERIALPORT_SRC_DARWIN_LIST_H_
|
|
2
|
+
#define PACKAGES_SERIALPORT_SRC_DARWIN_LIST_H_
|
|
3
|
+
#include <sys/param.h> // For MAXPATHLEN
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
#include <uv.h>
|
|
6
|
+
#include <list>
|
|
7
|
+
#include <string>
|
|
8
|
+
|
|
9
|
+
#define ERROR_STRING_SIZE 1088
|
|
10
|
+
|
|
11
|
+
Napi::Value List(const Napi::CallbackInfo& info);
|
|
12
|
+
void setIfNotEmpty(Napi::Object item, std::string key, const char *value);
|
|
13
|
+
|
|
14
|
+
struct ListResultItem {
|
|
15
|
+
std::string path;
|
|
16
|
+
std::string manufacturer;
|
|
17
|
+
std::string serialNumber;
|
|
18
|
+
std::string pnpId;
|
|
19
|
+
std::string locationId;
|
|
20
|
+
std::string vendorId;
|
|
21
|
+
std::string productId;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
struct ListBaton : public Napi::AsyncWorker {
|
|
25
|
+
ListBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:ListBaton"),
|
|
26
|
+
errorString() {}
|
|
27
|
+
std::list<ListResultItem*> results;
|
|
28
|
+
char errorString[ERROR_STRING_SIZE];
|
|
29
|
+
void Execute() override;
|
|
30
|
+
|
|
31
|
+
void OnOK() override {
|
|
32
|
+
Napi::Env env = Env();
|
|
33
|
+
Napi::HandleScope scope(env);
|
|
34
|
+
Napi::Array result = Napi::Array::New(env);
|
|
35
|
+
int i = 0;
|
|
36
|
+
for (std::list<ListResultItem*>::iterator it = results.begin(); it != results.end(); ++it, i++) {
|
|
37
|
+
Napi::Object item = Napi::Object::New(env);
|
|
38
|
+
|
|
39
|
+
setIfNotEmpty(item, "path", (*it)->path.c_str());
|
|
40
|
+
setIfNotEmpty(item, "manufacturer", (*it)->manufacturer.c_str());
|
|
41
|
+
setIfNotEmpty(item, "serialNumber", (*it)->serialNumber.c_str());
|
|
42
|
+
setIfNotEmpty(item, "pnpId", (*it)->pnpId.c_str());
|
|
43
|
+
setIfNotEmpty(item, "locationId", (*it)->locationId.c_str());
|
|
44
|
+
setIfNotEmpty(item, "vendorId", (*it)->vendorId.c_str());
|
|
45
|
+
setIfNotEmpty(item, "productId", (*it)->productId.c_str());
|
|
46
|
+
|
|
47
|
+
(result).Set(i, item);
|
|
48
|
+
}
|
|
49
|
+
Callback().Call({env.Null(), result});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
typedef struct SerialDevice {
|
|
54
|
+
char port[MAXPATHLEN];
|
|
55
|
+
char locationId[MAXPATHLEN];
|
|
56
|
+
char vendorId[MAXPATHLEN];
|
|
57
|
+
char productId[MAXPATHLEN];
|
|
58
|
+
char manufacturer[MAXPATHLEN];
|
|
59
|
+
char serialNumber[MAXPATHLEN];
|
|
60
|
+
} stSerialDevice;
|
|
61
|
+
|
|
62
|
+
typedef struct DeviceListItem {
|
|
63
|
+
struct SerialDevice value;
|
|
64
|
+
struct DeviceListItem *next;
|
|
65
|
+
int* length;
|
|
66
|
+
} stDeviceListItem;
|
|
67
|
+
|
|
68
|
+
#endif // PACKAGES_SERIALPORT_SRC_DARWIN_LIST_H_
|
package/src/poller.cpp
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <uv.h>
|
|
3
|
+
#include "./poller.h"
|
|
4
|
+
|
|
5
|
+
Poller::Poller (const Napi::CallbackInfo &info) : Napi::ObjectWrap<Poller>(info)
|
|
6
|
+
{
|
|
7
|
+
Napi::Env env = info.Env();
|
|
8
|
+
Napi::HandleScope scope(env);
|
|
9
|
+
if (!info[0].IsNumber()) {
|
|
10
|
+
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
this->fd = info[0].As<Napi::Number>().Int32Value();
|
|
14
|
+
|
|
15
|
+
// callback
|
|
16
|
+
if (!info[1].IsFunction()) {
|
|
17
|
+
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
this->callback = Napi::Persistent(info[1].As<Napi::Function>());
|
|
21
|
+
|
|
22
|
+
this->poll_handle = new uv_poll_t();
|
|
23
|
+
memset(this->poll_handle, 0, sizeof(uv_poll_t));
|
|
24
|
+
poll_handle->data = this;
|
|
25
|
+
int status = uv_poll_init(uv_default_loop(), poll_handle, fd);
|
|
26
|
+
if (0 != status) {
|
|
27
|
+
Napi::Error::New(env, uv_strerror(status)).ThrowAsJavaScriptException();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
uv_poll_init_success = true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Poller::~Poller() {
|
|
34
|
+
// if we call uv_poll_stop after uv_poll_init failed we segfault
|
|
35
|
+
if (uv_poll_init_success) {
|
|
36
|
+
uv_poll_stop(poll_handle);
|
|
37
|
+
uv_unref(reinterpret_cast<uv_handle_t*> (poll_handle));
|
|
38
|
+
uv_close(reinterpret_cast<uv_handle_t*> (poll_handle), Poller::onClose);
|
|
39
|
+
} else {
|
|
40
|
+
delete poll_handle;
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void Poller::onClose(uv_handle_t* poll_handle) {
|
|
46
|
+
// fprintf(stdout, "~Poller is closed\n");
|
|
47
|
+
delete poll_handle;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Events can be UV_READABLE | UV_WRITABLE | UV_DISCONNECT
|
|
51
|
+
void Poller::poll(Napi::Env env, int events) {
|
|
52
|
+
Napi::HandleScope scope(env);
|
|
53
|
+
// fprintf(stdout, "Poller:poll for %d\n", events);
|
|
54
|
+
this->events = this->events | events;
|
|
55
|
+
int status = uv_poll_start(this->poll_handle, events, Poller::onData);
|
|
56
|
+
if (0 != status) {
|
|
57
|
+
Napi::Error::New(env, uv_strerror(status)).ThrowAsJavaScriptException();
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void Poller::stop(Napi::Env env) {
|
|
63
|
+
Napi::HandleScope scope(env);
|
|
64
|
+
int status = uv_poll_stop(this->poll_handle);
|
|
65
|
+
if (0 != status) {
|
|
66
|
+
Napi::Error::New(env, uv_strerror(status)).ThrowAsJavaScriptException();
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
int Poller::_stop() {
|
|
72
|
+
return uv_poll_stop(poll_handle);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void Poller::onData(uv_poll_t* handle, int status, int events) {
|
|
76
|
+
Poller* obj = static_cast<Poller*>(handle->data);
|
|
77
|
+
Napi::Env env = obj->Env();
|
|
78
|
+
Napi::HandleScope scope(env);
|
|
79
|
+
|
|
80
|
+
// if Error
|
|
81
|
+
if (0 != status) {
|
|
82
|
+
// fprintf(stdout, "OnData Error status=%s events=%d\n", uv_strerror(status), events);
|
|
83
|
+
obj->_stop(); // doesn't matter if this errors
|
|
84
|
+
obj->callback.Call({Napi::Error::New(env, uv_strerror(status)).Value(), env.Undefined()});
|
|
85
|
+
} else {
|
|
86
|
+
// fprintf(stdout, "OnData status=%d events=%d subscribed=%d\n", status, events, obj->events);
|
|
87
|
+
// remove triggered events from the poll
|
|
88
|
+
int newEvents = obj->events & ~events;
|
|
89
|
+
obj->poll(env, newEvents);
|
|
90
|
+
obj->callback.Call({env.Null(), Napi::Number::New(env, events)});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
Napi::Object Poller::Init(Napi::Env env, Napi::Object exports) {
|
|
96
|
+
Napi::Function func = DefineClass(env, "Poller", {
|
|
97
|
+
StaticMethod<&Poller::New>("New"),
|
|
98
|
+
InstanceMethod<&Poller::poll>("poll"),
|
|
99
|
+
InstanceMethod<&Poller::stop>("stop"),
|
|
100
|
+
InstanceMethod<&Poller::destroy>("destroy"),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
Napi::FunctionReference* constructor = new Napi::FunctionReference();
|
|
104
|
+
|
|
105
|
+
*constructor = Napi::Persistent(func);
|
|
106
|
+
exports.Set("Poller", func);
|
|
107
|
+
|
|
108
|
+
env.SetInstanceData<Napi::FunctionReference>(constructor);
|
|
109
|
+
|
|
110
|
+
return exports;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
Napi::Value Poller::New(const Napi::CallbackInfo& info) {
|
|
114
|
+
Napi::Env env = info.Env();
|
|
115
|
+
Napi::HandleScope scope(env);
|
|
116
|
+
|
|
117
|
+
if (!info[0].IsNumber()) {
|
|
118
|
+
Napi::TypeError::New(env, "fd must be an int").ThrowAsJavaScriptException();
|
|
119
|
+
return env.Null();
|
|
120
|
+
}
|
|
121
|
+
Napi::Value fd = info[0];
|
|
122
|
+
if (!info[1].IsFunction()) {
|
|
123
|
+
Napi::TypeError::New(env, "cb must be a function").ThrowAsJavaScriptException();
|
|
124
|
+
return env.Null();
|
|
125
|
+
}
|
|
126
|
+
Napi::Function callback = info[1].As<Napi::Function>();
|
|
127
|
+
Napi::FunctionReference* constructor = info.Env().GetInstanceData<Napi::FunctionReference>();
|
|
128
|
+
return constructor->New({fd, callback});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Napi::Value Poller::poll(const Napi::CallbackInfo& info) {
|
|
132
|
+
Napi::Env env = info.Env();
|
|
133
|
+
Napi::HandleScope scope(env);
|
|
134
|
+
Poller* obj = this;
|
|
135
|
+
if (!info[0].IsNumber()) {
|
|
136
|
+
Napi::TypeError::New(env, "events must be an int").ThrowAsJavaScriptException();
|
|
137
|
+
return env.Null();
|
|
138
|
+
}
|
|
139
|
+
int events = info[0].As<Napi::Number>().Int32Value();
|
|
140
|
+
obj->poll(env, events);
|
|
141
|
+
return env.Undefined();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
Napi::Value Poller::stop(const Napi::CallbackInfo& info) {
|
|
145
|
+
Napi::Env env = info.Env();
|
|
146
|
+
Napi::HandleScope scope(env);
|
|
147
|
+
this->stop(env);
|
|
148
|
+
return env.Undefined();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
Napi::Value Poller::destroy(const Napi::CallbackInfo& info) {
|
|
152
|
+
Napi::Env env = info.Env();
|
|
153
|
+
Napi::HandleScope scope(env);
|
|
154
|
+
Poller* obj = this;
|
|
155
|
+
// TODO Fix destruction Segfault
|
|
156
|
+
obj->Reset();
|
|
157
|
+
// delete obj;
|
|
158
|
+
return env.Undefined();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
inline Napi::FunctionReference & Poller::constructor() {
|
|
162
|
+
static Napi::FunctionReference my_constructor;
|
|
163
|
+
// TODO Check if required
|
|
164
|
+
// my_constructor.SuppressDestruct();
|
|
165
|
+
return my_constructor;
|
|
166
|
+
}
|
package/src/poller.h
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#ifndef PACKAGES_SERIALPORT_SRC_POLLER_H_
|
|
2
|
+
#define PACKAGES_SERIALPORT_SRC_POLLER_H_
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
#include <uv.h>
|
|
6
|
+
|
|
7
|
+
class Poller : public Napi::ObjectWrap<Poller> {
|
|
8
|
+
public:
|
|
9
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
10
|
+
explicit Poller(const Napi::CallbackInfo &info);
|
|
11
|
+
static Napi::Value New(const Napi::CallbackInfo& info);
|
|
12
|
+
static void onData(uv_poll_t* handle, int status, int events);
|
|
13
|
+
static void onClose(uv_handle_t* poll_handle);
|
|
14
|
+
~Poller();
|
|
15
|
+
|
|
16
|
+
private:
|
|
17
|
+
int fd;
|
|
18
|
+
uv_poll_t* poll_handle = nullptr;
|
|
19
|
+
Napi::FunctionReference callback;
|
|
20
|
+
bool uv_poll_init_success = false;
|
|
21
|
+
|
|
22
|
+
// can this be read off of poll_handle?
|
|
23
|
+
int events = 0;
|
|
24
|
+
|
|
25
|
+
void poll(Napi::Env env, int events);
|
|
26
|
+
void stop(Napi::Env env);
|
|
27
|
+
int _stop();
|
|
28
|
+
|
|
29
|
+
Napi::Value poll(const Napi::CallbackInfo& info);
|
|
30
|
+
Napi::Value stop(const Napi::CallbackInfo& info);
|
|
31
|
+
Napi::Value destroy(const Napi::CallbackInfo& info);
|
|
32
|
+
static inline Napi::FunctionReference & constructor();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
#endif // PACKAGES_SERIALPORT_SRC_POLLER_H_
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
#include "./serialport.h"
|
|
2
|
+
|
|
3
|
+
#ifdef __APPLE__
|
|
4
|
+
#include "./darwin_list.h"
|
|
5
|
+
#endif
|
|
6
|
+
|
|
7
|
+
#ifdef WIN32
|
|
8
|
+
#define strncasecmp strnicmp
|
|
9
|
+
#include "./serialport_win.h"
|
|
10
|
+
#else
|
|
11
|
+
#include "./poller.h"
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
Napi::Value getValueFromObject(Napi::Object options, std::string key) {
|
|
15
|
+
Napi::String str = Napi::String::New(options.Env(), key);
|
|
16
|
+
return (options).Get(str);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
int getIntFromObject(Napi::Object options, std::string key) {
|
|
20
|
+
return getValueFromObject(options, key).ToNumber().Int64Value();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
bool getBoolFromObject(Napi::Object options, std::string key) {
|
|
24
|
+
return getValueFromObject(options, key).ToBoolean().Value();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Napi::String getStringFromObj(Napi::Object options, std::string key) {
|
|
28
|
+
return getValueFromObject(options, key).ToString();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
double getDoubleFromObject(Napi::Object options, std::string key) {
|
|
32
|
+
return getValueFromObject(options, key).ToNumber().DoubleValue();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Napi::Value Open(const Napi::CallbackInfo& info) {
|
|
36
|
+
Napi::Env env = info.Env();
|
|
37
|
+
// path
|
|
38
|
+
if (!info[0].IsString()) {
|
|
39
|
+
Napi::TypeError::New(env, "First argument must be a string").ThrowAsJavaScriptException();
|
|
40
|
+
return env.Null();
|
|
41
|
+
}
|
|
42
|
+
std::string path = info[0].ToString().Utf8Value();
|
|
43
|
+
|
|
44
|
+
// options
|
|
45
|
+
if (!info[1].IsObject()) {
|
|
46
|
+
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
|
|
47
|
+
return env.Null();
|
|
48
|
+
}
|
|
49
|
+
Napi::Object options = info[1].ToObject();
|
|
50
|
+
|
|
51
|
+
// callback
|
|
52
|
+
if (!info[2].IsFunction()) {
|
|
53
|
+
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
|
|
54
|
+
return env.Null();
|
|
55
|
+
}
|
|
56
|
+
Napi::Function callback = info[2].As<Napi::Function>();
|
|
57
|
+
OpenBaton* baton = new OpenBaton(callback);
|
|
58
|
+
snprintf(baton->path, sizeof(baton->path), "%s", path.c_str());
|
|
59
|
+
baton->baudRate = getIntFromObject(options, "baudRate");
|
|
60
|
+
baton->dataBits = getIntFromObject(options, "dataBits");
|
|
61
|
+
baton->parity = ToParityEnum(getStringFromObj(options, "parity"));
|
|
62
|
+
baton->stopBits = ToStopBitEnum(getDoubleFromObject(options, "stopBits"));
|
|
63
|
+
baton->rtscts = getBoolFromObject(options, "rtscts");
|
|
64
|
+
baton->rtsMode = ToRtsModeEnum(getStringFromObj(options, "rtsMode"));
|
|
65
|
+
baton->xon = getBoolFromObject(options, "xon");
|
|
66
|
+
baton->xoff = getBoolFromObject(options, "xoff");
|
|
67
|
+
baton->xany = getBoolFromObject(options, "xany");
|
|
68
|
+
baton->hupcl = getBoolFromObject(options, "hupcl");
|
|
69
|
+
baton->lock = getBoolFromObject(options, "lock");
|
|
70
|
+
|
|
71
|
+
#ifndef WIN32
|
|
72
|
+
baton->vmin = getIntFromObject(options, "vmin");
|
|
73
|
+
baton->vtime = getIntFromObject(options, "vtime");
|
|
74
|
+
#endif
|
|
75
|
+
|
|
76
|
+
baton->Queue();
|
|
77
|
+
return env.Undefined();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
Napi::Value Update(const Napi::CallbackInfo& info) {
|
|
81
|
+
Napi::Env env = info.Env();
|
|
82
|
+
// file descriptor
|
|
83
|
+
if (!info[0].IsNumber()) {
|
|
84
|
+
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
|
85
|
+
return env.Null();
|
|
86
|
+
}
|
|
87
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
88
|
+
|
|
89
|
+
// options
|
|
90
|
+
if (!info[1].IsObject()) {
|
|
91
|
+
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
|
|
92
|
+
return env.Null();
|
|
93
|
+
}
|
|
94
|
+
Napi::Object options = info[1].ToObject();
|
|
95
|
+
|
|
96
|
+
if (!(options).Has("baudRate")) {
|
|
97
|
+
Napi::TypeError::New(env, "\"baudRate\" must be set on options object").ThrowAsJavaScriptException();
|
|
98
|
+
return env.Null();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// callback
|
|
102
|
+
if (!info[2].IsFunction()) {
|
|
103
|
+
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
|
|
104
|
+
return env.Null();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
Napi::Function callback = info[2].As<Napi::Function>();
|
|
108
|
+
ConnectionOptionsBaton* baton = new ConnectionOptionsBaton(callback);
|
|
109
|
+
|
|
110
|
+
baton->fd = fd;
|
|
111
|
+
baton->baudRate = getIntFromObject(options, "baudRate");
|
|
112
|
+
|
|
113
|
+
baton->Queue();
|
|
114
|
+
return env.Undefined();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
Napi::Value Close(const Napi::CallbackInfo& info) {
|
|
118
|
+
Napi::Env env = info.Env();
|
|
119
|
+
// file descriptor
|
|
120
|
+
if (!info[0].IsNumber()) {
|
|
121
|
+
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
|
122
|
+
return env.Null();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// callback
|
|
126
|
+
if (!info[1].IsFunction()) {
|
|
127
|
+
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
|
128
|
+
return env.Null();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Napi::Function callback = info[1].As<Napi::Function>();
|
|
132
|
+
CloseBaton* baton = new CloseBaton(callback);
|
|
133
|
+
baton->fd = info[0].ToNumber().Int64Value();;
|
|
134
|
+
|
|
135
|
+
baton->Queue();
|
|
136
|
+
return env.Undefined();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Napi::Value Flush(const Napi::CallbackInfo& info) {
|
|
140
|
+
Napi::Env env = info.Env();
|
|
141
|
+
// file descriptor
|
|
142
|
+
if (!info[0].IsNumber()) {
|
|
143
|
+
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
|
144
|
+
return env.Null();
|
|
145
|
+
}
|
|
146
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
147
|
+
|
|
148
|
+
// callback
|
|
149
|
+
if (!info[1].IsFunction()) {
|
|
150
|
+
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
|
151
|
+
return env.Null();
|
|
152
|
+
}
|
|
153
|
+
Napi::Function callback = info[1].As<Napi::Function>();
|
|
154
|
+
|
|
155
|
+
FlushBaton* baton = new FlushBaton(callback);
|
|
156
|
+
baton->fd = fd;
|
|
157
|
+
|
|
158
|
+
baton->Queue();
|
|
159
|
+
return env.Undefined();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
Napi::Value Set(const Napi::CallbackInfo& info) {
|
|
163
|
+
Napi::Env env = info.Env();
|
|
164
|
+
// file descriptor
|
|
165
|
+
if (!info[0].IsNumber()) {
|
|
166
|
+
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
|
167
|
+
return env.Null();
|
|
168
|
+
}
|
|
169
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
170
|
+
|
|
171
|
+
// options
|
|
172
|
+
if (!info[1].IsObject()) {
|
|
173
|
+
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
|
|
174
|
+
return env.Null();
|
|
175
|
+
}
|
|
176
|
+
Napi::Object options = info[1].ToObject();
|
|
177
|
+
|
|
178
|
+
// callback
|
|
179
|
+
if (!info[2].IsFunction()) {
|
|
180
|
+
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
|
|
181
|
+
return env.Null();
|
|
182
|
+
}
|
|
183
|
+
Napi::Function callback = info[2].As<Napi::Function>();
|
|
184
|
+
|
|
185
|
+
SetBaton* baton = new SetBaton(callback);
|
|
186
|
+
baton->fd = fd;
|
|
187
|
+
baton->brk = getBoolFromObject(options, "brk");
|
|
188
|
+
baton->rts = getBoolFromObject(options, "rts");
|
|
189
|
+
baton->cts = getBoolFromObject(options, "cts");
|
|
190
|
+
baton->dtr = getBoolFromObject(options, "dtr");
|
|
191
|
+
baton->dsr = getBoolFromObject(options, "dsr");
|
|
192
|
+
baton->lowLatency = getBoolFromObject(options, "lowLatency");
|
|
193
|
+
|
|
194
|
+
baton->Queue();
|
|
195
|
+
return env.Undefined();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
Napi::Value Get(const Napi::CallbackInfo& info) {
|
|
199
|
+
Napi::Env env = info.Env();
|
|
200
|
+
// file descriptor
|
|
201
|
+
if (!info[0].IsNumber()) {
|
|
202
|
+
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
|
203
|
+
return env.Null();
|
|
204
|
+
}
|
|
205
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
206
|
+
|
|
207
|
+
// callback
|
|
208
|
+
if (!info[1].IsFunction()) {
|
|
209
|
+
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
|
210
|
+
return env.Null();
|
|
211
|
+
}
|
|
212
|
+
Napi::Function callback = info[1].As<Napi::Function>();
|
|
213
|
+
|
|
214
|
+
GetBaton* baton = new GetBaton(callback);
|
|
215
|
+
baton->fd = fd;
|
|
216
|
+
baton->cts = false;
|
|
217
|
+
baton->dsr = false;
|
|
218
|
+
baton->dcd = false;
|
|
219
|
+
baton->lowLatency = false;
|
|
220
|
+
|
|
221
|
+
baton->Queue();
|
|
222
|
+
return env.Undefined();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
Napi::Value GetBaudRate(const Napi::CallbackInfo& info) {
|
|
226
|
+
Napi::Env env = info.Env();
|
|
227
|
+
// file descriptor
|
|
228
|
+
if (!info[0].IsNumber()) {
|
|
229
|
+
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
|
230
|
+
return env.Null();
|
|
231
|
+
}
|
|
232
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
233
|
+
|
|
234
|
+
// callback
|
|
235
|
+
if (!info[1].IsFunction()) {
|
|
236
|
+
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
|
237
|
+
return env.Null();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
Napi::Function callback = info[1].As<Napi::Function>();
|
|
241
|
+
GetBaudRateBaton* baton = new GetBaudRateBaton(callback);
|
|
242
|
+
baton->fd = fd;
|
|
243
|
+
baton->baudRate = 0;
|
|
244
|
+
|
|
245
|
+
baton->Queue();
|
|
246
|
+
return env.Undefined();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
Napi::Value Drain(const Napi::CallbackInfo& info) {
|
|
250
|
+
Napi::Env env = info.Env();
|
|
251
|
+
// file descriptor
|
|
252
|
+
if (!info[0].IsNumber()) {
|
|
253
|
+
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
|
254
|
+
return env.Null();
|
|
255
|
+
}
|
|
256
|
+
int fd = info[0].As<Napi::Number>().Int32Value();
|
|
257
|
+
|
|
258
|
+
// callback
|
|
259
|
+
if (!info[1].IsFunction()) {
|
|
260
|
+
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
|
261
|
+
return env.Null();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
Napi::Function callback = info[1].As<Napi::Function>();
|
|
265
|
+
DrainBaton* baton = new DrainBaton(callback);
|
|
266
|
+
baton->fd = fd;
|
|
267
|
+
|
|
268
|
+
baton->Queue();
|
|
269
|
+
return env.Undefined();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
inline SerialPortParity ToParityEnum(const Napi::String& napistr) {
|
|
273
|
+
auto tmp = napistr.Utf8Value();
|
|
274
|
+
const char* str = tmp.c_str();
|
|
275
|
+
|
|
276
|
+
size_t count = strlen(str);
|
|
277
|
+
SerialPortParity parity = SERIALPORT_PARITY_NONE;
|
|
278
|
+
if (!strncasecmp(str, "none", count)) {
|
|
279
|
+
parity = SERIALPORT_PARITY_NONE;
|
|
280
|
+
} else if (!strncasecmp(str, "even", count)) {
|
|
281
|
+
parity = SERIALPORT_PARITY_EVEN;
|
|
282
|
+
} else if (!strncasecmp(str, "mark", count)) {
|
|
283
|
+
parity = SERIALPORT_PARITY_MARK;
|
|
284
|
+
} else if (!strncasecmp(str, "odd", count)) {
|
|
285
|
+
parity = SERIALPORT_PARITY_ODD;
|
|
286
|
+
} else if (!strncasecmp(str, "space", count)) {
|
|
287
|
+
parity = SERIALPORT_PARITY_SPACE;
|
|
288
|
+
}
|
|
289
|
+
return parity;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
inline SerialPortStopBits ToStopBitEnum(double stopBits) {
|
|
293
|
+
if (stopBits > 1.4 && stopBits < 1.6) {
|
|
294
|
+
return SERIALPORT_STOPBITS_ONE_FIVE;
|
|
295
|
+
}
|
|
296
|
+
if (stopBits == 2) {
|
|
297
|
+
return SERIALPORT_STOPBITS_TWO;
|
|
298
|
+
}
|
|
299
|
+
return SERIALPORT_STOPBITS_ONE;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
inline SerialPortRtsMode ToRtsModeEnum(const Napi::String& napistr) {
|
|
303
|
+
auto tmp = napistr.Utf8Value();
|
|
304
|
+
const char* str = tmp.c_str();
|
|
305
|
+
|
|
306
|
+
size_t count = strlen(str);
|
|
307
|
+
SerialPortRtsMode mode = SERIALPORT_RTSMODE_HANDSHAKE;
|
|
308
|
+
if (!strncasecmp(str, "enable", count)) {
|
|
309
|
+
mode = SERIALPORT_RTSMODE_ENABLE;
|
|
310
|
+
} else if (!strncasecmp(str, "handshake", count)) {
|
|
311
|
+
mode = SERIALPORT_RTSMODE_HANDSHAKE;
|
|
312
|
+
} else if (!strncasecmp(str, "toggle", count)) {
|
|
313
|
+
mode = SERIALPORT_RTSMODE_TOGGLE;
|
|
314
|
+
}
|
|
315
|
+
return mode;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
Napi::Object init(Napi::Env env, Napi::Object exports) {
|
|
319
|
+
exports.Set("set", Napi::Function::New(env, Set));
|
|
320
|
+
exports.Set("get", Napi::Function::New(env, Get));
|
|
321
|
+
exports.Set("getBaudRate", Napi::Function::New(env, GetBaudRate));
|
|
322
|
+
exports.Set("open", Napi::Function::New(env, Open));
|
|
323
|
+
exports.Set("update", Napi::Function::New(env, Update));
|
|
324
|
+
exports.Set("close", Napi::Function::New(env, Close));
|
|
325
|
+
exports.Set("flush", Napi::Function::New(env, Flush));
|
|
326
|
+
exports.Set("drain", Napi::Function::New(env, Drain));
|
|
327
|
+
|
|
328
|
+
#ifdef __APPLE__
|
|
329
|
+
exports.Set("list", Napi::Function::New(env, List));
|
|
330
|
+
#endif
|
|
331
|
+
|
|
332
|
+
#ifdef WIN32
|
|
333
|
+
exports.Set("write", Napi::Function::New(env, Write));
|
|
334
|
+
exports.Set("read", Napi::Function::New(env, Read));
|
|
335
|
+
exports.Set("list", Napi::Function::New(env, List));
|
|
336
|
+
#else
|
|
337
|
+
Poller::Init(env, exports);
|
|
338
|
+
#endif
|
|
339
|
+
return exports;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
NODE_API_MODULE(serialport, init);
|