2015-08-02 08:26:39 +02:00
( function ( ) {
'use strict' ;
2019-04-05 06:47:33 +02:00
var ArduinoFirmata , debug , events , exports , serialport ;
2015-08-02 08:26:39 +02:00
events = require ( 'eventemitter2' ) ;
2019-04-05 06:47:33 +02:00
serialport = require ( 'serialport' ) ;
2015-08-02 08:26:39 +02:00
debug = require ( 'debug' ) ( 'arduino-firmata' ) ;
2019-04-05 06:47:33 +02:00
exports = module . exports = ArduinoFirmata = ( function ( ) {
class ArduinoFirmata extends events . EventEmitter2 {
static list ( callback ) {
return serialport . list ( function ( err , ports ) {
var devices , j , len , port ;
if ( err ) {
return callback ( err ) ;
2015-08-02 08:26:39 +02:00
}
2019-04-05 06:47:33 +02:00
devices = [ ] ;
for ( j = 0 , len = ports . length ; j < len ; j ++ ) {
port = ports [ j ] ;
if ( /usb|acm|com|ama\d+/i . test ( port . comName ) ) {
devices . push ( port . comName ) ;
}
}
return callback ( null , devices ) ;
} ) ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
constructor ( ) {
super ( ) ;
this . status = ArduinoFirmata . Status . CLOSE ;
this . wait _for _data = 0 ;
this . execute _multi _byte _command = 0 ;
this . multi _byte _channel = 0 ;
this . stored _input _data = [ ] ;
this . parsing _sysex = false ;
this . sysex _bytes _read = 0 ;
this . digital _output _data = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
this . digital _input _data = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
this . analog _input _data = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
this . boardVersion = null ;
2015-08-02 08:26:39 +02:00
}
2019-04-05 06:47:33 +02:00
isOldArduinoDevice ( ) {
return /usbserial|USB/ . test ( this . serialport _name ) ;
2015-08-02 08:26:39 +02:00
}
2019-04-05 06:47:33 +02:00
connect ( serialport _name , opts = {
baudRate : 57600
} ) {
this . serialport _name = serialport _name ;
opts . parser = serialport . parsers . raw ;
if ( ! this . serialport _name ) {
ArduinoFirmata . list ( ( err , devices ) => {
return this . connect ( devices [ 0 ] , opts ) ;
} ) ;
return this ;
}
this . once ( 'boardReady' , function ( ) {
var io _init _wait ;
debug ( 'boardReady' ) ;
io _init _wait = this . isOldArduinoDevice ( ) ? ( debug ( ` old arduino device found ${ this . serialport _name } ` ) , 3000 ) : ( debug ( ` new arduino device found ${ this . serialport _name } ` ) , 100 ) ;
debug ( ` wait ${ io _init _wait } (msec) ` ) ;
return setTimeout ( ( ) => {
2015-08-02 08:26:39 +02:00
var i , j , k ;
for ( i = j = 0 ; j < 6 ; i = ++ j ) {
2019-04-05 06:47:33 +02:00
this . write ( [ ArduinoFirmata . REPORT _ANALOG | i , 1 ] ) ;
2015-08-02 08:26:39 +02:00
}
for ( i = k = 0 ; k < 2 ; i = ++ k ) {
2019-04-05 06:47:33 +02:00
this . write ( [ ArduinoFirmata . REPORT _DIGITAL | i , 1 ] ) ;
2015-08-02 08:26:39 +02:00
}
debug ( 'init IO ports' ) ;
2019-04-05 06:47:33 +02:00
return this . emit ( 'connect' ) ;
} , io _init _wait ) ;
} ) ;
this . serialport = new serialport ( this . serialport _name , opts ) ;
this . serialport . once ( 'open' , ( ) => {
2015-08-02 08:26:39 +02:00
var cid ;
2019-04-05 06:47:33 +02:00
cid = setInterval ( ( ) => {
2015-08-02 08:26:39 +02:00
debug ( 'request REPORT_VERSION' ) ;
2019-04-05 06:47:33 +02:00
return this . write ( [ ArduinoFirmata . REPORT _VERSION ] ) ;
2015-08-02 08:26:39 +02:00
} , 500 ) ;
2019-04-05 06:47:33 +02:00
this . once ( 'boardVersion' , ( version ) => {
2015-08-02 08:26:39 +02:00
clearInterval ( cid ) ;
2019-04-05 06:47:33 +02:00
this . status = ArduinoFirmata . Status . OPEN ;
return this . emit ( 'boardReady' ) ;
2015-08-02 08:26:39 +02:00
} ) ;
2019-04-05 06:47:33 +02:00
return this . serialport . on ( 'data' , ( data ) => {
2015-08-02 08:26:39 +02:00
var byte , j , len , results ;
results = [ ] ;
for ( j = 0 , len = data . length ; j < len ; j ++ ) {
byte = data [ j ] ;
2019-04-05 06:47:33 +02:00
results . push ( this . process _input ( byte ) ) ;
2015-08-02 08:26:39 +02:00
}
return results ;
} ) ;
2019-04-05 06:47:33 +02:00
} ) ;
return this ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
isOpen ( ) {
return this . status === ArduinoFirmata . Status . OPEN ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
close ( callback ) {
this . status = ArduinoFirmata . Status . CLOSE ;
return this . serialport . close ( callback ) ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
reset ( callback ) {
return this . write ( [ ArduinoFirmata . SYSTEM _RESET ] , callback ) ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
write ( bytes , callback ) {
return this . serialport . write ( bytes , callback ) ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
sysex ( command , data = [ ] , callback ) {
var write _data ;
//# http://firmata.org/wiki/V2.1ProtocolDetails#Sysex_Message_Format
data = data . map ( function ( i ) {
return i & 0b1111111 ; // 7bit
} ) ;
write _data = [ ArduinoFirmata . START _SYSEX , command ] . concat ( data , [ ArduinoFirmata . END _SYSEX ] ) ;
return this . write ( write _data , callback ) ;
2015-08-02 08:26:39 +02:00
}
2019-04-05 06:47:33 +02:00
pinMode ( pin , mode , callback ) {
switch ( mode ) {
case true :
mode = ArduinoFirmata . OUTPUT ;
break ;
case false :
mode = ArduinoFirmata . INPUT ;
}
return this . write ( [ ArduinoFirmata . SET _PIN _MODE , pin , mode ] , callback ) ;
2015-08-02 08:26:39 +02:00
}
2019-04-05 06:47:33 +02:00
digitalWrite ( pin , value , callback ) {
var port _num ;
this . pinMode ( pin , ArduinoFirmata . OUTPUT ) ;
port _num = ( pin >>> 3 ) & 0x0F ;
if ( value === 0 || value === false ) {
this . digital _output _data [ port _num ] &= ~ ( 1 << ( pin & 0x07 ) ) ;
} else {
this . digital _output _data [ port _num ] |= 1 << ( pin & 0x07 ) ;
}
return this . write ( [ ArduinoFirmata . DIGITAL _MESSAGE | port _num , this . digital _output _data [ port _num ] & 0x7F , this . digital _output _data [ port _num ] >>> 7 ] , callback ) ;
2015-08-02 08:26:39 +02:00
}
2019-04-05 06:47:33 +02:00
analogWrite ( pin , value , callback ) {
value = Math . floor ( value ) ;
this . pinMode ( pin , ArduinoFirmata . PWM ) ;
return this . write ( [ ArduinoFirmata . ANALOG _MESSAGE | ( pin & 0x0F ) , value & 0x7F , value >>> 7 ] , callback ) ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
servoWrite ( pin , angle , callback ) {
this . pinMode ( pin , ArduinoFirmata . SERVO ) ;
return this . write ( [ ArduinoFirmata . ANALOG _MESSAGE | ( pin & 0x0F ) , angle & 0x7F , angle >>> 7 ] , callback ) ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
digitalRead ( pin ) {
return ( ( this . digital _input _data [ pin >>> 3 ] >>> ( pin & 0x07 ) ) & 0x01 ) > 0 ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
analogRead ( pin ) {
return this . analog _input _data [ pin ] ;
}
2015-08-02 08:26:39 +02:00
2019-04-05 06:47:33 +02:00
process _input ( input _data ) {
var analog _value , command , diff , i , j , old _analog _value , results , stat , sysex _command , sysex _data ;
if ( this . parsing _sysex ) {
if ( input _data === ArduinoFirmata . END _SYSEX ) {
this . parsing _sysex = false ;
sysex _command = this . stored _input _data [ 0 ] ;
sysex _data = this . stored _input _data . slice ( 1 , this . sysex _bytes _read ) ;
return this . emit ( 'sysex' , {
command : sysex _command ,
data : sysex _data
} ) ;
} else {
this . stored _input _data [ this . sysex _bytes _read ] = input _data ;
return this . sysex _bytes _read += 1 ;
}
} else if ( this . wait _for _data > 0 && input _data < 128 ) {
this . wait _for _data -= 1 ;
this . stored _input _data [ this . wait _for _data ] = input _data ;
if ( this . execute _multi _byte _command !== 0 && this . wait _for _data === 0 ) {
switch ( this . execute _multi _byte _command ) {
case ArduinoFirmata . DIGITAL _MESSAGE :
input _data = ( this . stored _input _data [ 0 ] << 7 ) + this . stored _input _data [ 1 ] ;
diff = this . digital _input _data [ this . multi _byte _channel ] ^ input _data ;
this . digital _input _data [ this . multi _byte _channel ] = input _data ;
if ( this . listeners ( 'digitalChange' ) . length > 0 ) {
results = [ ] ;
for ( i = j = 0 ; j <= 13 ; i = ++ j ) {
if ( ( ( 0x01 << i ) & diff ) > 0 ) {
stat = ( input _data & diff ) > 0 ;
results . push ( this . emit ( 'digitalChange' , {
pin : i + this . multi _byte _channel * 8 ,
value : stat ,
old _value : ! stat
} ) ) ;
} else {
results . push ( void 0 ) ;
}
2015-08-02 08:26:39 +02:00
}
2019-04-05 06:47:33 +02:00
return results ;
}
break ;
case ArduinoFirmata . ANALOG _MESSAGE :
analog _value = ( this . stored _input _data [ 0 ] << 7 ) + this . stored _input _data [ 1 ] ;
old _analog _value = this . analogRead ( this . multi _byte _channel ) ;
this . analog _input _data [ this . multi _byte _channel ] = analog _value ;
if ( old _analog _value !== analog _value ) {
return this . emit ( 'analogChange' , {
pin : this . multi _byte _channel ,
value : analog _value ,
old _value : old _analog _value
} ) ;
2015-08-02 08:26:39 +02:00
}
2019-04-05 06:47:33 +02:00
break ;
case ArduinoFirmata . REPORT _VERSION :
this . boardVersion = ` ${ this . stored _input _data [ 1 ] } . ${ this . stored _input _data [ 0 ] } ` ;
return this . emit ( 'boardVersion' , this . boardVersion ) ;
}
2015-08-02 08:26:39 +02:00
}
} else {
2019-04-05 06:47:33 +02:00
if ( input _data < 0xF0 ) {
command = input _data & 0xF0 ;
this . multi _byte _channel = input _data & 0x0F ;
} else {
command = input _data ;
}
if ( command === ArduinoFirmata . START _SYSEX ) {
this . parsing _sysex = true ;
return this . sysex _bytes _read = 0 ;
} else if ( command === ArduinoFirmata . DIGITAL _MESSAGE || command === ArduinoFirmata . ANALOG _MESSAGE || command === ArduinoFirmata . REPORT _VERSION ) {
this . wait _for _data = 2 ;
return this . execute _multi _byte _command = command ;
}
2015-08-02 08:26:39 +02:00
}
}
2019-04-05 06:47:33 +02:00
} ;
ArduinoFirmata . Status = {
CLOSE : 0 ,
OPEN : 1
2015-08-02 08:26:39 +02:00
} ;
2019-04-05 06:47:33 +02:00
ArduinoFirmata . INPUT = 0 ;
ArduinoFirmata . OUTPUT = 1 ;
ArduinoFirmata . ANALOG = 2 ;
ArduinoFirmata . PWM = 3 ;
ArduinoFirmata . SERVO = 4 ;
ArduinoFirmata . SHIFT = 5 ;
ArduinoFirmata . I2C = 6 ;
ArduinoFirmata . LOW = 0 ;
ArduinoFirmata . HIGH = 1 ;
ArduinoFirmata . MAX _DATA _BYTES = 32 ;
ArduinoFirmata . DIGITAL _MESSAGE = 0x90 ; // send data for a digital port
ArduinoFirmata . ANALOG _MESSAGE = 0xE0 ; // send data for an analog pin (or PWM)
ArduinoFirmata . REPORT _ANALOG = 0xC0 ; // enable analog input by pin
ArduinoFirmata . REPORT _DIGITAL = 0xD0 ; // enable digital input by port
ArduinoFirmata . SET _PIN _MODE = 0xF4 ; // set a pin to INPUT/OUTPUT/PWM/etc
ArduinoFirmata . REPORT _VERSION = 0xF9 ; // report firmware version
ArduinoFirmata . SYSTEM _RESET = 0xFF ; // reset from MIDI
ArduinoFirmata . START _SYSEX = 0xF0 ; // start a MIDI SysEx message
ArduinoFirmata . END _SYSEX = 0xF7 ; // end a MIDI SysEx message
2015-08-02 08:26:39 +02:00
return ArduinoFirmata ;
2019-04-05 06:47:33 +02:00
} ) . call ( this ) ;
2015-08-02 08:26:39 +02:00
} ) . call ( this ) ;