diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..28f1ba7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.DS_Store \ No newline at end of file diff --git a/lib/firmata.js b/lib/firmata.js index c83cb91..a28ec7f 100644 --- a/lib/firmata.js +++ b/lib/firmata.js @@ -14,14 +14,32 @@ var SerialPort = require('serialport').SerialPort, * constants */ -const PIN_MODE = 0xF4, REPORT_DIGITAL = 0xD0, REPORT_ANALOG = 0xC0, DIGITAL_MESSAGE = 0x90, START_SYSEX = 0xF0, END_SYSEX = 0xF7, QUERY_FIRMWARE = 0x79, REPORT_VERSION = 0xF9, ANALOG_MESSAGE = 0xE0, CAPABILITY_QUERY = 0x6B, CAPABILITY_RESPONSE = 0x6C, PIN_STATE_QUERY = 0x6D, PIN_STATE_RESPONSE = 0x6E, ANALOG_MAPPING_QUERY = 0x69, ANALOG_MAPPING_RESPONSE = 0x6A, I2C_REQUEST = 0x76, I2C_REPLY = 0x77, I2C_CONFIG = 0x78, STRING_DATA = 0x71 - -/** - * MIDI_RESPONSE contains functions to be called when we receive a MIDI message from the arduino. - * used as a switch object as seen here http://james.padolsey.com/javascript/how-to-avoid-switch-case-syndrome/ - */ - -var MIDI_RESPONSE={}; +var PIN_MODE = 0xF4, + REPORT_DIGITAL = 0xD0, + REPORT_ANALOG = 0xC0, + DIGITAL_MESSAGE = 0x90, + START_SYSEX = 0xF0, + END_SYSEX = 0xF7, + QUERY_FIRMWARE = 0x79, + REPORT_VERSION = 0xF9, + ANALOG_MESSAGE = 0xE0, + CAPABILITY_QUERY = 0x6B, + CAPABILITY_RESPONSE = 0x6C, + PIN_STATE_QUERY = 0x6D, + PIN_STATE_RESPONSE = 0x6E, + ANALOG_MAPPING_QUERY = 0x69, + ANALOG_MAPPING_RESPONSE = 0x6A, + I2C_REQUEST = 0x76, + I2C_REPLY = 0x77, + I2C_CONFIG = 0x78, + STRING_DATA = 0x71 + + /** + * MIDI_RESPONSE contains functions to be called when we receive a MIDI message from the arduino. + * used as a switch object as seen here http://james.padolsey.com/javascript/how-to-avoid-switch-case-syndrome/ + */ + +var MIDI_RESPONSE = {}; /** * Handles a REPORT_VERSION response and emits the reportversion event. Also turns on all pins to start reporting @@ -29,7 +47,7 @@ var MIDI_RESPONSE={}; * @param {Board} board the current arduino board we are working with. */ -MIDI_RESPONSE[REPORT_VERSION]=function(board){ +MIDI_RESPONSE[REPORT_VERSION] = function(board) { board.version.major = board.currentBuffer[1]; board.version.minor = board.currentBuffer[2]; board.emit('reportversion'); @@ -44,8 +62,8 @@ MIDI_RESPONSE[REPORT_VERSION]=function(board){ * @private * @param {Board} board the current arduino board we are working with. */ - -MIDI_RESPONSE[ANALOG_MESSAGE]=function(board){ + +MIDI_RESPONSE[ANALOG_MESSAGE] = function(board) { var value = board.currentBuffer[1] | (board.currentBuffer[2] << 7); var port = board.currentBuffer[0] & 0x0F; if (board.pins[board.analogPins[port]]) { @@ -63,14 +81,14 @@ MIDI_RESPONSE[ANALOG_MESSAGE]=function(board){ * @private * @param {Board} board the current arduino board we are working with. */ - -MIDI_RESPONSE[DIGITAL_MESSAGE]=function(board){ + +MIDI_RESPONSE[DIGITAL_MESSAGE] = function(board) { var port = (board.currentBuffer[0] & 0x0F); var portValue = board.currentBuffer[1] | (board.currentBuffer[2] << 7); for (var i = 0; i < 8; i++) { var pinNumber = 8 * port + i; var pin = board.pins[pinNumber]; - if (pin.mode == board.MODES.INPUT) { + if (pin && (pin.mode == board.MODES.INPUT)) { pin.value = (portValue >> (i & 0x07)) & 0x01; board.emit('digital-read-' + pinNumber, pin.value); board.emit('digital-read', { @@ -85,7 +103,7 @@ MIDI_RESPONSE[DIGITAL_MESSAGE]=function(board){ * SYSEX_RESPONSE contains functions to be called when we receive a SYSEX message from the arduino. * used as a switch object as seen here http://james.padolsey.com/javascript/how-to-avoid-switch-case-syndrome/ */ - + var SYSEX_RESPONSE = {}; /** @@ -131,7 +149,7 @@ SYSEX_RESPONSE[CAPABILITY_RESPONSE] = function(board) { n = 0; continue; } - if (n == 0) { + if (n === 0) { supportedModes |= (1 << board.currentBuffer[i]); } n ^= 1; @@ -145,12 +163,12 @@ SYSEX_RESPONSE[CAPABILITY_RESPONSE] = function(board) { * @param {Board} board the current arduino board we are working with. */ -SYSEX_RESPONSE[PIN_STATE] = function(board) { +SYSEX_RESPONSE[PIN_STATE_RESPONSE] = function(board) { var pin = board.currentBuffer[2]; board.pins[pin].mode = board.currentBuffer[3]; board.pins[pin].value = board.currentBuffer[4]; if (board.currentBuffer.length > 6) { - board.pins[pin].value |= (board.currentBuffer[5] << 7) + board.pins[pin].value |= (board.currentBuffer[5] << 7); } if (board.currentBuffer.length > 7) { board.pins[pin].value |= (board.currentBuffer[6] << 14); @@ -185,7 +203,7 @@ SYSEX_RESPONSE[ANALOG_MAPPING_RESPONSE] = function(board) { * @param {Board} board the current arduino board we are working with. */ -SYSEX_RESPONSE[I2C_REPLY] = function(board){ +SYSEX_RESPONSE[I2C_REPLY] = function(board) { var replyBuffer = []; var slaveAddress = (board.currentBuffer[2] & 0x7F) | ((board.currentBuffer[3] & 0x7F) << 7); var register = (board.currentBuffer[4] & 0x7F) | ((board.currentBuffer[5] & 0x7F) << 7); @@ -201,8 +219,8 @@ SYSEX_RESPONSE[I2C_REPLY] = function(board){ * @param {Board} board the current arduino board we are working with. */ -SYSEX_RESPONSE[STRING_DATA] = function(board){ - console.log(new Buffer(board.currentBuffer.slice(1, -1)).toString('utf8')); +SYSEX_RESPONSE[STRING_DATA] = function(board) { + board.emit('string',new Buffer(board.currentBuffer.slice(1, -1)).toString('utf8')); }; /** @@ -221,7 +239,6 @@ SYSEX_RESPONSE[STRING_DATA] = function(board){ * @property currentBuffer An array holding the current bytes received from the arduino. * @property {SerialPort} sp The serial port object used to communicate with the arduino. */ - var Board = function(port, callback) { events.EventEmitter.call(this); var board = this; @@ -237,7 +254,7 @@ var Board = function(port, callback) { READ: 1, CONTINUOUS_READ: 2, STOP_READING: 3 - } + }; this.HIGH = 1; this.LOW = 0; this.pins = []; @@ -251,26 +268,27 @@ var Board = function(port, callback) { }); this.sp.on('data', function(data) { //we dont want to push 0 as the first byte on our buffer - if ((board.currentBuffer.length == 0 && data[0] != 0 || board.currentBuffer.length)) { + if ((board.currentBuffer.length === 0 && data[0] !== 0 || board.currentBuffer.length)) { board.currentBuffer.push(data[0]); } //a MIDI or SYSEX command function we are going to call var cmdFunc; + var cmd; //if the first byte is START_SYSEX and last byte is END_SYSEX we have a SYSEX command. if (board.currentBuffer[0] == START_SYSEX && board.currentBuffer[board.currentBuffer.length - 1] == END_SYSEX) { cmdFunc = SYSEX_RESPONSE[board.currentBuffer[1]]; - //if the first byte is not a START_SYSEX and we have 3 bytes we might have a MIDI Command - }else if(board.currentBuffer.length == 3 && board.currentBuffer[0] != START_SYSEX){ + //if the first byte is not a START_SYSEX and we have 3 bytes we might have a MIDI Command + } else if (board.currentBuffer.length == 3 && board.currentBuffer[0] != START_SYSEX) { //commands under 0xF0 we have a multi byte command - if(board.currentBuffer[0] < 240){ - var cmd = board.currentBuffer[0] & 0xF0; - }else{ - var cmd = board.currentBuffer[0]; + if (board.currentBuffer[0] < 240) { + cmd = board.currentBuffer[0] & 0xF0; + } else { + cmd = board.currentBuffer[0]; } cmdFunc = MIDI_RESPONSE[cmd]; } //if a function is found we will call it - if(cmdFunc){ + if (cmdFunc) { //call function with board object cmdFunc(board); //reset currentBuffer so we can receive the next command @@ -283,7 +301,7 @@ var Board = function(port, callback) { this.reportVersion(function() { board.queryCapabilities(function() { board.queryAnalogMapping(function() { - var pinsToQuery = [] + var pinsToQuery = []; for (i = 0; i < board.pins.length; i++) { pinsToQuery[i] = i; } @@ -292,15 +310,14 @@ var Board = function(port, callback) { board.queryPinState(pinsToQuery[i], function() { callback(); }); - } - else { + } else { board.queryPinState(pinsToQuery[i], function() {}); } } }); }); }); - } + }; sys.inherits(Board, events.EventEmitter); /** diff --git a/package.json b/package.json index de5b289..7335411 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,18 @@ -{ "name" : "firmata" -, "description" : "A library to control an arduino running firmata" -, "version" : "0.1.3" -, "author" : "Julian Gautier" -, "homepage" : "http://www.github.com/jgautier/firmata" -, "repository" : - { - "type" : "git" - ,"url" : "git://github.com/jgautier/firmata.git" - } -, "main" : "lib/firmata" -, "bin" : - { - "firmata" : "./repl.js" - } -, "dependencies" : - { - "serialport" : ">=0.2.0" - } -, "engines" : - { - "node" : "v0.5.0-pre" - } - -} +{ + "name": "firmata", + "description": "A library to control an arduino running firmata", + "version": "0.1.3", + "author": "Julian Gautier", + "homepage": "http://www.github.com/jgautier/firmata", + "repository": { + "type": "git", + "url": "git://github.com/jgautier/firmata.git" + }, + "main": "lib/firmata", + "bin": { + "firmata": "./repl.js" + }, + "dependencies": { + "serialport": ">=0.2.0" + } +} \ No newline at end of file diff --git a/repl.js b/repl.js index ffd1c0b..48d6cd6 100755 --- a/repl.js +++ b/repl.js @@ -1,13 +1,14 @@ #!/usr/bin/env node -var firmata=require('./lib/firmata.js') - ,repl = require('repl'); + +var firmata = require('./lib/firmata.js'), + repl = require('repl'); console.log('Enter USB Port and press enter:'); process.stdin.resume(); process.stdin.setEncoding('utf8'); -process.stdin.once('data',function(chunk){ - var port = chunk.replace('\n',''); - var board = new firmata.Board(port,function(){ - console.log('Successfully Connected to ')+port; - repl.start('firmata>').context.board=board; +process.stdin.once('data', function(chunk) { + var port = chunk.replace('\n', ''); + var board = new firmata.Board(port, function() { + console.log('Successfully Connected to ' + port); + repl.start('firmata>').context.board = board; }); }); \ No newline at end of file diff --git a/test/firmata.js b/test/firmata.js index 920a1fc..5695156 100644 --- a/test/firmata.js +++ b/test/firmata.js @@ -1,146 +1,138 @@ /* Tests performed with arduino Uno and firmata 2.2 */ -var assert = require('assert') - ,firmata = require('firmata') - ,async = require('async'); -var board=new firmata.Board('/dev/ttyS2',function(error){ - if(error){ +var assert = require('assert'), + firmata = require('firmata'), + async = require('async'); +var board = new firmata.Board('/dev/tty.usbmodemfa131', function(error) { + if (error) { console.log(error); - }else{ + } else { console.log('connected'); - exports['Test Connection']=function(){ - assert.ok(true,'We connected'); + exports['Test Connection'] = function() { + assert.ok(true, 'We connected'); }; - exports['Test Version']=function(){ - assert.ok(board.version.major == 2,'major version is 2'); - assert.ok(board.version.minor == 2,'minor version is 2'); + exports['Test Version'] = function() { + assert.ok(board.version.major == 2, 'major version is 2'); + assert.ok(board.version.minor == 2, 'minor version is 2'); }; - exports['Test Capabilities']=function(){ - assert.ok(board.pins[0].supportedModes.length === 0,'0 is a serial pin'); - assert.ok(board.pins[1].supportedModes.length === 0,'1 is a serial pin'); - for(var i = 2, length = board.pins.length; i < length; i++){ + exports['Test Capabilities'] = function() { + assert.ok(board.pins[0].supportedModes.length === 0, '0 is a serial pin'); + assert.ok(board.pins[1].supportedModes.length === 0, '1 is a serial pin'); + for (var i = 2, length = board.pins.length; i < length; i++) { //if the analogChannel is 127 then its a digital pin and it supports board.INPUT board.OUTPUT board.PWM and board.SERVO - if(board.pins[i].supportedModes.length === 0) - continue; - if(board.pins[i].analogChannel == 127){ - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.INPUT) > -1,'Pin has INPUT'); - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.OUTPUT) > -1,'Pin has OUTPUT'); - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.PWM) > -1,'Pin has PWM'); - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.SERVO) > -1,'Pin has Servo'); - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.ANALOG) == -1,'Pin does not have Analog'); - //on arduino uno there are Analog 6 and 7 which are analog only - }else if(board.pins[i].analogChannel > 5){ - assert.ok(board.pins[i].supportedModes.length == 1,'Only one mode'); - assert.ok(board.pins[i].supportedModes[0]==board.MODES.ANALOG,'Only analog'); - - //else its analog and it supported board.INPUT, board.OUTPUT and board.PWM but no board.SERVO - }else if(board.pins[i].analogChannel > 0){ - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.INPUT) > -1,'Pin has INPUT'); - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.PWM) > -1,'Pin has PWM'); - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.OUTPUT) > -1,'Pin has Output'); - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.ANALOG) > -1,'Pin has Analog'); - assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.SERVO) == -1,'Pin does not have Servo'); + if (board.pins[i].supportedModes.length === 0) continue; + if (board.pins[i].analogChannel == 127) { + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.INPUT) > -1, 'Pin has INPUT'); + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.OUTPUT) > -1, 'Pin has OUTPUT'); + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.PWM) > -1, 'Pin has PWM'); + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.SERVO) > -1, 'Pin has Servo'); + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.ANALOG) == -1, 'Pin does not have Analog'); + //on arduino uno there are Analog 6 and 7 which are analog only + } else if (board.pins[i].analogChannel > 5) { + assert.ok(board.pins[i].supportedModes.length == 1, 'Only one mode'); + assert.ok(board.pins[i].supportedModes[0] == board.MODES.ANALOG, 'Only analog'); + + //else its analog and it supported board.INPUT, board.OUTPUT and board.PWM but no board.SERVO + } else if (board.pins[i].analogChannel > 0) { + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.INPUT) > -1, 'Pin has INPUT'); + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.PWM) > -1, 'Pin has PWM'); + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.OUTPUT) > -1, 'Pin has Output'); + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.ANALOG) > -1, 'Pin has Analog'); + assert.ok(board.pins[i].supportedModes.indexOf(board.MODES.SERVO) == -1, 'Pin does not have Servo'); } } }; - exports['Test Pin State']=function(){ - assert.ok(board.pins[0].mode === 0,'0 is a serial pin'); - assert.ok(board.pins[1].mode === 0,'1 is a serial pin'); - for(var i = 2, length = board.pins.length; i< length; i++){ - if(board.pins[i].supportedModes.length === 0) - continue; - //if its digital - if(board.pins[i].analogChannel ==127){ - assert.ok(board.pins[i].mode == board.MODES.OUTPUT,'Digital defaults to Output'); - } - //else its analog - else{ - assert.ok(board.pins[i].mode == board.MODES.ANALOG,'Analgo defaults to analog'); - } - } - }; - exports['Test Query Firmware']=function(){ - board.queryFirmware(function(){ - assert.ok(true,'Firmware queried'); - }); - }; - var analogRead=function(callback){ - console.log('Connect photocell to analog 5'); - console.log('Testing in 15 seconds'); - var callbackCalled=false; - setTimeout(function(){ - console.log('Put your hand over light sensor'); - board.pinMode(5,board.MODES.ANALOG); - board.analogRead(5,function(value){ - if(value <500){ - if(!callbackCalled){ - callbackCalled=true; - callback(null,'1'); - } - } - }); - },15000); - }; - var digitalRead=function(callback){ - console.log('Connect photocell to digital 8'); - console.log('Testing in 15 seconds'); - var callbackCalled=false; - setTimeout(function(){ - console.log('Put Your hand over light sensor'); - board.pinMode(8,board.MODES.INPUT); - board.digitalRead(8,function(value){ - if(value === 0){ - if(!callbackCalled){ - callbackCalled=true; - callback(null,'2'); - } - } - }); - },15000); - }; - var readYes=function(callback){ - process.stdin.resume(); - process.stdin.setEncoding('utf8'); - process.stdin.once('data',function(chunk){ - callback(null,chunk); - }); - }; - var digitalWrite=function(callback){ - console.log('Test Digital Write Connect LED to Pin 7'); - console.log('Testing in 15 seconds'); - setTimeout(function(){ - console.log('Press Y if you see the light turn on'); - board.pinMode(7,board.MODES.OUTPUT); - board.digitalWrite(7,board.HIGH); - callback(null,'3'); - },15000); - }; - var analogWrite=function(callback){ - console.log('Testing Analog Write Connect LED to Pin 9'); - console.log('Testing in 15 seconds'); - setTimeout(function(){ - board.pinMode(9,board.MODES.PWM); - board.analogWrite(9,255); - console.log('Press Y if you saw the light turn on'); - callback(null,'4'); - },15000); - }; - exports['Test Pins']=function(){ - async.series([ - analogRead - ,digitalRead - ,digitalWrite - ,readYes - ,analogWrite - ,readYes - ],function(error,results){ - assert.ok(true,'Analog Read Succesful'); - assert.ok(true,'Digital Read Successful'); - assert.ok(results[3] == 'Y\n','Digital Write Successful'); - assert.ok(results[5] == 'Y\n','Analog WRite Successful'); - process.exit(); - }); - }; + exports['Test Pin State'] = function() { + assert.ok(board.pins[0].mode === 0, '0 is a serial pin'); + assert.ok(board.pins[1].mode === 0, '1 is a serial pin'); + for (var i = 2, length = board.pins.length; i < length; i++) { + if (board.pins[i].supportedModes.length === 0) continue; + //if its digital + if (board.pins[i].analogChannel == 127) { + assert.ok(board.pins[i].mode == board.MODES.OUTPUT, 'Digital defaults to Output'); + } + //else its analog + else { + assert.ok(board.pins[i].mode == board.MODES.ANALOG, 'Analgo defaults to analog'); + } + } + }; + exports['Test Query Firmware'] = function() { + board.queryFirmware(function() { + assert.ok(true, 'Firmware queried'); + }); + }; + var analogRead = function(callback) { + console.log('Connect photocell to analog 5'); + console.log('Testing in 15 seconds'); + var callbackCalled = false; + setTimeout(function() { + console.log('Put your hand over light sensor'); + board.pinMode(5, board.MODES.ANALOG); + board.analogRead(5, function(value) { + if (value < 500) { + if (!callbackCalled) { + callbackCalled = true; + callback(null, '1'); + } + } + }); + }, 15000); + }; + var digitalRead = function(callback) { + console.log('Connect photocell to digital 8'); + console.log('Testing in 15 seconds'); + var callbackCalled = false; + setTimeout(function() { + console.log('Put Your hand over light sensor'); + board.pinMode(8, board.MODES.INPUT); + board.digitalRead(8, function(value) { + if (value == 0) { + if (!callbackCalled) { + callbackCalled = true; + callback(null, '2'); + } + } + }); + }, 15000); + }; + var readYes = function(callback) { + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + process.stdin.once('data', function(chunk) { + callback(null, chunk); + }); + }; + var digitalWrite = function(callback) { + console.log('Test Digital Write Connect LED to Pin 7'); + console.log('Testing in 15 seconds'); + setTimeout(function() { + console.log('Press Y if you see the light turn on'); + board.pinMode(7, board.MODES.OUTPUT); + board.digitalWrite(7, board.HIGH); + callback(null, '3'); + }, 15000); + }; + var analogWrite = function(callback) { + console.log('Testing Analog Write Connect LED to Pin 9'); + console.log('Testing in 15 seconds'); + setTimeout(function() { + board.pinMode(9, board.MODES.PWM); + board.analogWrite(9, 255); + console.log('Press Y if you saw the light turn on'); + callback(null, '4'); + }, 15000); + }; + exports['Test Pins'] = function() { + async.series([ + analogRead, digitalRead, digitalWrite, readYes, analogWrite, readYes], function(error, results) { + assert.ok(true, 'Analog Read Succesful'); + assert.ok(true, 'Digital Read Successful'); + assert.ok(results[3] == 'Y\n', 'Digital Write Successful'); + assert.ok(results[5] == 'Y\n', 'Analog WRite Successful'); + process.exit(); + }); + }; } }); \ No newline at end of file