Comparing version 0.3.2 to 0.3.3
{ | ||
"name": "rpi-gpio", | ||
"version": "0.3.2", | ||
"version": "0.3.3", | ||
"description": "Control Raspberry Pi GPIO pins with node.js", | ||
@@ -32,4 +32,5 @@ "main": "rpi-gpio.js", | ||
"dependencies": { | ||
"async": "~0.8.0" | ||
"async": "~0.8.0", | ||
"debug": "~0.8.1" | ||
} | ||
} |
308
rpi-gpio.js
@@ -1,17 +0,10 @@ | ||
var fs = require('fs'); | ||
var util = require('util'); | ||
var fs = require('fs'); | ||
var util = require('util'); | ||
var EventEmitter = require('events').EventEmitter; | ||
var async = require('async'); | ||
var async = require('async'); | ||
var debug = require('debug')('rpi-gpio'); | ||
var PATH = '/sys/class/gpio'; | ||
// Constructor | ||
function Gpio() { | ||
EventEmitter.call(this); | ||
this.reset(); | ||
} | ||
util.inherits(Gpio, EventEmitter); | ||
var pins = { | ||
current: undefined, | ||
v1: { | ||
@@ -75,144 +68,165 @@ '1': null, | ||
// Constants | ||
Gpio.prototype.DIR_IN = 'in'; | ||
Gpio.prototype.DIR_OUT = 'out'; | ||
Gpio.prototype.MODE_RPI = 'mode_rpi'; | ||
Gpio.prototype.MODE_BCM = 'mode_bcm'; | ||
function Gpio() { | ||
var currentPins; | ||
var exportedPins = {}; | ||
var getPinForCurrentMode = getPinRpi; | ||
/** | ||
* Set pin reference mode. Defaults to 'mode_rpi'. | ||
* | ||
* @param {string} mode Pin reference mode, 'mode_rpi' or 'mode_bcm' | ||
*/ | ||
Gpio.prototype.setMode = function(mode) { | ||
if (mode === this.MODE_RPI) { | ||
getPinForCurrentMode = getPinRpi; | ||
} else if (mode === this.MODE_BCM) { | ||
getPinForCurrentMode = getPinBcm; | ||
} else { | ||
throw new Error('Cannot set invalid mode'); | ||
} | ||
this.DIR_IN = 'in'; | ||
this.DIR_OUT = 'out'; | ||
this.MODE_RPI = 'mode_rpi'; | ||
this.MODE_BCM = 'mode_bcm'; | ||
this.emit('modeChange', mode); | ||
}; | ||
/** | ||
* Set pin reference mode. Defaults to 'mode_rpi'. | ||
* | ||
* @param {string} mode Pin reference mode, 'mode_rpi' or 'mode_bcm' | ||
*/ | ||
this.setMode = function(mode) { | ||
if (mode === this.MODE_RPI) { | ||
getPinForCurrentMode = getPinRpi; | ||
} else if (mode === this.MODE_BCM) { | ||
getPinForCurrentMode = getPinBcm; | ||
} else { | ||
throw new Error('Cannot set invalid mode'); | ||
} | ||
/** | ||
* Setup a channel for use as an input or output | ||
* | ||
* @param {number} channel Reference to the pin in the current mode's schema | ||
* @param {string} direction The pin direction, either 'in' or 'out' | ||
* @param {function} cb Optional callback | ||
*/ | ||
Gpio.prototype.setup = function(channel, direction, cb /*err*/) { | ||
if (!channel) { | ||
return cb(new Error('Channel not specified')); | ||
} | ||
this.emit('modeChange', mode); | ||
}; | ||
direction = direction || this.DIR_OUT; | ||
/** | ||
* Setup a channel for use as an input or output | ||
* | ||
* @param {number} channel Reference to the pin in the current mode's schema | ||
* @param {string} direction The pin direction, either 'in' or 'out' | ||
* @param {function} cb Optional callback | ||
*/ | ||
this.setup = function(channel, direction, cb /*err*/) { | ||
if (!channel) { | ||
return process.nextTick(function() { | ||
cb(new Error('Channel not specified')); | ||
}); | ||
} | ||
if (typeof direction === 'function') { | ||
cb = direction; | ||
direction = this.DIR_OUT; | ||
} | ||
direction = direction || this.DIR_OUT; | ||
if (direction !== this.DIR_IN && direction !== this.DIR_OUT) { | ||
return cb(new Error('Cannot set invalid direction')); | ||
} | ||
if (typeof direction === 'function') { | ||
cb = direction; | ||
direction = this.DIR_OUT; | ||
} | ||
var pin; | ||
async.waterfall([ | ||
function(next) { | ||
setRaspberryVersion(next); | ||
}, | ||
function(next) { | ||
pin = getPinForCurrentMode(channel); | ||
isExported(pin, next); | ||
}, | ||
function(isExported, next) { | ||
if (isExported) { | ||
return unexportPin(pin, next); | ||
} | ||
return next(null); | ||
}, | ||
function(next) { | ||
exportPin(pin, next); | ||
}, | ||
function(next) { | ||
this.exportedPins[pin] = true; | ||
this.emit('export', channel); | ||
createListener.call(this, channel, pin); | ||
setDirection(pin, direction, next); | ||
}.bind(this) | ||
], cb); | ||
}; | ||
if (direction !== this.DIR_IN && direction !== this.DIR_OUT) { | ||
return process.nextTick(function() { | ||
cb(new Error('Cannot set invalid direction')); | ||
}); | ||
} | ||
/** | ||
* Write a value to a channel | ||
* | ||
* @param {number} channel The channel to write to | ||
* @param {boolean} value If true, turns the channel on, else turns off | ||
* @param {function} cb Optional callback | ||
*/ | ||
Gpio.prototype.write = function(channel, value, cb /*err*/ ) { | ||
var pin = getPinForCurrentMode(channel); | ||
if (!this.exportedPins[pin]) { | ||
return cb(new Error('Pin has not been exported')); | ||
} | ||
var pin; | ||
async.waterfall([ | ||
function(next) { | ||
setRaspberryVersion(currentPins, function(err, pinSchema) { | ||
if (err) next(err); | ||
currentPins = pinSchema; | ||
next(); | ||
}); | ||
}, | ||
function(next) { | ||
pin = getPinForCurrentMode(currentPins, channel); | ||
debug('set up pin %d', pin); | ||
isExported(pin, next); | ||
}, | ||
function(isExported, next) { | ||
if (isExported) { | ||
return unexportPin(pin, next); | ||
} | ||
return next(null); | ||
}, | ||
function(next) { | ||
exportPin(pin, next); | ||
}, | ||
function(next) { | ||
exportedPins[pin] = true; | ||
this.emit('export', channel); | ||
createListener.call(this, channel, pin); | ||
setDirection(pin, direction, next); | ||
}.bind(this) | ||
], cb); | ||
}; | ||
value = (!!value && value !== '0') ? '1' : '0'; | ||
fs.writeFile(PATH + '/gpio' + pin + '/value', value, cb || function () {}); | ||
}; | ||
Gpio.prototype.output = Gpio.prototype.write; | ||
/** | ||
* Write a value to a channel | ||
* | ||
* @param {number} channel The channel to write to | ||
* @param {boolean} value If true, turns the channel on, else turns off | ||
* @param {function} cb Optional callback | ||
*/ | ||
this.write = this.output = function(channel, value, cb /*err*/ ) { | ||
var pin = getPinForCurrentMode(currentPins, channel); | ||
/** | ||
* Read a value from a channel | ||
* | ||
* @param {number} channel The channel to read from | ||
* @param {function} cb Callback which receives the channel's boolean value | ||
*/ | ||
Gpio.prototype.read = function(channel, cb /*err,value*/) { | ||
var pin = getPinForCurrentMode(channel); | ||
if (!exportedPins[pin]) { | ||
return process.nextTick(function() { | ||
cb(new Error('Pin has not been exported')); | ||
}); | ||
} | ||
if (!this.exportedPins[pin]) { | ||
return cb(new Error('Pin has not been exported')); | ||
} | ||
value = (!!value && value !== '0') ? '1' : '0'; | ||
fs.writeFile(PATH + '/gpio' + pin + '/value', value, cb || function () {}); | ||
}; | ||
fs.readFile(PATH + '/gpio' + pin + '/value', 'utf-8', function(err, data) { | ||
data = (data + '').trim() || '0'; | ||
return cb(err, data === '1'); | ||
}); | ||
}; | ||
Gpio.prototype.input = Gpio.prototype.read; | ||
/** | ||
* Read a value from a channel | ||
* | ||
* @param {number} channel The channel to read from | ||
* @param {function} cb Callback which receives the channel's boolean value | ||
*/ | ||
this.read = this.input = function(channel, cb /*err,value*/) { | ||
var pin = getPinForCurrentMode(currentPins, channel); | ||
/** | ||
* Unexport any pins setup by this module | ||
* | ||
* @param {function} cb Optional callback | ||
*/ | ||
Gpio.prototype.destroy = function(cb) { | ||
var tasks = Object.keys(this.exportedPins).map(function(pin) { | ||
return function(done) { | ||
unexportPin(pin, done); | ||
if (!exportedPins[pin]) { | ||
return process.nextTick(function() { | ||
cb(new Error('Pin has not been exported')); | ||
}); | ||
} | ||
}); | ||
async.parallel(tasks, cb); | ||
}; | ||
/** | ||
* Reset the state of the module | ||
*/ | ||
Gpio.prototype.reset = function() { | ||
this.exportedPins = {}; | ||
this.removeAllListeners(); | ||
fs.readFile(PATH + '/gpio' + pin + '/value', 'utf-8', function(err, data) { | ||
data = (data + '').trim() || '0'; | ||
return cb(err, data === '1'); | ||
}); | ||
}; | ||
pins.current = undefined; | ||
getPinForCurrentMode = getPinRpi; | ||
}; | ||
/** | ||
* Unexport any pins setup by this module | ||
* | ||
* @param {function} cb Optional callback | ||
*/ | ||
this.destroy = function(cb) { | ||
var tasks = Object.keys(exportedPins).map(function(pin) { | ||
return function(done) { | ||
unexportPin(pin, done); | ||
} | ||
}); | ||
async.parallel(tasks, cb); | ||
}; | ||
/** | ||
* Sets the version of the model | ||
*/ | ||
function setRaspberryVersion(cb) { | ||
if (pins.current) { | ||
/** | ||
* Reset the state of the module | ||
*/ | ||
this.reset = function() { | ||
exportedPins = {}; | ||
this.removeAllListeners(); | ||
currentPins = undefined; | ||
exportedPins = {}; | ||
getPinForCurrentMode = getPinRpi; | ||
}; | ||
// Init | ||
EventEmitter.call(this); | ||
this.reset(); | ||
} | ||
util.inherits(Gpio, EventEmitter); | ||
function setRaspberryVersion(currentPins, cb) { | ||
if (currentPins) { | ||
return cb(null); | ||
@@ -227,19 +241,19 @@ } | ||
var revisionNumber = parseInt(match[1], 16); | ||
var pinVersion = (revisionNumber < 4) ? 'v1' : 'v2'; | ||
if (revisionNumber < 3) { | ||
pins.current = pins.v1; | ||
} else { | ||
pins.current = pins.v2; | ||
} | ||
debug( | ||
'seen hardware revision %d; using pin mode %s', | ||
revisionNumber, | ||
pinVersion | ||
); | ||
return cb(null); | ||
return cb(null, pins[pinVersion]); | ||
}); | ||
}; | ||
var getPinForCurrentMode = getPinRpi; | ||
function getPinRpi(channel) { | ||
return pins.current[channel] + ''; | ||
function getPinRpi(currentPins, channel) { | ||
return currentPins[channel] + ''; | ||
}; | ||
function getPinBcm(channel) { | ||
function getPinBcm(currentPins, channel) { | ||
return channel + ''; | ||
@@ -249,2 +263,3 @@ }; | ||
function createListener(channel, pin) { | ||
debug('listen for pin %d', pin); | ||
var self = this; | ||
@@ -260,2 +275,3 @@ fs.watchFile(PATH + '/gpio' + pin + '/value', function() { | ||
function setDirection(pin, direction, cb) { | ||
debug('set direction %s on pin %d', direction.toUpperCase(), pin); | ||
fs.writeFile(PATH + '/gpio' + pin + '/direction', direction, function(err) { | ||
@@ -267,2 +283,3 @@ if (cb) return cb(err); | ||
function exportPin(pin, cb) { | ||
debug('export pin %d', pin); | ||
fs.writeFile(PATH + '/export', pin, function(err) { | ||
@@ -274,2 +291,3 @@ if (cb) return cb(err); | ||
function unexportPin(pin, cb) { | ||
debug('unexport pin %d', pin); | ||
fs.unwatchFile(PATH + '/gpio' + pin + '/value'); | ||
@@ -276,0 +294,0 @@ fs.writeFile(PATH + '/unexport', pin, function(err) { |
@@ -10,6 +10,7 @@ var assert = require('assert'); | ||
var cpuinfo = { | ||
v1: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 0002\nSerial : 000000009a5d9c22', | ||
v1Overvolted: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 100000002\nSerial : 000000009a5d9c22', | ||
v2: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 000e\nSerial : 000000009a5d9c22', | ||
v2Overvolted: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 10000003\nSerial : 000000009a5d9c22' | ||
v1: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 0003\nSerial : 000000009a5d9c22', | ||
v1Overvolted: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 100000003\nSerial : 000000009a5d9c22', | ||
v2: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 0004\nSerial : 000000009a5d9c22', | ||
v2Overvolted: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 10000004\nSerial : 000000009a5d9c22', | ||
v2latest: 'Processor : ARMv6-compatible processor rev 7 (v6l)\nBogoMIPS : 697.95\nFeatures : swp half thumb fastmult vfp edsp java tls\nCPU implementer : 0x41\nCPU architecture: 7\nCPU variant : 0x0\nCPU part : 0xb76\nCPU revision : 7\n\n\nHardware : BCM2708\nRevision : 000f\nSerial : 000000009a5d9c22' | ||
} | ||
@@ -563,2 +564,44 @@ | ||
context('using Raspberry Pi latest revision 2 hardware', function() { | ||
beforeEach(function() { | ||
fs.readFile.withArgs('/proc/cpuinfo').yieldsAsync(null, cpuinfo.v2latest); | ||
}); | ||
var map = { | ||
// RPI to BCM | ||
'3': '2', | ||
'5': '3', | ||
'7': '4', | ||
'8': '14', | ||
'10': '15', | ||
'11': '17', | ||
'12': '18', | ||
'13': '27', | ||
'15': '22', | ||
'16': '23', | ||
'18': '24', | ||
'19': '10', | ||
'21': '9', | ||
'22': '25', | ||
'23': '11', | ||
'24': '8', | ||
'26': '7' | ||
} | ||
Object.keys(map).forEach(function(rpiPin) { | ||
var bcmPin = map[rpiPin]; | ||
context('writing to RPI pin ' + rpiPin, function() { | ||
beforeEach(function(done) { | ||
gpio.setup(rpiPin, gpio.DIR_IN, done); | ||
}); | ||
it('should write to pin ' + bcmPin + ' (BCM)', function() { | ||
assert.equal(fs.writeFile.getCall(0).args[1], bcmPin); | ||
}); | ||
}); | ||
}); | ||
}); | ||
context('using Raspberry Pi revision 1 hardware overvolted', function() { | ||
@@ -565,0 +608,0 @@ beforeEach(function() { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
42084
9
852
2
+ Addeddebug@~0.8.1
+ Addeddebug@0.8.1(transitive)