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

More robust serial connection establishment & error handling #4

Merged
merged 8 commits into from
Oct 13, 2014
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
2 changes: 1 addition & 1 deletion examples/adjustable-baud.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var arduino = require('../');
var board = new arduino.Board({
debug: true,
baudrate: 9600
});
}).setup();

var led = new arduino.Led({
board: board,
Expand Down
4 changes: 2 additions & 2 deletions examples/adjustable-port.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var arduino = require('../');
var board = new arduino.Board({
debug: true,
device: "ACM"
});
}).setup();

var led = new arduino.Led({
board: board,
Expand All @@ -12,4 +12,4 @@ var led = new arduino.Led({

board.on('ready', function(){
led.blink();
});
});
2 changes: 1 addition & 1 deletion examples/analogled.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ var arduino = require('../');

var board = new arduino.Board({
debug: true
});
}).setup();

var aled = new arduino.Led({
board: board,
Expand Down
2 changes: 1 addition & 1 deletion examples/basic.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

var arduino = require('../');

var board = new arduino.Board();
var board = new arduino.Board().setup();

board.on('connected', function(){
board.write('HELLO WORLD');
Expand Down
2 changes: 1 addition & 1 deletion examples/button.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var arduino = require('../');

var board = new arduino.Board();
var board = new arduino.Board().setup();

var button = new arduino.Button({
board: board,
Expand Down
2 changes: 1 addition & 1 deletion examples/combination.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var arduino = require('../');

var board = new arduino.Board();
var board = new arduino.Board().setup();

var button = new arduino.Button({
board: board,
Expand Down
2 changes: 1 addition & 1 deletion examples/ir.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var arduino = require('../')

var board = new arduino.Board({
debug: true
});
}).setup();

var ir = new arduino.IR({
board: board
Expand Down
4 changes: 2 additions & 2 deletions examples/led.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ var arduino = require('../');

var board = new arduino.Board({
debug: true
});
}).setup();

var led = new arduino.Led({
board: board,
pin: "A0"
pin: "13"
});

board.on('ready', function(){
Expand Down
2 changes: 1 addition & 1 deletion examples/piezo.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ var arduino = require('../');

var board = new arduino.Board({
debug: true
});
}).setup();

var piezo = new arduino.Piezo({
board: board
Expand Down
2 changes: 1 addition & 1 deletion examples/ping.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var arduino = require('../'),

board = new arduino.Board({
debug: false
});
}).setup();

ping = new arduino.Ping({
board: board,
Expand Down
2 changes: 1 addition & 1 deletion examples/pir.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var arduino = require('../'),

board = new arduino.Board({
debug: false
});
}).setup();

pir = new arduino.PIR({
board: board,
Expand Down
2 changes: 1 addition & 1 deletion examples/rc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var arduino = require('../')

var board = new arduino.Board({
debug: true
});
}).setup();

var rc = new arduino.RC({
board: board,
Expand Down
2 changes: 1 addition & 1 deletion examples/sensor-throttled.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var arduino = require('../'),

board = new arduino.Board({
debug: false
});
}).setup();

sensor = new arduino.Sensor({
board: board,
Expand Down
2 changes: 1 addition & 1 deletion examples/sensor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var arduino = require('../'),

board = new arduino.Board({
debug: true
});
}).setup();

sensor = new arduino.Sensor({
board: board,
Expand Down
2 changes: 1 addition & 1 deletion examples/servo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var arduino = require('../'),
// Construct instances
board = new arduino.Board({
debug: true
});
}).setup();

led = new arduino.Led({
board: board,
Expand Down
139 changes: 84 additions & 55 deletions lib/board.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

var events = require('events'),
child = require('child_process'),
util = require('util'),
Expand All @@ -7,24 +6,37 @@ var events = require('events'),

/*
* The main Arduino constructor
* Connect to the serial port and bind
*
* [NEW] Does *not* open a serial connection. Add a `setup()` call to do so.
*
* This allows the user to add a listener for error events that occur
* during the serial connection attempts.
*/
var Board = function (options) {
this.log('info', 'initializing');
this.debug = options && options.debug || false;
this.device = options && options.device || 'usb|ttyACM*|ttyS0';
this.debug = options && options.debug || false;
this.devregex = options && options.devregex || 'usb|ttyACM*|ttyS0';
this.baudrate = options && options.baudrate || 115200;
this.writeBuffer = [];
}

/*
* EventEmitter, I choose you!
*/
util.inherits(Board, events.EventEmitter);

/*
* Establish the serial connection
*
* Tries to open a serial connection with `connectSerial()`.
* If successful, the connection is initialized ("clearing bytes", debug mode).
* If unsuccessful, error event is emitted; if no listeners: error is thrown.
*/
Board.prototype.setup = function() {
var self = this;
this.detect(function (err, serial) {
if (err) {
if(self.listeners('error').length)
self.emit('error', err);
else
throw new Error(err);
}else{
self.serial = serial;
this.connectSerial(function(found) {
if (found) {
self.serial = found;
self.emit('connected');

self.log('info', 'binding serial events');
Expand Down Expand Up @@ -56,52 +68,70 @@ var Board = function (options) {

self.emit('ready');
}, 500);
} else {
msg = "Could not establish Serial connection to Arduino.";
if (self.listeners('error').length > 0) {
self.emit('error', msg);
} else {
throw new Error(msg);
}
}
});
return this;
}

/*
* EventEmitter, I choose you!
*/
util.inherits(Board, events.EventEmitter);

/*
* Detect an Arduino board
* Loop through all USB devices and try to connect
* This should really message the device and wait for a correct response
* (Tries to) Open serial connection with Arduino (formerly named `detect()`)
*
* Loops through devices matching `devregex` and naively tries to open a serial
* connection with each until one succeeds.
* This should really message the device and wait for a correct response to
* ensure that we're actually connected to an Arduino running `duino`. FIXME
*
* Returns false if no serial connection could be established.
*/
Board.prototype.detect = function (callback) {
Board.prototype.connectSerial = function (callback) {
this.log('info', 'attempting to find Arduino board');
var self = this;
child.exec('ls /dev | grep -E "'+ self.device +'"', function(err, stdout, stderr){
var usb = stdout.slice(0, -1).split('\n'),
found = false,
err = null,
possible, temp;

while ( usb.length ) {
possible = usb.pop();

if (possible.slice(0, 2) !== 'cu') {
try {
temp = new serial.SerialPort('/dev/' + possible, {
baudrate: self.baudrate,
parser: serial.parsers.readline('\n')
});
} catch (e) {
err = e;
}
if (!err) {
found = temp;
self.log('info', 'found board at ' + temp.port);
break;
} else {
err = new Error('Could not find Arduino');
}
}
child.exec('ls /dev | grep -E "'+ self.devregex +'"', function(err, stdout, stderr){

function skipUnwanted(e) {
return (e !== '') && (e.slice(0, 2) !== 'cu');
}

callback(err, found);
var devices = stdout.slice(0, -1).split('\n').filter(skipUnwanted),
device,
candidate;

// loop over list of possible Arduinos
// do not stop (even/especially on error, that's the point!) until
// - we run out of options, or
// - a serial connection is established
var success = devices.some(function(device) {
try {
self.log('debug', 'attempting to open serial conn.: ' + device);
candidate = new serial.SerialPort('/dev/' + device, {
baudrate: self.baudrate,
parser: serial.parsers.readline('\n')
});

// connection succeeded, though we don't test whether it's an Arduino
self.log('info', 'found board at /dev/' + device);
return true;

} catch (e) {
// ignore error and cont.
self.log('warning', 'error while establishing serial connection with'
+ '/dev/' + device + '; trying next');
return false;
}
});

if (success) {
callback(candidate);
} else {
callback(false);
}
});
}

Expand Down Expand Up @@ -137,18 +167,17 @@ Board.prototype.write = function (m) {
}
}

/*
* Add a 0 to the front of a single-digit pin number
*/
// Add a 0 to the front of a single-digit pin number
Board.prototype.normalizePin = function (pin) {
return this.lpad( 2, '0', pin );
}

// Left-pad values with 0s so it has three digits.
Board.prototype.normalizeVal = function(val) {
return this.lpad( 3, '0', val );
return this.lpad( 3, '0', val );
}

//
// Left-pad `str` with `chr` and return the last `len` digits
Board.prototype.lpad = function(len, chr, str) {
return (Array(len + 1).join(chr || ' ') + str).substr(-len);
};
Expand Down Expand Up @@ -210,8 +239,8 @@ Board.prototype.analogRead = function (pin) {
* Utility function to pause for a given time
*/
Board.prototype.delay = function (ms) {
ms += +new Date();
while (+new Date() < ms) { }
ms += Date.now();
while (Date.now() < ms) { }
}

/*
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
],
"name": "duino",
"description": "Arduino framework for mad scientists",
"version": "0.0.11",
"version": "0.1.0",
"keywords": [
"arduino",
"serial",
Expand Down
Loading