1-
21var events = require ( 'events' ) ,
32 child = require ( 'child_process' ) ,
43 util = require ( 'util' ) ,
@@ -7,24 +6,37 @@ var events = require('events'),
76
87/*
98 * The main Arduino constructor
10- * Connect to the serial port and bind
9+ *
10+ * [NEW] Does *not* open a serial connection. Add a `setup()` call to do so.
11+ *
12+ * This allows the user to add a listener for error events that occur
13+ * during the serial connection attempts.
1114 */
1215var Board = function ( options ) {
1316 this . log ( 'info' , 'initializing' ) ;
14- this . debug = options && options . debug || false ;
15- this . device = options && options . device || 'usb|ttyACM*|ttyS0' ;
17+ this . debug = options && options . debug || false ;
18+ this . devregex = options && options . devregex || 'usb|ttyACM*|ttyS0' ;
1619 this . baudrate = options && options . baudrate || 115200 ;
1720 this . writeBuffer = [ ] ;
21+ }
22+
23+ /*
24+ * EventEmitter, I choose you!
25+ */
26+ util . inherits ( Board , events . EventEmitter ) ;
1827
28+ /*
29+ * Establish the serial connection
30+ *
31+ * Tries to open a serial connection with `connectSerial()`.
32+ * If successful, the connection is initialized ("clearing bytes", debug mode).
33+ * If unsuccessful, error event is emitted; if no listeners: error is thrown.
34+ */
35+ Board . prototype . setup = function ( ) {
1936 var self = this ;
20- this . detect ( function ( err , serial ) {
21- if ( err ) {
22- if ( self . listeners ( 'error' ) . length )
23- self . emit ( 'error' , err ) ;
24- else
25- throw new Error ( err ) ;
26- } else {
27- self . serial = serial ;
37+ this . connectSerial ( function ( found ) {
38+ if ( found ) {
39+ self . serial = found ;
2840 self . emit ( 'connected' ) ;
2941
3042 self . log ( 'info' , 'binding serial events' ) ;
@@ -56,52 +68,69 @@ var Board = function (options) {
5668
5769 self . emit ( 'ready' ) ;
5870 } , 500 ) ;
71+ } else {
72+ msg = "Could not establish Serial connection to Arduino." ;
73+ if ( self . listeners ( 'error' ) . length > 0 ) {
74+ self . emit ( 'error' , msg ) ;
75+ } else {
76+ throw new Error ( msg ) ;
77+ }
5978 }
6079 } ) ;
6180}
6281
6382/*
64- * EventEmitter, I choose you!
83+ * (Tries to) Open serial connection with Arduino (formerly named `detect()`)
84+ *
85+ * Loops through devices matching `devregex` and naively tries to open a serial
86+ * connection with each until one succeeds.
87+ * This should really message the device and wait for a correct response to
88+ * ensure that we're actually connected to an Arduino running `duino`. FIXME
89+ *
90+ * Returns false if no serial connection could be established.
6591 */
66- util . inherits ( Board , events . EventEmitter ) ;
67-
68- /*
69- * Detect an Arduino board
70- * Loop through all USB devices and try to connect
71- * This should really message the device and wait for a correct response
72- */
73- Board . prototype . detect = function ( callback ) {
92+ Board . prototype . connectSerial = function ( callback ) {
7493 this . log ( 'info' , 'attempting to find Arduino board' ) ;
7594 var self = this ;
76- child . exec ( 'ls /dev | grep -E "' + self . device + '"' , function ( err , stdout , stderr ) {
77- var usb = stdout . slice ( 0 , - 1 ) . split ( '\n' ) ,
78- found = false ,
79- err = null ,
80- possible , temp ;
81-
82- while ( usb . length ) {
83- possible = usb . pop ( ) ;
84-
85- if ( possible . slice ( 0 , 2 ) !== 'cu' ) {
86- try {
87- temp = new serial . SerialPort ( '/dev/' + possible , {
88- baudrate : self . baudrate ,
89- parser : serial . parsers . readline ( '\n' )
90- } ) ;
91- } catch ( e ) {
92- err = e ;
93- }
94- if ( ! err ) {
95- found = temp ;
96- self . log ( 'info' , 'found board at ' + temp . port ) ;
97- break ;
98- } else {
99- err = new Error ( 'Could not find Arduino' ) ;
100- }
101- }
95+ child . exec ( 'ls /dev | grep -E "' + self . devregex + '"' , function ( err , stdout , stderr ) {
96+
97+ function skipUnwanted ( e ) {
98+ return ( e !== '' ) && ( e . slice ( 0 , 2 ) !== 'cu' ) ;
10299 }
103100
104- callback ( err , found ) ;
101+ var devices = stdout . slice ( 0 , - 1 ) . split ( '\n' ) . filter ( skipUnwanted ) ,
102+ device ,
103+ candidate ;
104+
105+ // loop over list of possible Arduinos
106+ // do not stop (even/especially on error, that's the point!) until
107+ // - we run out of options, or
108+ // - a serial connection is established
109+ var success = devices . some ( function ( device ) {
110+ try {
111+ self . log ( 'debug' , 'attempting to open serial conn.: ' + device ) ;
112+ candidate = new serial . SerialPort ( '/dev/' + device , {
113+ baudrate : self . baudrate ,
114+ parser : serial . parsers . readline ( '\n' )
115+ } ) ;
116+
117+ // connection succeeded, though we don't test whether it's an Arduino
118+ self . log ( 'info' , 'found board at /dev/' + device ) ;
119+ return true ;
120+
121+ } catch ( e ) {
122+ // ignore error and cont.
123+ self . log ( 'warning' , 'error while establishing serial connection with'
124+ + '/dev/' + device + '; trying next' ) ;
125+ return false ;
126+ }
127+ } ) ;
128+
129+ if ( success ) {
130+ callback ( candidate ) ;
131+ } else {
132+ callback ( false ) ;
133+ }
105134 } ) ;
106135}
107136
@@ -137,18 +166,17 @@ Board.prototype.write = function (m) {
137166 }
138167}
139168
140- /*
141- * Add a 0 to the front of a single-digit pin number
142- */
169+ // Add a 0 to the front of a single-digit pin number
143170Board . prototype . normalizePin = function ( pin ) {
144171 return this . lpad ( 2 , '0' , pin ) ;
145172}
146173
174+ // Left-pad values with 0s so it has three digits.
147175Board . prototype . normalizeVal = function ( val ) {
148- return this . lpad ( 3 , '0' , val ) ;
176+ return this . lpad ( 3 , '0' , val ) ;
149177}
150178
151- //
179+ // Left-pad `str` with `chr` and return the last `len` digits
152180Board . prototype . lpad = function ( len , chr , str ) {
153181 return ( Array ( len + 1 ) . join ( chr || ' ' ) + str ) . substr ( - len ) ;
154182} ;
0 commit comments