Files
Plastic-Raspi-5/node_modules/@serialport/bindings-cpp/src/serialport.cpp

343 lines
10 KiB
C++

#include "./serialport.h"
#ifdef __APPLE__
#include "./darwin_list.h"
#endif
#ifdef WIN32
#define strncasecmp strnicmp
#include "./serialport_win.h"
#else
#include "./poller.h"
#endif
Napi::Value getValueFromObject(Napi::Object options, std::string key) {
Napi::String str = Napi::String::New(options.Env(), key);
return (options).Get(str);
}
int getIntFromObject(Napi::Object options, std::string key) {
return getValueFromObject(options, key).ToNumber().Int64Value();
}
bool getBoolFromObject(Napi::Object options, std::string key) {
return getValueFromObject(options, key).ToBoolean().Value();
}
Napi::String getStringFromObj(Napi::Object options, std::string key) {
return getValueFromObject(options, key).ToString();
}
double getDoubleFromObject(Napi::Object options, std::string key) {
return getValueFromObject(options, key).ToNumber().DoubleValue();
}
Napi::Value Open(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// path
if (!info[0].IsString()) {
Napi::TypeError::New(env, "First argument must be a string").ThrowAsJavaScriptException();
return env.Null();
}
std::string path = info[0].ToString().Utf8Value();
// options
if (!info[1].IsObject()) {
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Object options = info[1].ToObject();
// callback
if (!info[2].IsFunction()) {
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function callback = info[2].As<Napi::Function>();
OpenBaton* baton = new OpenBaton(callback);
snprintf(baton->path, sizeof(baton->path), "%s", path.c_str());
baton->baudRate = getIntFromObject(options, "baudRate");
baton->dataBits = getIntFromObject(options, "dataBits");
baton->parity = ToParityEnum(getStringFromObj(options, "parity"));
baton->stopBits = ToStopBitEnum(getDoubleFromObject(options, "stopBits"));
baton->rtscts = getBoolFromObject(options, "rtscts");
baton->rtsMode = ToRtsModeEnum(getStringFromObj(options, "rtsMode"));
baton->xon = getBoolFromObject(options, "xon");
baton->xoff = getBoolFromObject(options, "xoff");
baton->xany = getBoolFromObject(options, "xany");
baton->hupcl = getBoolFromObject(options, "hupcl");
baton->lock = getBoolFromObject(options, "lock");
#ifndef WIN32
baton->vmin = getIntFromObject(options, "vmin");
baton->vtime = getIntFromObject(options, "vtime");
#endif
baton->Queue();
return env.Undefined();
}
Napi::Value Update(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// file descriptor
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
return env.Null();
}
int fd = info[0].As<Napi::Number>().Int32Value();
// options
if (!info[1].IsObject()) {
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Object options = info[1].ToObject();
if (!(options).Has("baudRate")) {
Napi::TypeError::New(env, "\"baudRate\" must be set on options object").ThrowAsJavaScriptException();
return env.Null();
}
// callback
if (!info[2].IsFunction()) {
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function callback = info[2].As<Napi::Function>();
ConnectionOptionsBaton* baton = new ConnectionOptionsBaton(callback);
baton->fd = fd;
baton->baudRate = getIntFromObject(options, "baudRate");
baton->Queue();
return env.Undefined();
}
Napi::Value Close(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// file descriptor
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
return env.Null();
}
// callback
if (!info[1].IsFunction()) {
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function callback = info[1].As<Napi::Function>();
CloseBaton* baton = new CloseBaton(callback);
baton->fd = info[0].ToNumber().Int64Value();;
baton->Queue();
return env.Undefined();
}
Napi::Value Flush(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// file descriptor
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
return env.Null();
}
int fd = info[0].As<Napi::Number>().Int32Value();
// callback
if (!info[1].IsFunction()) {
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function callback = info[1].As<Napi::Function>();
FlushBaton* baton = new FlushBaton(callback);
baton->fd = fd;
baton->Queue();
return env.Undefined();
}
Napi::Value Set(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// file descriptor
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
return env.Null();
}
int fd = info[0].As<Napi::Number>().Int32Value();
// options
if (!info[1].IsObject()) {
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Object options = info[1].ToObject();
// callback
if (!info[2].IsFunction()) {
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function callback = info[2].As<Napi::Function>();
SetBaton* baton = new SetBaton(callback);
baton->fd = fd;
baton->brk = getBoolFromObject(options, "brk");
baton->rts = getBoolFromObject(options, "rts");
baton->cts = getBoolFromObject(options, "cts");
baton->dtr = getBoolFromObject(options, "dtr");
baton->dsr = getBoolFromObject(options, "dsr");
baton->lowLatency = getBoolFromObject(options, "lowLatency");
baton->Queue();
return env.Undefined();
}
Napi::Value Get(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// file descriptor
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
return env.Null();
}
int fd = info[0].As<Napi::Number>().Int32Value();
// callback
if (!info[1].IsFunction()) {
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function callback = info[1].As<Napi::Function>();
GetBaton* baton = new GetBaton(callback);
baton->fd = fd;
baton->cts = false;
baton->dsr = false;
baton->dcd = false;
baton->lowLatency = false;
baton->Queue();
return env.Undefined();
}
Napi::Value GetBaudRate(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// file descriptor
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
return env.Null();
}
int fd = info[0].As<Napi::Number>().Int32Value();
// callback
if (!info[1].IsFunction()) {
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function callback = info[1].As<Napi::Function>();
GetBaudRateBaton* baton = new GetBaudRateBaton(callback);
baton->fd = fd;
baton->baudRate = 0;
baton->Queue();
return env.Undefined();
}
Napi::Value Drain(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// file descriptor
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
return env.Null();
}
int fd = info[0].As<Napi::Number>().Int32Value();
// callback
if (!info[1].IsFunction()) {
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
Napi::Function callback = info[1].As<Napi::Function>();
DrainBaton* baton = new DrainBaton(callback);
baton->fd = fd;
baton->Queue();
return env.Undefined();
}
inline SerialPortParity ToParityEnum(const Napi::String& napistr) {
auto tmp = napistr.Utf8Value();
const char* str = tmp.c_str();
size_t count = strlen(str);
SerialPortParity parity = SERIALPORT_PARITY_NONE;
if (!strncasecmp(str, "none", count)) {
parity = SERIALPORT_PARITY_NONE;
} else if (!strncasecmp(str, "even", count)) {
parity = SERIALPORT_PARITY_EVEN;
} else if (!strncasecmp(str, "mark", count)) {
parity = SERIALPORT_PARITY_MARK;
} else if (!strncasecmp(str, "odd", count)) {
parity = SERIALPORT_PARITY_ODD;
} else if (!strncasecmp(str, "space", count)) {
parity = SERIALPORT_PARITY_SPACE;
}
return parity;
}
inline SerialPortStopBits ToStopBitEnum(double stopBits) {
if (stopBits > 1.4 && stopBits < 1.6) {
return SERIALPORT_STOPBITS_ONE_FIVE;
}
if (stopBits == 2) {
return SERIALPORT_STOPBITS_TWO;
}
return SERIALPORT_STOPBITS_ONE;
}
inline SerialPortRtsMode ToRtsModeEnum(const Napi::String& napistr) {
auto tmp = napistr.Utf8Value();
const char* str = tmp.c_str();
size_t count = strlen(str);
SerialPortRtsMode mode = SERIALPORT_RTSMODE_HANDSHAKE;
if (!strncasecmp(str, "enable", count)) {
mode = SERIALPORT_RTSMODE_ENABLE;
} else if (!strncasecmp(str, "handshake", count)) {
mode = SERIALPORT_RTSMODE_HANDSHAKE;
} else if (!strncasecmp(str, "toggle", count)) {
mode = SERIALPORT_RTSMODE_TOGGLE;
}
return mode;
}
Napi::Object init(Napi::Env env, Napi::Object exports) {
exports.Set("set", Napi::Function::New(env, Set));
exports.Set("get", Napi::Function::New(env, Get));
exports.Set("getBaudRate", Napi::Function::New(env, GetBaudRate));
exports.Set("open", Napi::Function::New(env, Open));
exports.Set("update", Napi::Function::New(env, Update));
exports.Set("close", Napi::Function::New(env, Close));
exports.Set("flush", Napi::Function::New(env, Flush));
exports.Set("drain", Napi::Function::New(env, Drain));
#ifdef __APPLE__
exports.Set("list", Napi::Function::New(env, List));
#endif
#ifdef WIN32
exports.Set("write", Napi::Function::New(env, Write));
exports.Set("read", Napi::Function::New(env, Read));
exports.Set("list", Napi::Function::New(env, List));
#else
Poller::Init(env, exports);
#endif
return exports;
}
NODE_API_MODULE(serialport, init);