Comparing version 0.3.4 to 0.4.0
{ | ||
"name": "rpi-gpio", | ||
"version": "0.3.4", | ||
"version": "0.4.0", | ||
"description": "Control Raspberry Pi GPIO pins with node.js", | ||
@@ -5,0 +5,0 @@ "main": "rpi-gpio.js", |
rpi-gpio.js | ||
========== | ||
Control Raspberry Pi GPIO pins with node.js | ||
@@ -11,5 +10,5 @@ | ||
## Setup | ||
See this guide on how to get [node.js running on Raspberry Pi](http://elsmorian.com/post/23474168753/node-js-on-raspberry-pi). | ||
See this guide on how to get [node.js running on Raspberry Pi](http://joshondesign.com/2013/10/23/noderpi). | ||
This module can be installed with npm: | ||
This module can then be installed with npm: | ||
```js | ||
@@ -20,8 +19,48 @@ npm install rpi-gpio | ||
## Usage | ||
Please see the examples below. Make make sure you are running as root or with sudo, else the Raspberry Pi will not let you output to the GPIO. All of the functions relating to the pins within this module are asynchronous, so where necessary - for example in reading the value of a pin - a callback must be provided. | ||
Firstly, make make sure you are running your application as root or with sudo, else the Raspberry Pi will not let you output to the GPIO. | ||
Please note that there are two different ways to reference a channel; either using the Raspberry Pi or the BCM/SoC naming schema (sadly, neither of which match the physical pins!). This module supports both schemas, with Raspberry Pi being the default. Please see [this page](http://elinux.org/RPi_Low-level_peripherals) for more details. | ||
Before you can read or write, you must use setup() to open a channel, and must specify whether it will be used for input or output. Having done this, you can then read in the state of the channel or write a value to it using read() or write(). | ||
All of the functions relating to the pin state within this module are asynchronous, so where necessary - for example in reading the value of a channel - a callback must be provided. This module inherits the standard [EventEmitter](http://nodejs.org/api/events.html), so you may use its functions to listen to events. | ||
### Query the value of a pin | ||
Please note that there are two different and confusing ways to reference a channel; either using the Raspberry Pi or the BCM/SoC naming schema (sadly, neither of which match the physical pins!). This module supports both schemas, with Raspberry Pi being the default. Please see [this page](http://elinux.org/RPi_Low-level_peripherals) for more details. | ||
## API | ||
### setup(channel [, direction], callback) | ||
Sets up a channel for read or write. Must be done before the channel can be used. | ||
* channel: Reference to the pin in the current mode's schema. | ||
* direction: The pin direction, pass either DIR_IN for read mode or DIR_OUT for write mode. Defaults to DIR_OUT. | ||
* callback: Provides Error as the first argument if an error occured. | ||
### read(channel, callback) | ||
Reads the value of a channel. | ||
* channel: Reference to the pin in the current mode's schema. | ||
* callback: Provides Error as the first argument if an error occured, otherwise the pin value boolean as the second argument. | ||
### write(channel, value [, callback]) | ||
Writes the value of a channel. | ||
* channel: Reference to the pin in the current mode's schema. | ||
* value: Boolean value to specify whether the channel will turn on or off. | ||
* callback: Provides Error as the first argument if an error occured. | ||
### setMode(mode) | ||
Sets the channel addressing schema. | ||
* mode: Specify either Raspberry Pi or SoC/BCM pin schemas, by passing MODE_RPI or MODE_BCM. Defaults to MODE_RPI. | ||
### input() | ||
Alias of read(). | ||
### output() | ||
Alias of write(). | ||
### destroy() | ||
Tears down any previously set up channels. | ||
### reset() | ||
Tears down the module state - used for testing. | ||
## Examples | ||
### Setup and read the value of a pin | ||
```js | ||
@@ -39,17 +78,6 @@ var gpio = require('rpi-gpio'); | ||
### Listen for changes on a pin | ||
The GPIO module inherits from `EventEmitter` so any of the [EventEmitter functions](http://nodejs.org/api/events.html) can be used. The example below shows how to listen for a change in value to a channel. | ||
### Setup and write to a pin | ||
```js | ||
var gpio = require('rpi-gpio'); | ||
gpio.on('change', function(channel, value) { | ||
console.log('Channel ' + channel + ' value is now ' + value); | ||
}); | ||
gpio.setup(7, gpio.DIR_IN); | ||
``` | ||
### Write to a pin | ||
```js | ||
var gpio = require('rpi-gpio'); | ||
gpio.setup(7, gpio.DIR_OUT, write); | ||
@@ -65,5 +93,14 @@ | ||
### Unexport pins when finished | ||
This will close any pins that were opened by the module. | ||
### Listen for changes on a pin | ||
```js | ||
var gpio = require('rpi-gpio'); | ||
gpio.on('change', function(channel, value) { | ||
console.log('Channel ' + channel + ' value is now ' + value); | ||
}); | ||
gpio.setup(7, gpio.DIR_IN); | ||
``` | ||
### Unexport pins opened by the module when finished | ||
```js | ||
var gpio = require('../rpi-gpio'); | ||
@@ -97,6 +134,6 @@ | ||
var pin = 7, | ||
delay = 2000, | ||
count = 0, | ||
max = 3; | ||
var pin = 7; | ||
var delay = 2000; | ||
var count = 0; | ||
var max = 3; | ||
@@ -103,0 +140,0 @@ gpio.on('change', function(channel, value) { |
@@ -69,3 +69,4 @@ var fs = require('fs'); | ||
var currentPins; | ||
var exportedPins = {}; | ||
var exportedInputPins = {}; | ||
var exportedOutputPins = {}; | ||
var getPinForCurrentMode = getPinRpi; | ||
@@ -149,5 +150,11 @@ | ||
function(next) { | ||
exportedPins[pinForSetup] = true; | ||
this.emit('export', channel); | ||
createListener.call(this, channel, pinForSetup); | ||
if (direction === this.DIR_IN) { | ||
exportedInputPins[pinForSetup] = true; | ||
} else { | ||
exportedOutputPins[pinForSetup] = true; | ||
} | ||
setDirection(pinForSetup, direction, next); | ||
@@ -168,5 +175,12 @@ }.bind(this) | ||
if (!exportedPins[pin]) { | ||
if (!exportedOutputPins[pin]) { | ||
var message; | ||
if (exportedInputPins[pin]) { | ||
message = 'Pin has been exported for input so cannot be written to'; | ||
} else { | ||
message = 'Pin has not been exported'; | ||
} | ||
return process.nextTick(function() { | ||
cb(new Error('Pin has not been exported')); | ||
cb(new Error(message)); | ||
}); | ||
@@ -188,3 +202,3 @@ } | ||
if (!exportedPins[pin]) { | ||
if (!exportedInputPins[pin]) { | ||
return process.nextTick(function() { | ||
@@ -207,7 +221,10 @@ cb(new Error('Pin has not been exported')); | ||
this.destroy = function(cb) { | ||
var tasks = Object.keys(exportedPins).map(function(pin) { | ||
return function(done) { | ||
unexportPin(pin, done); | ||
} | ||
}); | ||
var tasks = Object.keys(exportedOutputPins) | ||
.concat(Object.keys(exportedInputPins)) | ||
.map(function(pin) { | ||
return function(done) { | ||
unexportPin(pin, done); | ||
} | ||
}); | ||
async.parallel(tasks, cb); | ||
@@ -220,7 +237,7 @@ }; | ||
this.reset = function() { | ||
exportedPins = {}; | ||
exportedOutputPins = {}; | ||
exportedInputPins = {}; | ||
this.removeAllListeners(); | ||
currentPins = undefined; | ||
exportedPins = {}; | ||
getPinForCurrentMode = getPinRpi; | ||
@@ -271,3 +288,3 @@ }; | ||
Gpio.read(channel, function(err, value) { | ||
if (err) return cb(err); | ||
// @todo how should error be handled here? | ||
Gpio.emit('change', channel, value); | ||
@@ -274,0 +291,0 @@ }); |
233
test/main.js
@@ -9,8 +9,5 @@ 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 : 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' | ||
function getCpuInfo(revision) { | ||
revision = revision || '0002'; | ||
return '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 : ' + revision + '\nSerial : 000000009a5d9c22'; | ||
} | ||
@@ -25,3 +22,3 @@ | ||
sinon.stub(fs, 'readFile') | ||
.withArgs('/proc/cpuinfo').yieldsAsync(null, cpuinfo.v1); | ||
.withArgs('/proc/cpuinfo').yieldsAsync(null, getCpuInfo()); | ||
sinon.spy(fs, 'unwatchFile'); | ||
@@ -332,2 +329,27 @@ }); | ||
context('when pin 1 has been setup for input', function() { | ||
var onSetup; | ||
var onWrite; | ||
beforeEach(function(done) { | ||
onSetup = sinon.spy(done); | ||
gpio.setup(1, gpio.DIR_IN, onSetup); | ||
}); | ||
context('and pin 1 is written to with boolean true', function() { | ||
beforeEach(function(done) { | ||
var callback = function() { | ||
done(); | ||
} | ||
onWrite = sinon.spy(callback); | ||
gpio.write(1, true, onWrite); | ||
}); | ||
it('should run the callback with an error', function() { | ||
sinon.assert.calledOnce(onWrite); | ||
assert.ok(onWrite.getCall(0).args[0]); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -337,3 +359,3 @@ | ||
context('when pin 1 is setup', function() { | ||
context('when pin 1 is setup for input', function() { | ||
beforeEach(function(done) { | ||
@@ -478,3 +500,3 @@ gpio.setup(1, gpio.DIR_IN, done); | ||
describe('pin translation', function() { | ||
describe('handles pin translation', function() { | ||
@@ -486,8 +508,22 @@ context('when in RPI mode', function() { | ||
context('using Raspberry Pi revision 1 hardware', function() { | ||
beforeEach(function() { | ||
fs.readFile.withArgs('/proc/cpuinfo').yieldsAsync(null, cpuinfo.v1); | ||
}); | ||
var revisionMap = { | ||
'0002': 'v1', | ||
'0003': 'v1', | ||
'0004': 'v2', | ||
'0005': 'v2', | ||
'0006': 'v2', | ||
'0007': 'v2', | ||
'0008': 'v2', | ||
'0009': 'v2', | ||
'000d': 'v2', | ||
'000e': 'v2', | ||
'000f': 'v2', | ||
// Over-volted hardware | ||
'10000003': 'v1', | ||
'10000004': 'v2', | ||
'1000000f': 'v2' | ||
}; | ||
var map = { | ||
var map = { | ||
v1: { | ||
// RPI to BCM | ||
@@ -511,25 +547,4 @@ '3': '0', | ||
'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 2 hardware', function() { | ||
beforeEach(function() { | ||
fs.readFile.withArgs('/proc/cpuinfo').yieldsAsync(null, cpuinfo.v2); | ||
}); | ||
var map = { | ||
}, | ||
v2: { | ||
// RPI to BCM | ||
@@ -554,142 +569,30 @@ '3': '2', | ||
} | ||
}; | ||
Object.keys(map).forEach(function(rpiPin) { | ||
var bcmPin = map[rpiPin]; | ||
Object.keys(revisionMap).forEach(function(revision) { | ||
var revisionSchema = revisionMap[revision]; | ||
var pinMap = map[revisionSchema]; | ||
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('and hardware revision is: ' + revision, function() { | ||
beforeEach(function() { | ||
fs.readFile.withArgs('/proc/cpuinfo').yieldsAsync(null, getCpuInfo(revision)); | ||
}); | ||
}); | ||
}); | ||
context('using Raspberry Pi latest revision 2 hardware', function() { | ||
beforeEach(function() { | ||
fs.readFile.withArgs('/proc/cpuinfo').yieldsAsync(null, cpuinfo.v2latest); | ||
}); | ||
Object.keys(pinMap).forEach(function(rpiPin) { | ||
var bcmPin = pinMap[rpiPin]; | ||
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' | ||
} | ||
context('writing to RPI pin ' + rpiPin, function() { | ||
beforeEach(function(done) { | ||
gpio.setup(rpiPin, gpio.DIR_IN, done); | ||
}); | ||
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); | ||
}); | ||
}); | ||
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() { | ||
beforeEach(function() { | ||
fs.readFile.withArgs('/proc/cpuinfo').yieldsAsync(null, cpuinfo.v1Overvolted); | ||
}); | ||
var map = { | ||
// RPI to BCM | ||
'3': '0', | ||
'5': '1', | ||
'7': '4', | ||
'8': '14', | ||
'10': '15', | ||
'11': '17', | ||
'12': '18', | ||
'13': '21', | ||
'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 2 hardware overvolted', function() { | ||
beforeEach(function() { | ||
fs.readFile.withArgs('/proc/cpuinfo').yieldsAsync(null, cpuinfo.v2Overvolted); | ||
}); | ||
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); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -696,0 +599,0 @@ |
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
224
39886
8
774