Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect serial device disconnect on linux while polling #393

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 28 additions & 18 deletions serialport.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,13 @@ function SerialPortFactory() {
options.parser(self, data);
};

options.disconnectedCallback = options.disconnectedCallback || function () {
options.disconnectedCallback = options.disconnectedCallback || function (err) {
if (self.closing) {
return;
}
var err = new Error("Disconnected");
if(!err) {
err = new Error("Disconnected");
}
self.emit("disconnect",err);
};

Expand Down Expand Up @@ -196,7 +198,13 @@ function SerialPortFactory() {
}
if (process.platform !== 'win32') {
self.paused = false;
self.serialPoller = new factory.SerialPortBinding.SerialportPoller(self.fd, function () { self._read(); });
self.serialPoller = new factory.SerialPortBinding.SerialportPoller(self.fd, function (err) {
if(!err) {
self._read();
} else {
self.disconnected(err);
}
});
self.serialPoller.start();
}

Expand Down Expand Up @@ -263,16 +271,14 @@ function SerialPortFactory() {
function afterRead(err, bytesRead, readPool, bytesRequested) {
self.reading = false;
if (err) {

if (err.code && err.code === 'EAGAIN') {
if (self.fd >= 0) {
self.serialPoller.start();
}
} else if (err.code && (err.code === "EBADF" || err.code === 'ENXIO' || (err.errno===-1 || err.code === 'UNKNOWN'))) { // handle edge case were mac/unix doesn't clearly know the error.
self.disconnected();
self.disconnected(err);
} else {
self.fd = null;
// console.log("afterRead");
self.emit('error', err);
self.readable = false;
}
Expand Down Expand Up @@ -346,15 +352,15 @@ function SerialPortFactory() {
} // if !'win32'


SerialPort.prototype.disconnected = function (callback) {
SerialPort.prototype.disconnected = function (err) {
var self = this;
var fd = self.fd;

// send notification of disconnect
if (self.options.disconnectedCallback) {
self.options.disconnectedCallback();
self.options.disconnectedCallback(err);
} else {
self.emit("disconnect");
self.emit("disconnect", err);
}
self.paused = true;
self.closing = true;
Expand All @@ -366,9 +372,14 @@ function SerialPortFactory() {

try {
factory.SerialPortBinding.close(fd, function (err) {
if(err) {
console.log('Disconnect completed with error:' + err);
} else {
console.log('Disconnect completed');
}
});
} catch (e) {
//handle silently as we are just cleaning up the OS.
console.log('Disconnect failed with exception', e);
}

self.removeAllListeners();
Expand All @@ -380,9 +391,6 @@ function SerialPortFactory() {
self.serialPoller.close();
}

if (callback) {
callback();
}
};


Expand All @@ -406,6 +414,13 @@ function SerialPortFactory() {
}

self.closing = true;

// Stop polling before closing the port.
if (process.platform !== 'win32') {
self.readable = false;
self.serialPoller.close();
}

try {
factory.SerialPortBinding.close(fd, function (err) {

Expand All @@ -424,11 +439,6 @@ function SerialPortFactory() {
self.closing = false;
self.fd = 0;

if (process.platform !== 'win32') {
self.readable = false;
self.serialPoller.close();
}

if (callback) {
callback();
}
Expand Down
1 change: 1 addition & 0 deletions src/serialport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ void EIO_AfterWrite(uv_work_t* req) {
// We're not done with this baton, so throw it right back onto the queue.
// Don't re-push the write in the event loop if there was an error; because same error could occur again!
// TODO: Add a uv_poll here for unix...
fprintf(stderr, "Write again...\n");
uv_queue_work(uv_default_loop(), req, EIO_Write, (uv_after_work_cb)EIO_AfterWrite);
return;
}
Expand Down
31 changes: 24 additions & 7 deletions src/serialport_poller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,38 @@ SerialportPoller::~SerialportPoller() {
};

void _serialportReadable(uv_poll_t *req, int status, int events) {
SerialportPoller* obj = (SerialportPoller*) req->data;

SerialportPoller* sp = (SerialportPoller*) req->data;
// We can stop polling until we have read all of the data...
obj->_stop();

obj->callCallback();
sp->_stop();
sp->callCallback(status);
}

void SerialportPoller::callCallback() {
void SerialportPoller::callCallback(int status) {
// uv_work_t* req = new uv_work_t;

// Call the callback to go read more data...
callback_->Call(0, NULL); //2, argv

v8::Handle<v8::Value> argv[1];
if(status != 0) {
// error handling changed in libuv, see:
// https://github.com/joyent/libuv/commit/3ee4d3f183331
#ifdef UV_ERRNO_H_
const char* err_string = uv_strerror(status);
#else
uv_err_t errno = uv_last_error(uv_default_loop());
const char* err_string = uv_strerror(errno);
#endif
snprintf(this->errorString, sizeof(this->errorString), "Error %s on polling", err_string);
argv[0] = v8::Exception::Error(NanNew<v8::String>(this->errorString));
} else {
argv[0] = NanUndefined();
}

callback_->Call(1, argv);
}



void SerialportPoller::Init(Handle<Object> target) {
NanScope();

Expand Down
4 changes: 3 additions & 1 deletion src/serialport_poller.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
#define SERIALPORT_POLLER_H

#include <nan.h>
#include "serialport.h"

class SerialportPoller : public node::ObjectWrap {
public:
static void Init(v8::Handle<v8::Object> target);

void callCallback();
void callCallback(int status);

void _start();
void _stop();
Expand All @@ -26,6 +27,7 @@ class SerialportPoller : public node::ObjectWrap {

uv_poll_t poll_handle_;
int fd_;
char errorString[ERROR_STRING_SIZE];

NanCallback* callback_;
};
Expand Down
2 changes: 1 addition & 1 deletion src/serialport_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void EIO_Open(uv_work_t* req) {
}


int flags = (O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
int flags = (O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC | O_SYNC);
int fd = open(data->path, flags);

if (fd == -1) {
Expand Down