diff --git a/examples/adjustable-baud.js b/examples/adjustable-baud.js index f897045..6e1b8f0 100644 --- a/examples/adjustable-baud.js +++ b/examples/adjustable-baud.js @@ -3,7 +3,7 @@ var arduino = require('../'); var board = new arduino.Board({ debug: true, baudrate: 9600 -}); +}).setup(); var led = new arduino.Led({ board: board, diff --git a/examples/adjustable-port.js b/examples/adjustable-port.js index 3815493..e6b64d3 100644 --- a/examples/adjustable-port.js +++ b/examples/adjustable-port.js @@ -3,7 +3,7 @@ var arduino = require('../'); var board = new arduino.Board({ debug: true, device: "ACM" -}); +}).setup(); var led = new arduino.Led({ board: board, @@ -12,4 +12,4 @@ var led = new arduino.Led({ board.on('ready', function(){ led.blink(); -}); \ No newline at end of file +}); diff --git a/examples/analogled.js b/examples/analogled.js index 66d891a..3c3836d 100644 --- a/examples/analogled.js +++ b/examples/analogled.js @@ -2,7 +2,7 @@ var arduino = require('../'); var board = new arduino.Board({ debug: true -}); +}).setup(); var aled = new arduino.Led({ board: board, diff --git a/examples/basic.js b/examples/basic.js index ca573c0..d0e148f 100644 --- a/examples/basic.js +++ b/examples/basic.js @@ -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'); diff --git a/examples/button.js b/examples/button.js index 1ba9ad6..d42bc66 100644 --- a/examples/button.js +++ b/examples/button.js @@ -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, diff --git a/examples/combination.js b/examples/combination.js index a5812e4..b088d4f 100644 --- a/examples/combination.js +++ b/examples/combination.js @@ -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, diff --git a/examples/led.js b/examples/led.js index 1325284..8163f9f 100644 --- a/examples/led.js +++ b/examples/led.js @@ -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(){ diff --git a/examples/piezo.js b/examples/piezo.js index dd59278..f86bb16 100644 --- a/examples/piezo.js +++ b/examples/piezo.js @@ -2,7 +2,7 @@ var arduino = require('../'); var board = new arduino.Board({ debug: true -}); +}).setup(); var piezo = new arduino.Piezo({ board: board diff --git a/examples/ping.js b/examples/ping.js index c50499c..b7a4a63 100644 --- a/examples/ping.js +++ b/examples/ping.js @@ -3,7 +3,7 @@ var arduino = require('../'), board = new arduino.Board({ debug: false -}); +}).setup(); ping = new arduino.Ping({ board: board, diff --git a/examples/pir.js b/examples/pir.js index fd3e788..adcd2f7 100644 --- a/examples/pir.js +++ b/examples/pir.js @@ -3,7 +3,7 @@ var arduino = require('../'), board = new arduino.Board({ debug: false -}); +}).setup(); pir = new arduino.PIR({ board: board, diff --git a/examples/sensor-throttled.js b/examples/sensor-throttled.js index 1e4ed85..2abeea5 100644 --- a/examples/sensor-throttled.js +++ b/examples/sensor-throttled.js @@ -3,7 +3,7 @@ var arduino = require('../'), board = new arduino.Board({ debug: false -}); +}).setup(); sensor = new arduino.Sensor({ board: board, diff --git a/examples/sensor.js b/examples/sensor.js index b1a105a..94802d6 100644 --- a/examples/sensor.js +++ b/examples/sensor.js @@ -3,7 +3,7 @@ var arduino = require('../'), board = new arduino.Board({ debug: true -}); +}).setup(); sensor = new arduino.Sensor({ board: board, diff --git a/examples/servo.js b/examples/servo.js index eb732ab..c240b04 100644 --- a/examples/servo.js +++ b/examples/servo.js @@ -4,7 +4,7 @@ var arduino = require('../'), // Construct instances board = new arduino.Board({ debug: true -}); +}).setup(); led = new arduino.Led({ board: board, diff --git a/lib/board.js b/lib/board.js index 0901827..e17260c 100644 --- a/lib/board.js +++ b/lib/board.js @@ -1,4 +1,3 @@ - var events = require('events'), child = require('child_process'), util = require('util'), @@ -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'); @@ -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); + } }); } @@ -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); }; @@ -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) { } } /* diff --git a/package.json b/package.json index 546ec97..60db465 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "name": "duino", "description": "Arduino framework for mad scientists", - "version": "0.0.9", + "version": "0.1.0", "keywords": [ "arduino", "serial",