├── gulpfile.js ├── test ├── gpio │ └── README.md ├── transform_rpio_sim.js ├── rpio_sim_helper.js ├── lib │ ├── index.js │ ├── gpio_util.js │ ├── write_stream.js │ ├── read_stream.js │ ├── gpio_group.js │ └── gpio.js ├── spec.js └── rpio_sim.js ├── .gitignore ├── travis_pre_install.sh ├── examples ├── stream_read.js ├── simple_toggle.js ├── trace_input.js ├── stream_write.js ├── async_toggle.js ├── async_toggle2.js ├── toggle_with_a_button.js ├── read_write.js └── traffic.js ├── .travis.yml ├── lib ├── gpio_util.js ├── index.js ├── write_stream.js ├── read_stream.js ├── gpio_group.js └── gpio.js ├── package.json ├── script └── printcov.js └── README.md /gulpfile.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/gpio/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | test-app 4 | coverage.lcov 5 | npm-debug.log 6 | sftp-config.json 7 | -------------------------------------------------------------------------------- /travis_pre_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sed -i '/"rpio": .*/d' ./package.json 3 | 4 | # for mac 5 | # sed -i "" '/"rpio": .*/d' ./package.json 6 | -------------------------------------------------------------------------------- /examples/stream_read.js: -------------------------------------------------------------------------------- 1 | const Gpio = require('../lib/index.js').Gpio; 2 | 3 | var gs = Gpio.createReadStream(32, {throttle: 100}); 4 | 5 | gs.pipe(process.stdout); 6 | 7 | process.on("SIGINT", function(){ 8 | gs.end(); 9 | process.exit(0); 10 | }); 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '4' 4 | sudo: false 5 | before_install: 6 | - sh travis_pre_install.sh 7 | script: 8 | - "npm run test-cov" 9 | after_script: "npm install coveralls && cd lib && cat coverage.lcov | ../node_modules/coveralls/bin/coveralls.js && cd .." -------------------------------------------------------------------------------- /examples/simple_toggle.js: -------------------------------------------------------------------------------- 1 | const Gpio = require('../lib/index.js').Gpio; 2 | const gpio = new Gpio(40); 3 | 4 | gpio.open(Gpio.OUTPUT); 5 | 6 | for(var i = 0; i < 10; i++){ 7 | gpio.sleep(500); 8 | gpio.toggle(); 9 | gpio.sleep(500); 10 | gpio.toggle(); 11 | } 12 | 13 | gpio.close(); 14 | -------------------------------------------------------------------------------- /examples/trace_input.js: -------------------------------------------------------------------------------- 1 | const Gpio = require('../lib/index.js').Gpio; 2 | 3 | var input = Gpio.createReadStream(32, {throttle: 100}); 4 | 5 | var output = Gpio.createWriteStream(40); 6 | 7 | input.pipe(output); 8 | 9 | process.on("SIGINT", function(){ 10 | input.end(); 11 | output.end(); 12 | process.exit(0); 13 | }); 14 | 15 | -------------------------------------------------------------------------------- /examples/stream_write.js: -------------------------------------------------------------------------------- 1 | const Gpio = require('../lib/index.js').Gpio; 2 | 3 | var gs = Gpio.createWriteStream(40, { 4 | mode: Gpio.OUTPUT, 5 | state: Gpio.HIGH 6 | }); 7 | 8 | console.log('Please input value of P40.'); 9 | 10 | process.stdin.pipe(gs); 11 | 12 | process.on("SIGINT", function(){ 13 | gs.end(); 14 | process.exit(0); 15 | }); 16 | 17 | -------------------------------------------------------------------------------- /examples/async_toggle.js: -------------------------------------------------------------------------------- 1 | const Gpio = require('../lib/index.js').Gpio; 2 | const gpio = new Gpio(40); 3 | 4 | gpio.open(Gpio.OUTPUT); 5 | 6 | void function loop(){ 7 | Promise.resolve(gpio.toggle()) 8 | .then(gpio.sleep.bind(null, 500, true)) 9 | .then(loop) 10 | }(); 11 | 12 | process.on("SIGINT", function(){ 13 | gpio.close(); 14 | 15 | console.log('shutdown!'); 16 | process.exit(0); 17 | }); 18 | -------------------------------------------------------------------------------- /test/transform_rpio_sim.js: -------------------------------------------------------------------------------- 1 | module.exports = function(babel) { 2 | var t = babel.types; 3 | 4 | return {visitor: { 5 | CallExpression: function(path){ 6 | if(path.node.callee.name === 'require'){ 7 | var module = path.node.arguments[0]; 8 | if(module && module.value === 'rpio'){ 9 | module.value = '../rpio_sim.js'; 10 | } 11 | } 12 | } 13 | }}; 14 | }; 15 | -------------------------------------------------------------------------------- /examples/async_toggle2.js: -------------------------------------------------------------------------------- 1 | const wait = require('wait-promise'); 2 | const Gpio = require('../lib/index.js').Gpio; 3 | 4 | var gpio = new Gpio(40); 5 | gpio.open(Gpio.OUTPUT); 6 | 7 | wait.every(500).and(function(){ 8 | //forever - never return true 9 | gpio.toggle(); 10 | 11 | }).forward(); 12 | 13 | process.on("SIGINT", function(){ 14 | gpio.close(); 15 | 16 | console.log('shutdown!'); 17 | process.exit(0); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/toggle_with_a_button.js: -------------------------------------------------------------------------------- 1 | const Gpio = require('../lib/index.js').Gpio; 2 | const button = new Gpio(32); 3 | const output = new Gpio(40); 4 | 5 | button.open(Gpio.INPUT); 6 | output.open(Gpio.OUTPUT, Gpio.LOW); 7 | 8 | //button down 9 | button.on('rising', function(obj){ 10 | output.toggle(); 11 | }); 12 | 13 | process.on("SIGINT", function(){ 14 | button.close(); 15 | output.close(); 16 | 17 | console.log('shutdown!'); 18 | process.exit(0); 19 | }); 20 | -------------------------------------------------------------------------------- /lib/gpio_util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const rpio = require('rpio'); 4 | 5 | rpio.POLL_NONE = 0; 6 | rpio.PULL_DEFAULT = -1; 7 | rpio.UNKNOWN = -1; 8 | 9 | const props = [ 10 | 'UNKNOWN','INPUT','OUTPUT', 11 | 'PULL_OFF','PULL_DOWN','PULL_UP','PULL_DEFAULT', 12 | 'HIGH','LOW', 13 | 'POLL_NONE','POLL_LOW','POLL_HIGH','POLL_BOTH' 14 | ]; 15 | 16 | function defineStaticProperties(obj){ 17 | props.forEach(function(prop){ 18 | Object.defineProperty(obj, prop, { 19 | value: rpio[prop], 20 | writable: false, 21 | configurable: false, 22 | enumerable: true 23 | }); 24 | }); 25 | } 26 | 27 | module.exports = { 28 | defineStaticProperties: defineStaticProperties 29 | } 30 | -------------------------------------------------------------------------------- /test/rpio_sim_helper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | var pin = 0|process.argv[2]; 6 | var timers = process.argv[3].split(',').map(o => 0|o); 7 | var fileName = './test/gpio/gpio' + pin; 8 | 9 | 10 | function writeAndWait(value, time){ 11 | fs.writeFileSync(fileName, new Buffer([value])); 12 | return new Promise(function(resolve){ 13 | setTimeout(resolve, time); 14 | }); 15 | } 16 | 17 | var p = Promise.resolve(); 18 | 19 | for(var i = 0; i < timers.length; i += 2){ 20 | p = p.then(((i) => () => writeAndWait(timers[i], timers[i + 1]))(i)); 21 | } 22 | 23 | p.then(function(){ 24 | var content = fs.readFileSync(fileName); 25 | console.log(content); 26 | }).catch(err => console.log(err)); 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/read_write.js: -------------------------------------------------------------------------------- 1 | const Gpio = require('../lib/index.js').Gpio; 2 | const gpio = new Gpio(40); 3 | 4 | gpio.open(Gpio.OUTPUT); 5 | gpio.write(0b10101); //on 6 | gpio.sleep(1000); 7 | 8 | console.log(gpio.value); //1 9 | 10 | gpio.write('01010'); //off 11 | 12 | gpio.sleep(1000); 13 | 14 | console.log(gpio.value); //0 15 | gpio.activeLow = true; 16 | console.log(gpio.value); //1 17 | 18 | console.log(gpio.read(5).join('')); 19 | 20 | const gpio2 = new Gpio(32); 21 | gpio2.open(Gpio.INPUT); 22 | 23 | setInterval(function(){ 24 | console.log(gpio2.read(5).join('')); 25 | },100); 26 | 27 | process.on("SIGINT", function(){ 28 | gpio.close(); 29 | gpio2.close(); 30 | 31 | console.log('shutdown!'); 32 | process.exit(0); 33 | }); 34 | 35 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const rpio = require('rpio'), 4 | Gpio = require('./gpio.js'), 5 | GpioGroup = require('./gpio_group.js'), 6 | ReadStream = require('./read_stream.js'), 7 | WriteStream = require('./write_stream.js'); 8 | 9 | Gpio.createReadStream = function(pin, options){ 10 | return new ReadStream(pin, options); 11 | } 12 | Gpio.createWriteStream = function(pin, options){ 13 | return new WriteStream(pin, options); 14 | } 15 | Gpio.group = function(pins, activeLow){ 16 | return new GpioGroup(pins, activeLow); 17 | } 18 | 19 | var rpio2 = { 20 | init: rpio.init, 21 | rpio: rpio, 22 | Gpio: Gpio, 23 | ReadStream: ReadStream, 24 | WriteStream: WriteStream, 25 | GpioGroup: GpioGroup 26 | } 27 | 28 | require('./gpio_util.js').defineStaticProperties(rpio2); 29 | 30 | module.exports = rpio2; 31 | -------------------------------------------------------------------------------- /lib/write_stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Writable = require("stream").Writable; 4 | var inherits = require("util").inherits; 5 | 6 | var Gpio = require("./gpio.js"); 7 | 8 | function WriteStream(gpio, options) { 9 | options = Object.assign({ 10 | mode: Gpio.OUTPUT 11 | }, options); 12 | 13 | if(typeof gpio === 'number'){ 14 | gpio = new Gpio(gpio); 15 | gpio.open(options.mode, options.state); 16 | this._autoClose = true; 17 | } 18 | 19 | Writable.call(this, options); 20 | this.gpio = gpio; 21 | } 22 | 23 | inherits(WriteStream, Writable) 24 | 25 | WriteStream.prototype._write = function (chunk, encoding, callback) { 26 | this.gpio.write(chunk); 27 | callback(); 28 | } 29 | 30 | WriteStream.prototype.end = function(){ 31 | if(this._autoClose) this.gpio.close(); 32 | Writable.prototype.end.call(this); 33 | } 34 | 35 | module.exports = WriteStream; 36 | -------------------------------------------------------------------------------- /examples/traffic.js: -------------------------------------------------------------------------------- 1 | var GpioGroup = require('../lib/index.js').GpioGroup; 2 | var pins = [32, 40, 33]; //RGB 3 | var group = new GpioGroup(pins, true); 4 | group.open(GpioGroup.OUTPUT); 5 | 6 | var color = { 7 | yellow: 0b110, 8 | red: 0b100, 9 | green: 0b010 10 | }; 11 | 12 | function turn(color){ 13 | return new Promise(function(resolve, reject) { 14 | group.value = color; 15 | resolve(); 16 | }) 17 | } 18 | function wait(time){ 19 | return new Promise(function(resolve, reject) { 20 | setTimeout(resolve,time); 21 | }) 22 | } 23 | 24 | void function (){ 25 | turn(color.green) 26 | .then(wait.bind(null, 5000)) 27 | .then(turn.bind(null, color.yellow)) 28 | .then(wait.bind(null, 2000)) 29 | .then(turn.bind(null, color.red)) 30 | .then(wait.bind(null, 5000)) 31 | .then(arguments.callee) 32 | }(); 33 | 34 | process.on("SIGINT", function(){ 35 | group.close(); 36 | 37 | console.log('shutdown!'); 38 | process.exit(0); 39 | }); 40 | -------------------------------------------------------------------------------- /lib/read_stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Readable = require("stream").Readable; 4 | const inherits = require("util").inherits; 5 | 6 | const Gpio = require('./gpio.js'); 7 | 8 | function ReadStream(gpio, options){ 9 | options = Object.assign({ 10 | mode: Gpio.INPUT 11 | }, options); 12 | 13 | if(typeof gpio === 'number'){ 14 | gpio = new Gpio(gpio); 15 | gpio.open(options.mode, options.state); 16 | this._autoClose = true; 17 | } 18 | 19 | if(options && options.throttle){ 20 | this.throttle = options.throttle; 21 | this.timer = null; 22 | } 23 | 24 | Readable.call(this, options); 25 | this.gpio = gpio; 26 | } 27 | 28 | inherits(ReadStream, Readable); 29 | 30 | ReadStream.prototype._read = function (size) { 31 | if(!this.throttle){ 32 | var buf = this.gpio.read(size); 33 | this.push(buf.join('')); 34 | }else if(!this.timer){ 35 | var self = this; 36 | this.timer = setTimeout(function(){ 37 | self.timer = null; 38 | self.push(self.gpio.value.toString()); 39 | self.read(0); 40 | }, this.throttle); 41 | } 42 | } 43 | 44 | ReadStream.prototype.end = function(){ 45 | if(this._autoClose) this.gpio.close(); 46 | this.emit('end'); 47 | } 48 | 49 | module.exports = ReadStream; 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rpio2", 3 | "version": "0.4.1", 4 | "description": "Control Raspberry Pi GPIO pins with node.js. Fast and easy to use.", 5 | "main": "lib/index.js", 6 | "dependencies": { 7 | "rpio": "^0.9.11" 8 | }, 9 | "devDependencies": { 10 | "consoler": "^0.2.0", 11 | "chokidar": "^1.6.0", 12 | "wait-promise": "0.4.1", 13 | "babel-cli": "6.x.x", 14 | "babel-runtime": "6.x.x", 15 | "mocha": "^2.3.4", 16 | "mocha-lcov-reporter": "^1.2.0", 17 | "chai": "^3.4.1", 18 | "babel-plugin-transform-coverage": "^0.1.5" 19 | }, 20 | "scripts": { 21 | "test": "babel lib --out-dir test/lib --plugins ../test/transform_rpio_sim.js && mocha test/spec.js", 22 | "printcov": "script/printcov.js lib/coverage.lcov lib", 23 | "test-cov": "babel lib --out-dir test/lib --plugins ../test/transform_rpio_sim.js,transform-coverage && mocha test/spec.js --reporter=mocha-lcov-reporter > lib/coverage.lcov && npm run printcov" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/akira-cn/rpio2.git" 28 | }, 29 | "keywords": [ 30 | "rpio", 31 | "bcm2835", 32 | "gpio", 33 | "gpiomem", 34 | "i2c", 35 | "mmap", 36 | "pi", 37 | "pwm", 38 | "raspberry", 39 | "raspberrypi", 40 | "raspberry pi", 41 | "rpi", 42 | "spi" 43 | ], 44 | "author": "akira-cn", 45 | "license": "GPL" 46 | } 47 | -------------------------------------------------------------------------------- /lib/gpio_group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Gpio = require('./gpio.js'); 4 | 5 | function GpioGroup(pins, activeLow){ 6 | this.gpios = pins.map(function(pin){ 7 | return new Gpio(pin, activeLow); 8 | }); 9 | } 10 | 11 | GpioGroup.init = Gpio.init; 12 | require('./gpio_util.js').defineStaticProperties(GpioGroup); 13 | 14 | Object.assign(GpioGroup.prototype, { 15 | open: function(){ 16 | var args = [].slice.call(arguments); 17 | return this.gpios.map(function(gpio){ 18 | return gpio.open.apply(gpio, args); 19 | }); 20 | }, 21 | close: function(){ 22 | var args = [].slice.call(arguments); 23 | return this.gpios.map(function(gpio){ 24 | return gpio.close.apply(gpio, args); 25 | }); 26 | }, 27 | sleep: function(ms){ 28 | return Gpio.prototype.sleep(ms); 29 | } 30 | }); 31 | 32 | Object.defineProperty(GpioGroup.prototype, 'value', { 33 | get: function(){ 34 | var args = [].slice.call(arguments); 35 | var values = this.gpios.map(function(gpio){ 36 | return gpio.value; 37 | }); 38 | return parseInt(values.join(''), 2); 39 | }, 40 | set: function(value){ 41 | var len = this.gpios.length; 42 | var padStr = new Array(len).join('0'); 43 | value = (padStr + value.toString(2)).slice(-len); 44 | var self = this; 45 | 46 | return value.split('').map(function(val, idx){ 47 | var gpio = self.gpios[idx]; 48 | return gpio.value = 0|val; 49 | }); 50 | } 51 | }); 52 | 53 | module.exports = GpioGroup; 54 | -------------------------------------------------------------------------------- /test/lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | global._$jscoverage = global._$jscoverage || {}; 4 | _$jscoverage['index.js'] = []; 5 | _$jscoverage['index.js'][3] = 0; 6 | _$jscoverage['index.js'][9] = 0; 7 | _$jscoverage['index.js'][10] = 0; 8 | _$jscoverage['index.js'][12] = 0; 9 | _$jscoverage['index.js'][13] = 0; 10 | _$jscoverage['index.js'][16] = 0; 11 | _$jscoverage['index.js'][25] = 0; 12 | _$jscoverage['index.js'][27] = 0; 13 | _$jscoverage['index.js'].source = ['\'use strict\';', '', 'const rpio = require(\'rpio\'),', ' Gpio = require(\'./gpio.js\'),', ' GpioGroup = require(\'./gpio_group.js\'),', ' ReadStream = require(\'./read_stream.js\'),', ' WriteStream = require(\'./write_stream.js\');', '', 'Gpio.createReadStream = function(pin, options){', ' return new ReadStream(pin, options);', '}', 'Gpio.createWriteStream = function(pin, options){', ' return new WriteStream(pin, options);', '}', '', 'var rpio2 = {', ' init: rpio.init,', ' rpio: rpio,', ' Gpio: Gpio,', ' ReadStream: ReadStream,', ' WriteStream: WriteStream,', ' GpioGroup: GpioGroup', '}', '', 'require(\'./gpio_util.js\').defineStaticProperties(rpio2);', '', 'module.exports = rpio2;', '']; 14 | _$jscoverage['index.js'][3]++; 15 | const rpio = require('../rpio_sim.js'), 16 | Gpio = require('./gpio.js'), 17 | GpioGroup = require('./gpio_group.js'), 18 | ReadStream = require('./read_stream.js'), 19 | WriteStream = require('./write_stream.js'); 20 | 21 | _$jscoverage['index.js'][9]++; 22 | Gpio.createReadStream = function (pin, options) { 23 | _$jscoverage['index.js'][10]++; 24 | 25 | return new ReadStream(pin, options); 26 | }; 27 | _$jscoverage['index.js'][12]++; 28 | Gpio.createWriteStream = function (pin, options) { 29 | _$jscoverage['index.js'][13]++; 30 | 31 | return new WriteStream(pin, options); 32 | }; 33 | 34 | _$jscoverage['index.js'][16]++; 35 | var rpio2 = { 36 | init: rpio.init, 37 | rpio: rpio, 38 | Gpio: Gpio, 39 | ReadStream: ReadStream, 40 | WriteStream: WriteStream, 41 | GpioGroup: GpioGroup 42 | }; 43 | 44 | _$jscoverage['index.js'][25]++; 45 | require('./gpio_util.js').defineStaticProperties(rpio2); 46 | 47 | _$jscoverage['index.js'][27]++; 48 | module.exports = rpio2; -------------------------------------------------------------------------------- /test/lib/gpio_util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | global._$jscoverage = global._$jscoverage || {}; 4 | _$jscoverage['gpio_util.js'] = []; 5 | _$jscoverage['gpio_util.js'][3] = 0; 6 | _$jscoverage['gpio_util.js'][5] = 0; 7 | _$jscoverage['gpio_util.js'][6] = 0; 8 | _$jscoverage['gpio_util.js'][7] = 0; 9 | _$jscoverage['gpio_util.js'][9] = 0; 10 | _$jscoverage['gpio_util.js'][16] = 0; 11 | _$jscoverage['gpio_util.js'][17] = 0; 12 | _$jscoverage['gpio_util.js'][18] = 0; 13 | _$jscoverage['gpio_util.js'][27] = 0; 14 | _$jscoverage['gpio_util.js'].source = ['\'use strict\';', '', 'const rpio = require(\'rpio\');', '', 'rpio.POLL_NONE = 0;', 'rpio.PULL_DEFAULT = -1;', 'rpio.UNKNOWN = -1;', '', 'const props = [', ' \'UNKNOWN\',\'INPUT\',\'OUTPUT\',', ' \'PULL_OFF\',\'PULL_DOWN\',\'PULL_UP\',\'PULL_DEFAULT\',', ' \'HIGH\',\'LOW\',', ' \'POLL_NONE\',\'POLL_LOW\',\'POLL_HIGH\',\'POLL_BOTH\'', '];', '', 'function defineStaticProperties(obj){', ' props.forEach(function(prop){', ' Object.defineProperty(obj, prop, {', ' value: rpio[prop],', ' writable: false,', ' configurable: false,', ' enumerable: true', ' });', ' });', '}', '', 'module.exports = {', ' defineStaticProperties: defineStaticProperties', '}', '']; 15 | _$jscoverage['gpio_util.js'][3]++; 16 | const rpio = require('../rpio_sim.js'); 17 | 18 | _$jscoverage['gpio_util.js'][5]++; 19 | rpio.POLL_NONE = 0; 20 | _$jscoverage['gpio_util.js'][6]++; 21 | rpio.PULL_DEFAULT = -1; 22 | _$jscoverage['gpio_util.js'][7]++; 23 | rpio.UNKNOWN = -1; 24 | 25 | _$jscoverage['gpio_util.js'][9]++; 26 | const props = ['UNKNOWN', 'INPUT', 'OUTPUT', 'PULL_OFF', 'PULL_DOWN', 'PULL_UP', 'PULL_DEFAULT', 'HIGH', 'LOW', 'POLL_NONE', 'POLL_LOW', 'POLL_HIGH', 'POLL_BOTH']; 27 | 28 | _$jscoverage['gpio_util.js'][16]++; 29 | function defineStaticProperties(obj) { 30 | _$jscoverage['gpio_util.js'][17]++; 31 | 32 | props.forEach(function (prop) { 33 | _$jscoverage['gpio_util.js'][18]++; 34 | 35 | Object.defineProperty(obj, prop, { 36 | value: rpio[prop], 37 | writable: false, 38 | configurable: false, 39 | enumerable: true 40 | }); 41 | }); 42 | } 43 | 44 | _$jscoverage['gpio_util.js'][27]++; 45 | module.exports = { 46 | defineStaticProperties: defineStaticProperties 47 | }; -------------------------------------------------------------------------------- /script/printcov.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | var consoler = require('consoler'); 5 | consoler.add('warning: uncovered code', 'yellow'); 6 | 7 | if(process.argv.length < 3){ 8 | console.log('printcov lcov-file [source-src]'); 9 | process.exit(0); 10 | } 11 | 12 | var lcov = process.argv[2]; 13 | var source = process.argv[3]; 14 | 15 | function percentage(covered, statements){ 16 | var percentage = Math.floor(100 * covered/statements); 17 | var color = 'cyan'; 18 | 19 | if(percentage >= 80 && percentage < 100){ 20 | color = 'magenta'; 21 | }else if(percentage >= 40 && percentage < 80){ 22 | color = 'yellow'; 23 | }else if(percentage < 40){ 24 | color = 'red'; 25 | } 26 | return (percentage + '%')[color]; 27 | } 28 | 29 | function print(){ 30 | var content = fs.readFileSync(lcov, 'utf-8'); 31 | 32 | console.log('Generated test coverages:\n'); 33 | 34 | var total = 0, total_covered = 0; 35 | 36 | if(content){ 37 | var lines = content.split(/\n/g); 38 | 39 | var file = null, covered = 0, statements = 0, 40 | sourceMap = null, linesNotCovered = []; 41 | 42 | lines.forEach((line) => { 43 | var fileBegin = /^SF:(.+)$/.exec(line), 44 | fileEnd = /^end_of_record$/.exec(line), 45 | lineCover = /^DA:(\d+),(\d+)/.exec(line); 46 | 47 | if(fileBegin){ 48 | file = fileBegin[1]; 49 | if(source){ 50 | var sourceFile = require('path').join(source, file); 51 | sourceMap = fs.readFileSync(sourceFile, 'utf-8'); 52 | sourceMap = sourceMap.split(/\n/g); 53 | } 54 | } else if(fileEnd){ 55 | console.log(`${file}: ${percentage(covered, statements)}`); 56 | 57 | if(linesNotCovered.length){ 58 | consoler('warning: uncovered code', linesNotCovered.map((l) => `\tline ${l}: ${sourceMap[l-1]}`).join('\n').red); 59 | } 60 | 61 | total += statements; 62 | total_covered += covered; 63 | 64 | file = null; 65 | covered = 0; 66 | statements = 0; 67 | sourceMap = null; 68 | linesNotCovered = []; 69 | } else if(lineCover){ 70 | var n = lineCover[2]|0; 71 | var l = lineCover[1]|0; 72 | 73 | if(n > 0){ 74 | covered++; 75 | }else{ 76 | if(sourceMap){ 77 | linesNotCovered.push(l); 78 | } 79 | } 80 | statements++; 81 | } 82 | }); 83 | } 84 | console.log(`\ntotal: ${percentage(total_covered, total)}\n`); 85 | } 86 | 87 | print(); 88 | -------------------------------------------------------------------------------- /test/lib/write_stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | global._$jscoverage = global._$jscoverage || {}; 4 | _$jscoverage["write_stream.js"] = []; 5 | _$jscoverage["write_stream.js"][3] = 0; 6 | _$jscoverage["write_stream.js"][4] = 0; 7 | _$jscoverage["write_stream.js"][6] = 0; 8 | _$jscoverage["write_stream.js"][8] = 0; 9 | _$jscoverage["write_stream.js"][9] = 0; 10 | _$jscoverage["write_stream.js"][13] = 0; 11 | _$jscoverage["write_stream.js"][14] = 0; 12 | _$jscoverage["write_stream.js"][15] = 0; 13 | _$jscoverage["write_stream.js"][16] = 0; 14 | _$jscoverage["write_stream.js"][19] = 0; 15 | _$jscoverage["write_stream.js"][20] = 0; 16 | _$jscoverage["write_stream.js"][23] = 0; 17 | _$jscoverage["write_stream.js"][25] = 0; 18 | _$jscoverage["write_stream.js"][26] = 0; 19 | _$jscoverage["write_stream.js"][27] = 0; 20 | _$jscoverage["write_stream.js"][30] = 0; 21 | _$jscoverage["write_stream.js"][31] = 0; 22 | _$jscoverage["write_stream.js"][32] = 0; 23 | _$jscoverage["write_stream.js"][35] = 0; 24 | _$jscoverage["write_stream.js"].source = ["'use strict';", "", "var Writable = require(\"stream\").Writable;", "var inherits = require(\"util\").inherits;", "", "var Gpio = require(\"./gpio.js\");", "", "function WriteStream(gpio, options) {", " options = Object.assign({", " mode: Gpio.OUTPUT", " }, options);", "", " if(typeof gpio === 'number'){", " gpio = new Gpio(gpio);", " gpio.open(options.mode, options.state);", " this._autoClose = true;", " }", "", " Writable.call(this, options);", " this.gpio = gpio;", "}", "", "inherits(WriteStream, Writable)", "", "WriteStream.prototype._write = function (chunk, encoding, callback) {", " this.gpio.write(chunk);", " callback();", "}", "", "WriteStream.prototype.end = function(){", " if(this._autoClose) this.gpio.close();", " Writable.prototype.end.call(this);", "}", "", "module.exports = WriteStream;", ""]; 25 | _$jscoverage["write_stream.js"][3]++; 26 | var Writable = require("stream").Writable; 27 | _$jscoverage["write_stream.js"][4]++; 28 | var inherits = require("util").inherits; 29 | 30 | _$jscoverage["write_stream.js"][6]++; 31 | var Gpio = require("./gpio.js"); 32 | 33 | _$jscoverage["write_stream.js"][8]++; 34 | function WriteStream(gpio, options) { 35 | _$jscoverage["write_stream.js"][9]++; 36 | 37 | options = Object.assign({ 38 | mode: Gpio.OUTPUT 39 | }, options); 40 | 41 | _$jscoverage["write_stream.js"][13]++; 42 | if (typeof gpio === 'number') { 43 | _$jscoverage["write_stream.js"][14]++; 44 | 45 | gpio = new Gpio(gpio); 46 | _$jscoverage["write_stream.js"][15]++; 47 | gpio.open(options.mode, options.state); 48 | _$jscoverage["write_stream.js"][16]++; 49 | this._autoClose = true; 50 | } 51 | 52 | _$jscoverage["write_stream.js"][19]++; 53 | Writable.call(this, options); 54 | _$jscoverage["write_stream.js"][20]++; 55 | this.gpio = gpio; 56 | } 57 | 58 | _$jscoverage["write_stream.js"][23]++; 59 | inherits(WriteStream, Writable); 60 | 61 | _$jscoverage["write_stream.js"][25]++; 62 | WriteStream.prototype._write = function (chunk, encoding, callback) { 63 | _$jscoverage["write_stream.js"][26]++; 64 | 65 | this.gpio.write(chunk); 66 | _$jscoverage["write_stream.js"][27]++; 67 | callback(); 68 | }; 69 | 70 | _$jscoverage["write_stream.js"][30]++; 71 | WriteStream.prototype.end = function () { 72 | if (this._autoClose) { 73 | _$jscoverage["write_stream.js"][31]++; 74 | this.gpio.close(); 75 | }_$jscoverage["write_stream.js"][32]++; 76 | Writable.prototype.end.call(this); 77 | }; 78 | 79 | _$jscoverage["write_stream.js"][35]++; 80 | module.exports = WriteStream; -------------------------------------------------------------------------------- /test/lib/read_stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | global._$jscoverage = global._$jscoverage || {}; 4 | _$jscoverage["read_stream.js"] = []; 5 | _$jscoverage["read_stream.js"][3] = 0; 6 | _$jscoverage["read_stream.js"][4] = 0; 7 | _$jscoverage["read_stream.js"][6] = 0; 8 | _$jscoverage["read_stream.js"][8] = 0; 9 | _$jscoverage["read_stream.js"][9] = 0; 10 | _$jscoverage["read_stream.js"][13] = 0; 11 | _$jscoverage["read_stream.js"][14] = 0; 12 | _$jscoverage["read_stream.js"][15] = 0; 13 | _$jscoverage["read_stream.js"][16] = 0; 14 | _$jscoverage["read_stream.js"][19] = 0; 15 | _$jscoverage["read_stream.js"][20] = 0; 16 | _$jscoverage["read_stream.js"][21] = 0; 17 | _$jscoverage["read_stream.js"][24] = 0; 18 | _$jscoverage["read_stream.js"][25] = 0; 19 | _$jscoverage["read_stream.js"][28] = 0; 20 | _$jscoverage["read_stream.js"][30] = 0; 21 | _$jscoverage["read_stream.js"][31] = 0; 22 | _$jscoverage["read_stream.js"][32] = 0; 23 | _$jscoverage["read_stream.js"][33] = 0; 24 | _$jscoverage["read_stream.js"][34] = 0; 25 | _$jscoverage["read_stream.js"][35] = 0; 26 | _$jscoverage["read_stream.js"][36] = 0; 27 | _$jscoverage["read_stream.js"][37] = 0; 28 | _$jscoverage["read_stream.js"][38] = 0; 29 | _$jscoverage["read_stream.js"][39] = 0; 30 | _$jscoverage["read_stream.js"][44] = 0; 31 | _$jscoverage["read_stream.js"][45] = 0; 32 | _$jscoverage["read_stream.js"][46] = 0; 33 | _$jscoverage["read_stream.js"][49] = 0; 34 | _$jscoverage["read_stream.js"].source = ["'use strict';", "", "const Readable = require(\"stream\").Readable;", "const inherits = require(\"util\").inherits;", "", "const Gpio = require('./gpio.js');", "", "function ReadStream(gpio, options){", " options = Object.assign({", " mode: Gpio.INPUT", " }, options);", "", " if(typeof gpio === 'number'){", " gpio = new Gpio(gpio);", " gpio.open(options.mode, options.state);", " this._autoClose = true;", " }", "", " if(options && options.throttle){", " this.throttle = options.throttle;", " this.timer = null;", " }", "", " Readable.call(this, options);", " this.gpio = gpio;", "}", "", "inherits(ReadStream, Readable);", "", "ReadStream.prototype._read = function (size) {", " if(!this.throttle){", " var buf = this.gpio.read(size);", " this.push(buf.join(''));", " }else if(!this.timer){", " var self = this;", " this.timer = setTimeout(function(){", " self.timer = null;", " self.push(self.gpio.value.toString());", " self.read(0);", " }, this.throttle);", " }", "}", "", "ReadStream.prototype.end = function(){", " if(this._autoClose) this.gpio.close();", " this.emit('end');", "}", "", "module.exports = ReadStream;", ""]; 35 | _$jscoverage["read_stream.js"][3]++; 36 | const Readable = require("stream").Readable; 37 | _$jscoverage["read_stream.js"][4]++; 38 | const inherits = require("util").inherits; 39 | 40 | _$jscoverage["read_stream.js"][6]++; 41 | const Gpio = require('./gpio.js'); 42 | 43 | _$jscoverage["read_stream.js"][8]++; 44 | function ReadStream(gpio, options) { 45 | _$jscoverage["read_stream.js"][9]++; 46 | 47 | options = Object.assign({ 48 | mode: Gpio.INPUT 49 | }, options); 50 | 51 | _$jscoverage["read_stream.js"][13]++; 52 | if (typeof gpio === 'number') { 53 | _$jscoverage["read_stream.js"][14]++; 54 | 55 | gpio = new Gpio(gpio); 56 | _$jscoverage["read_stream.js"][15]++; 57 | gpio.open(options.mode, options.state); 58 | _$jscoverage["read_stream.js"][16]++; 59 | this._autoClose = true; 60 | } 61 | 62 | _$jscoverage["read_stream.js"][19]++; 63 | if (options && options.throttle) { 64 | _$jscoverage["read_stream.js"][20]++; 65 | 66 | this.throttle = options.throttle; 67 | _$jscoverage["read_stream.js"][21]++; 68 | this.timer = null; 69 | } 70 | 71 | _$jscoverage["read_stream.js"][24]++; 72 | Readable.call(this, options); 73 | _$jscoverage["read_stream.js"][25]++; 74 | this.gpio = gpio; 75 | } 76 | 77 | _$jscoverage["read_stream.js"][28]++; 78 | inherits(ReadStream, Readable); 79 | 80 | _$jscoverage["read_stream.js"][30]++; 81 | ReadStream.prototype._read = function (size) { 82 | _$jscoverage["read_stream.js"][31]++; 83 | 84 | if (!this.throttle) { 85 | _$jscoverage["read_stream.js"][32]++; 86 | 87 | var buf = this.gpio.read(size); 88 | _$jscoverage["read_stream.js"][33]++; 89 | this.push(buf.join('')); 90 | } else { 91 | _$jscoverage["read_stream.js"][34]++; 92 | if (!this.timer) { 93 | _$jscoverage["read_stream.js"][35]++; 94 | 95 | var self = this; 96 | _$jscoverage["read_stream.js"][36]++; 97 | this.timer = setTimeout(function () { 98 | _$jscoverage["read_stream.js"][37]++; 99 | 100 | self.timer = null; 101 | _$jscoverage["read_stream.js"][38]++; 102 | self.push(self.gpio.value.toString()); 103 | _$jscoverage["read_stream.js"][39]++; 104 | self.read(0); 105 | }, this.throttle); 106 | } 107 | } 108 | }; 109 | 110 | _$jscoverage["read_stream.js"][44]++; 111 | ReadStream.prototype.end = function () { 112 | if (this._autoClose) { 113 | _$jscoverage["read_stream.js"][45]++; 114 | this.gpio.close(); 115 | }_$jscoverage["read_stream.js"][46]++; 116 | this.emit('end'); 117 | }; 118 | 119 | _$jscoverage["read_stream.js"][49]++; 120 | module.exports = ReadStream; -------------------------------------------------------------------------------- /test/spec.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const rpio2 = require('./lib/index'); 3 | const cluster = require('cluster'); 4 | const wait = require('wait-promise'); 5 | 6 | describe('rpio2 tests', function(){ 7 | this.timeout(10000); 8 | var rpio = rpio2.rpio; 9 | var Gpio = rpio2.Gpio; 10 | 11 | describe('rpio tests', function(){ 12 | it('test rpio sim', function(){ 13 | 14 | //console.log(rpio2.rpio); 15 | var gpio = rpio.open(40, rpio.INPUT); 16 | expect(rpio.read(40)).to.equal(0); 17 | gpio = rpio.open(3, rpio.INPUT); 18 | expect(rpio.read(3)).to.equal(1); 19 | var foo = function(){ 20 | rpio.write(3, 0); 21 | }; 22 | expect(foo).to.throw(Error); 23 | rpio.close(3); 24 | 25 | var gpio = rpio.open(3, rpio.OUTPUT); 26 | expect(rpio.read(3)).to.equal(0); 27 | rpio.write(3, 1); 28 | expect(rpio.read(3)).to.equal(1); 29 | rpio.close(3); 30 | 31 | //simulate input signals 32 | rpio.helper(40, [1,200,0]).then( 33 | function(res){ 34 | expect(rpio.read(40)).to.equal(0); 35 | }); 36 | 37 | return wait.after(1000).and(function(){ 38 | rpio.close(40); 39 | }).check(()=>true); 40 | }); 41 | 42 | it('test rpio sim 2', function(){ 43 | var gpio = rpio.open(40, rpio.INPUT); 44 | expect(()=>rpio.write(40,0)).to.throw(Error); 45 | rpio.mode(40, rpio.OUTPUT); 46 | rpio.write(40, 1) 47 | expect(rpio.read(40)).to.equal(1); 48 | rpio.close(40); 49 | }); 50 | 51 | it('test rpio sim 3', function(cb){ 52 | rpio.open(32, rpio.INPUT); 53 | 54 | rpio.poll(32, function(pin){ 55 | //console.log('changed:' + pin); 56 | expect(rpio.read(pin)).to.equal(1); 57 | }, rpio.POLL_BOTH); 58 | 59 | rpio.helper(32, [0,100,1]).then(function(res){ 60 | rpio.close(32); 61 | cb(); 62 | }).catch(err=>console.log(err)); 63 | }); 64 | 65 | it('test rpio sim 4', function(){ 66 | var t = Date.now(); 67 | rpio.msleep(500); 68 | expect(Date.now() - t).to.be.above(499); 69 | }); 70 | 71 | it('test rpio sim 5', function(){ 72 | var gpio = rpio.open(40, rpio.OUTPUT); 73 | var buff = new Buffer(10); 74 | rpio.readbuf(40, buff); 75 | expect(buff.join('')).to.equal('0000000000'); 76 | buff[4] = 1; 77 | rpio.writebuf(40, buff, 5); 78 | expect(rpio.read(40)).to.equal(1); 79 | rpio.close(40); 80 | }); 81 | }); 82 | 83 | describe('Gpio tests', function(){ 84 | it('sync toggle', function(){ 85 | const gpio = new Gpio(40); 86 | 87 | gpio.open(Gpio.OUTPUT, Gpio.LOW); 88 | 89 | for(var i = 0; i < 10; i++){ 90 | gpio.sleep(50); 91 | expect(i % 2).to.equal(gpio.value); 92 | gpio.toggle(); 93 | } 94 | 95 | gpio.close(); 96 | }); 97 | it('async toggle', function(done){ 98 | const gpio = new Gpio(40); 99 | 100 | gpio.open(Gpio.OUTPUT, Gpio.LOW); 101 | 102 | var i = 0; 103 | 104 | void function loop(){ 105 | Promise.resolve(gpio.toggle()) 106 | .then(gpio.sleep.bind(null, 50, true)) 107 | .then(function(){ 108 | expect(i % 2).to.equal(1 ^ gpio.value); 109 | if(i++ < 10) loop(); 110 | else { 111 | gpio.close(); 112 | done(); 113 | } 114 | }) 115 | }(); 116 | }); 117 | it('async toggle 2', function(done){ 118 | var gpio = new Gpio(40); 119 | gpio.open(Gpio.OUTPUT); 120 | 121 | wait.every(50).limit(10).and(function(i){ 122 | expect(i % 2).to.equal(gpio.value); 123 | gpio.toggle(); 124 | 125 | }).forward().catch(function(){ 126 | gpio.close(40); 127 | done(); 128 | }); 129 | }); 130 | 131 | it('read pin', function(done){ 132 | var input = new Gpio(40); 133 | input.open(Gpio.INPUT); 134 | 135 | var values = []; 136 | 137 | rpio.helper(40, [0,100,1,100,0,100,1,100,0,100,1,100,0,100,1]) 138 | .then(function(){ 139 | expect(values.join('')).to.equal('01010'); 140 | input.close(); 141 | done(); 142 | }); 143 | 144 | wait.after(90).every(100).limit(5).and(function(){ 145 | values.push(input.value) 146 | }).forward(); 147 | }); 148 | 149 | it('events', function(done){ 150 | var input = new Gpio(32); 151 | input.open(Gpio.INPUT); 152 | 153 | setTimeout(function(){ 154 | rpio.helper(32, [0, 100,1,100,0,100,1,100,0]) 155 | .then(function(){ 156 | expect(rCount).to.equal(2); 157 | expect(fCount).to.equal(2); 158 | input.close(); 159 | done(); 160 | }).catch(err=>console.log(err)); 161 | }, 200); 162 | 163 | var rCount = 0, fCount = 0; 164 | input.on('rising', function(pin){ 165 | //console.log('rising', input.value); 166 | expect(pin.value).to.equal(1); 167 | rCount++; 168 | }); 169 | 170 | input.on('falling', function(pin){ 171 | //console.log('falling', input.value); 172 | expect(pin.value).to.equal(0); 173 | fCount++; 174 | }); 175 | }); 176 | 177 | }); 178 | }); -------------------------------------------------------------------------------- /test/lib/gpio_group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | global._$jscoverage = global._$jscoverage || {}; 4 | _$jscoverage['gpio_group.js'] = []; 5 | _$jscoverage['gpio_group.js'][3] = 0; 6 | _$jscoverage['gpio_group.js'][5] = 0; 7 | _$jscoverage['gpio_group.js'][6] = 0; 8 | _$jscoverage['gpio_group.js'][7] = 0; 9 | _$jscoverage['gpio_group.js'][11] = 0; 10 | _$jscoverage['gpio_group.js'][12] = 0; 11 | _$jscoverage['gpio_group.js'][14] = 0; 12 | _$jscoverage['gpio_group.js'][16] = 0; 13 | _$jscoverage['gpio_group.js'][17] = 0; 14 | _$jscoverage['gpio_group.js'][18] = 0; 15 | _$jscoverage['gpio_group.js'][22] = 0; 16 | _$jscoverage['gpio_group.js'][23] = 0; 17 | _$jscoverage['gpio_group.js'][24] = 0; 18 | _$jscoverage['gpio_group.js'][28] = 0; 19 | _$jscoverage['gpio_group.js'][32] = 0; 20 | _$jscoverage['gpio_group.js'][34] = 0; 21 | _$jscoverage['gpio_group.js'][35] = 0; 22 | _$jscoverage['gpio_group.js'][36] = 0; 23 | _$jscoverage['gpio_group.js'][38] = 0; 24 | _$jscoverage['gpio_group.js'][41] = 0; 25 | _$jscoverage['gpio_group.js'][42] = 0; 26 | _$jscoverage['gpio_group.js'][43] = 0; 27 | _$jscoverage['gpio_group.js'][44] = 0; 28 | _$jscoverage['gpio_group.js'][46] = 0; 29 | _$jscoverage['gpio_group.js'][47] = 0; 30 | _$jscoverage['gpio_group.js'][48] = 0; 31 | _$jscoverage['gpio_group.js'][53] = 0; 32 | _$jscoverage['gpio_group.js'].source = ['\'use strict\';', '', 'const Gpio = require(\'./gpio.js\');', '', 'function GpioGroup(pins, activeLow){', ' this.gpios = pins.map(function(pin){', ' return new Gpio(pin, activeLow);', ' });', '}', '', 'GpioGroup.init = Gpio.init;', 'require(\'./gpio_util.js\').defineStaticProperties(GpioGroup);', '', 'Object.assign(GpioGroup.prototype, {', ' open: function(){', ' var args = [].slice.call(arguments);', ' return this.gpios.map(function(gpio){', ' return gpio.open.apply(gpio, args);', ' });', ' },', ' close: function(){', ' var args = [].slice.call(arguments);', ' return this.gpios.map(function(gpio){', ' return gpio.close.apply(gpio, args);', ' }); ', ' },', ' sleep: function(ms){', ' return Gpio.prototype.sleep(ms);', ' }', '});', '', 'Object.defineProperty(GpioGroup.prototype, \'value\', {', ' get: function(){', ' var args = [].slice.call(arguments);', ' var values = this.gpios.map(function(gpio){', ' return gpio.value;', ' });', ' return parseInt(values.join(\'\'), 2);', ' },', ' set: function(value){', ' var len = this.gpios.length;', ' var padStr = new Array(len).join(\'0\');', ' value = (padStr + value.toString(2)).slice(-len);', ' var self = this;', '', ' return value.split(\'\').map(function(val, idx){', ' var gpio = self.gpios[idx];', ' return gpio.value = 0|val;', ' });', ' }', '});', '', 'module.exports = GpioGroup;', '']; 33 | _$jscoverage['gpio_group.js'][3]++; 34 | const Gpio = require('./gpio.js'); 35 | 36 | _$jscoverage['gpio_group.js'][5]++; 37 | function GpioGroup(pins, activeLow) { 38 | _$jscoverage['gpio_group.js'][6]++; 39 | 40 | this.gpios = pins.map(function (pin) { 41 | _$jscoverage['gpio_group.js'][7]++; 42 | 43 | return new Gpio(pin, activeLow); 44 | }); 45 | } 46 | 47 | _$jscoverage['gpio_group.js'][11]++; 48 | GpioGroup.init = Gpio.init; 49 | _$jscoverage['gpio_group.js'][12]++; 50 | require('./gpio_util.js').defineStaticProperties(GpioGroup); 51 | 52 | _$jscoverage['gpio_group.js'][14]++; 53 | Object.assign(GpioGroup.prototype, { 54 | open: function () { 55 | _$jscoverage['gpio_group.js'][16]++; 56 | 57 | var args = [].slice.call(arguments); 58 | _$jscoverage['gpio_group.js'][17]++; 59 | return this.gpios.map(function (gpio) { 60 | _$jscoverage['gpio_group.js'][18]++; 61 | 62 | return gpio.open.apply(gpio, args); 63 | }); 64 | }, 65 | close: function () { 66 | _$jscoverage['gpio_group.js'][22]++; 67 | 68 | var args = [].slice.call(arguments); 69 | _$jscoverage['gpio_group.js'][23]++; 70 | return this.gpios.map(function (gpio) { 71 | _$jscoverage['gpio_group.js'][24]++; 72 | 73 | return gpio.close.apply(gpio, args); 74 | }); 75 | }, 76 | sleep: function (ms) { 77 | _$jscoverage['gpio_group.js'][28]++; 78 | 79 | return Gpio.prototype.sleep(ms); 80 | } 81 | }); 82 | 83 | _$jscoverage['gpio_group.js'][32]++; 84 | Object.defineProperty(GpioGroup.prototype, 'value', { 85 | get: function () { 86 | _$jscoverage['gpio_group.js'][34]++; 87 | 88 | var args = [].slice.call(arguments); 89 | _$jscoverage['gpio_group.js'][35]++; 90 | var values = this.gpios.map(function (gpio) { 91 | _$jscoverage['gpio_group.js'][36]++; 92 | 93 | return gpio.value; 94 | }); 95 | _$jscoverage['gpio_group.js'][38]++; 96 | return parseInt(values.join(''), 2); 97 | }, 98 | set: function (value) { 99 | _$jscoverage['gpio_group.js'][41]++; 100 | 101 | var len = this.gpios.length; 102 | _$jscoverage['gpio_group.js'][42]++; 103 | var padStr = new Array(len).join('0'); 104 | _$jscoverage['gpio_group.js'][43]++; 105 | value = (padStr + value.toString(2)).slice(-len); 106 | _$jscoverage['gpio_group.js'][44]++; 107 | var self = this; 108 | 109 | _$jscoverage['gpio_group.js'][46]++; 110 | return value.split('').map(function (val, idx) { 111 | _$jscoverage['gpio_group.js'][47]++; 112 | 113 | var gpio = self.gpios[idx]; 114 | _$jscoverage['gpio_group.js'][48]++; 115 | return gpio.value = 0 | val; 116 | }); 117 | } 118 | }); 119 | 120 | _$jscoverage['gpio_group.js'][53]++; 121 | module.exports = GpioGroup; -------------------------------------------------------------------------------- /test/rpio_sim.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const child_process = require('child_process'); 4 | 5 | var pinMap = { 6 | 3: 2, 7 | 5: 3, 8 | 7: 4, 9 | 8: 14, 10 | 10: 15, 11 | 11: 17, 12 | 12: 18, 13 | 13: 27, 14 | 15: 22, 15 | 16: 23, 16 | 18: 24, 17 | 19: 10, 18 | 21: 9, 19 | 22: 25, 20 | 23: 11, 21 | 24: 8, 22 | 26: 7, 23 | 29: 5, 24 | 31: 6, 25 | 32: 12, 26 | 33: 13, 27 | 35: 19, 28 | 36: 16, 29 | 37: 26, 30 | 38: 20, 31 | 40: 21 32 | }; 33 | 34 | var config = { 35 | mapping : 'physical' 36 | }; 37 | 38 | var gpios = { 39 | 40 | }; 41 | 42 | var fs = require('fs'); 43 | var chokidar = require('chokidar'); 44 | 45 | module.exports = { 46 | helper: function (pin, signal){ 47 | if(config.mapping === 'physical'){ 48 | pin = pinMap[pin]; 49 | } 50 | return new Promise(function(resolve, reject){ 51 | child_process.exec('node ./test/rpio_sim_helper ' + pin + ' ' + signal, 52 | function(err, res){ 53 | if(err) reject(err); 54 | else resolve(res); 55 | }); 56 | }); 57 | }, 58 | //constants 59 | UNKNOWN: -1, 60 | HIGH : 1, 61 | LOW : 0, 62 | INPUT : 0, 63 | OUTPUT : 1, 64 | PULL_OFF : 0, 65 | PULL_DOWN : 1, 66 | PULL_UP : 2, 67 | PULL_DEFAULT : -1, 68 | POLL_NONE : 0, 69 | POLL_LOW : 1, 70 | POLL_HIGH : 2, 71 | POLL_BOTH : 3, 72 | init: function(options){ 73 | config.mapping = options.mapping || 'physical'; 74 | }, 75 | open: function(pin, mode, state, debug){ 76 | if(debug){ 77 | console.log(pin, mode, state); 78 | } 79 | if(config.mapping === 'physical'){ 80 | pin = pinMap[pin]; 81 | } 82 | if(!pin){ 83 | console.error('no such pin.'); 84 | return; 85 | } 86 | 87 | var gpio = { 88 | mode: mode, 89 | state: state || this.PULL_DEFAULT 90 | }; 91 | 92 | var file = './test/gpio/gpio' + pin; 93 | 94 | Object.defineProperty(gpio, 'value', { 95 | get: function(){ 96 | return fs.readFileSync(file)[0]; 97 | }, 98 | set: function(value){ 99 | fs.writeFileSync(file, new Buffer([value])); 100 | } 101 | }); 102 | 103 | if(mode === this.INPUT){ 104 | if(gpio.state === this.PULL_DEFAULT 105 | || gpio.state === this.PULL_OFF){ 106 | gpio.value = pin <= 8 ? 1 : 0; 107 | }else{ 108 | gpio.value = gpio.state === this.PULL_UP ? 1 : 0; 109 | } 110 | }else{ 111 | gpio.value = state; 112 | } 113 | 114 | gpios[pin] = gpio; 115 | 116 | return gpio; 117 | }, 118 | close: function(pin){ 119 | if(config.mapping === 'physical'){ 120 | pin = pinMap[pin]; 121 | } 122 | if(!pin){ 123 | console.error('no such pin.'); 124 | return; 125 | } 126 | var gpio = gpios[pin]; 127 | var file = './test/gpio/gpio' + pin; 128 | if(gpio.watcher){ 129 | gpio.watcher.unwatch(file); 130 | gpio.watcher.close(); 131 | delete gpio.watcher; 132 | } 133 | fs.unlinkSync(file); 134 | delete gpios[pin]; 135 | }, 136 | read: function(pin){ 137 | if(config.mapping === 'physical'){ 138 | pin = pinMap[pin]; 139 | } 140 | var gpio = gpios[pin]; 141 | if(!pin || !gpios){ 142 | console.error('the pin not avaliable!'); 143 | return; 144 | } 145 | return gpio.value; 146 | }, 147 | write: function(pin, value){ 148 | if(config.mapping === 'physical'){ 149 | pin = pinMap[pin]; 150 | } 151 | var gpio = gpios[pin]; 152 | if(gpio.mode === this.INPUT){ 153 | throw new Error('input pin is readonly.'); 154 | } 155 | gpio.value = value; 156 | }, 157 | readbuf: function(pin, buf, length){ 158 | length = length || buf.length; 159 | for(var i = 0; i < length && i < buf.length; i++){ 160 | buf[i] = this.read(pin); 161 | } 162 | return buf[i]; 163 | }, 164 | writebuf: function(pin, buf, length){ 165 | length = length || buf.length; 166 | for(var i = 0; i < length && i < buf.length; i++){ 167 | this.write(pin, buf[i]); 168 | } 169 | }, 170 | poll: function(pin, cb, direction){ 171 | direction = direction || this.POLL_NONE; 172 | var gpioPin = pin; 173 | if(config.mapping === 'physical'){ 174 | gpioPin = pinMap[pin]; 175 | } 176 | var gpio = gpios[gpioPin]; 177 | if(gpio.mode === this.OUTPUT){ 178 | throw new Error('cannot listening a output pin'); 179 | } 180 | 181 | direction = direction || this.POLL_NONE; 182 | var file = './test/gpio/gpio' + gpioPin; 183 | 184 | if(cb){ 185 | //console.log('add watcher', file, direction); 186 | var self = this; 187 | gpio.watcher = chokidar.watch(file); 188 | 189 | gpio.watcher.on('change', function(path){ 190 | if(gpio.watchedValue == null){ 191 | gpio.watchedValue = gpio.value; //first created 192 | return; 193 | }else if(gpio.watchedValue === gpio.value){ 194 | return; 195 | } 196 | gpio.watchedValue = gpio.value; 197 | //console.log('trigger watcher', direction); 198 | if(gpio.value == 1 && (direction === self.POLL_HIGH || direction === self.POLL_BOTH)){ 199 | cb(pin); 200 | } 201 | if(gpio.value == 0 && (direction === self.POLL_LOW || direction === self.POLL_BOTH)){ 202 | cb(pin); 203 | } 204 | }); 205 | }else{ 206 | if(gpio.watcher){ 207 | gpio.watcher.unwatch(file); 208 | gpio.watcher.close(); 209 | //console.log('remove watcher', file); 210 | delete gpio.watcher; 211 | } 212 | } 213 | }, 214 | msleep: function(ms){ 215 | var t = Date.now(); 216 | while(Date.now() - t < ms); 217 | }, 218 | mode: function(pin, mode){ 219 | if(config.mapping === 'physical'){ 220 | pin = pinMap[pin]; 221 | } 222 | var gpio = gpios[pin]; 223 | gpio.mode = mode; 224 | }, 225 | pud: function(pin, state){ 226 | if(config.mapping === 'physical'){ 227 | pin = pinMap[pin]; 228 | } 229 | var gpio = gpios[pin]; 230 | gpio.state = state; 231 | } 232 | }; 233 | -------------------------------------------------------------------------------- /lib/gpio.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const rpio = require('rpio'), 4 | util = require('util'), 5 | EventEmitter = require('events').EventEmitter; 6 | 7 | function updateEdge(gpio, type){ 8 | var changes = gpio.listeners('change').length, 9 | risings = gpio.listeners('rising').length, 10 | fallings = gpio.listeners('falling').length; 11 | 12 | var edge = gpio.edge; 13 | 14 | function triggerEvent(pin){ 15 | gpio.emit('change', gpio, pin); 16 | if(gpio.value) gpio.emit('rising', gpio, pin); 17 | else gpio.emit('falling', gpio, pin); 18 | } 19 | 20 | if(type === 'change'){ 21 | changes ++; 22 | }else if(type === 'rising'){ 23 | risings ++; 24 | }else if(type === 'falling'){ 25 | fallings ++; 26 | } 27 | 28 | if(changes > 0 || 29 | risings > 0 && fallings > 0){ 30 | if(edge !== rpio.POLL_BOTH){ 31 | gpio.edge = rpio.POLL_BOTH; 32 | if(edge !== rpio.POLL_NONE){ 33 | rpio.poll(gpio.pin, null); 34 | } 35 | rpio.poll(gpio.pin, triggerEvent, rpio.POLL_BOTH); 36 | } 37 | }else if(risings > 0){ 38 | if(edge !== rpio.POLL_HIGH){ 39 | gpio.edge = rpio.POLL_HIGH; 40 | if(edge !== rpio.POLL_NONE){ 41 | rpio.poll(gpio.pin, null); 42 | } 43 | rpio.poll(gpio.pin, triggerEvent, rpio.POLL_HIGH); 44 | } 45 | }else if(fallings > 0){ 46 | if(edge !== rpio.POLL_LOW){ 47 | gpio.edge = rpio.POLL_LOW; 48 | if(edge !== rpio.POLL_NONE){ 49 | rpio.poll(gpio.pin, null); 50 | } 51 | rpio.poll(gpio.pin, triggerEvent, rpio.POLL_LOW); 52 | } 53 | }else{ 54 | if(edge !== rpio.POLL_NONE){ 55 | rpio.poll(gpio.pin, null); 56 | } 57 | gpio.edge = rpio.POLL_NONE; 58 | } 59 | } 60 | 61 | function Gpio(pin, activeLow){ 62 | this.pin = pin; 63 | this.edge = rpio.POLL_NONE; 64 | this.activeLow = !!activeLow; 65 | 66 | this.on('removeListener', function(type){ 67 | updateEdge(this); 68 | }); 69 | 70 | this.on('newListener', function(type){ 71 | updateEdge(this, type); 72 | }); 73 | 74 | //private properties 75 | var mode = -1; 76 | Object.defineProperty(this, '_mode', { 77 | get: function(){ 78 | return mode; 79 | }, 80 | set: function(value){ 81 | mode = value; 82 | }, 83 | enumerable: false 84 | }); 85 | 86 | //input state POLL_HIGH POLL_ROW resistors 87 | var state = -1; 88 | Object.defineProperty(this, '_state', { 89 | get: function(){ 90 | return state; 91 | }, 92 | set: function(value){ 93 | state = value; 94 | }, 95 | enumerable: false 96 | }); 97 | } 98 | 99 | util.inherits(Gpio, EventEmitter); 100 | 101 | Gpio.init = rpio.init; 102 | require('./gpio_util.js').defineStaticProperties(Gpio); 103 | 104 | Object.assign(Gpio.prototype, { 105 | open: function(mode, value){ 106 | this._mode = mode; 107 | if(mode === rpio.INPUT && value !== undefined){ 108 | this._state = value; 109 | } 110 | if(mode === rpio.OUTPUT){ 111 | return rpio.open(this.pin, mode, this.activeLow ^ value); 112 | }else{ 113 | return rpio.open(this.pin, mode, value); 114 | } 115 | }, 116 | close: function(){ 117 | this.removeAllListeners(); 118 | this._mode = this._state = -1; 119 | return rpio.close(this.pin); 120 | }, 121 | read: function(length){ 122 | if(length === undefined){ 123 | return this.value; 124 | }else{ 125 | var buf = new Buffer(length); 126 | rpio.readbuf(this.pin, buf, length); 127 | 128 | if(this.activeLow){ 129 | for(var i = 0; i < buf.length; i++){ 130 | buf[i] ^= 1; 131 | } 132 | } 133 | 134 | return buf; 135 | } 136 | }, 137 | write: function(buf, length){ 138 | 139 | var self = this; 140 | 141 | function writeData(){ 142 | if(self.activeLow){ 143 | var newBuf = new Buffer(length || buf.length); 144 | for(var i = 0; i < newBuf.length; i++){ 145 | newBuf[i] = 1 ^ buf[i]; 146 | } 147 | return rpio.writebuf(self.pin, newBuf, length); 148 | }else{ 149 | return rpio.writebuf(self.pin, buf, length); 150 | } 151 | } 152 | 153 | if(length === undefined && buf === 0 || buf === 1){ 154 | //gpio.write(1) 155 | this.value = buf; 156 | return; 157 | }else if(typeof buf === 'string'){ 158 | //gpio.write('1010101') 159 | buf = new Buffer(buf.trim().split('').map(function(i){return 0|i})); 160 | return writeData(); 161 | }else if(typeof buf === 'number'){ 162 | //gpio.write(0b10101010); 163 | return this.write(buf.toString(2), length); 164 | }else if(buf instanceof Buffer){ 165 | if(buf[0] !== 0 && buf[0] !== 1){ 166 | //Buffer<'0','1','0','1'...> 167 | return this.write(buf.toString(), length); 168 | }else{ 169 | //Buffer<00,01,00,01...> 170 | return writeData(); 171 | } 172 | } 173 | }, 174 | sleep: function(ms, async){ 175 | if(!async){ 176 | return rpio.msleep(ms); 177 | } 178 | return new Promise(function(resolve){ 179 | setTimeout(resolve, ms); 180 | }); 181 | }, 182 | toggle: function(){ 183 | this.value ^= 1; 184 | return this.value; 185 | } 186 | }); 187 | 188 | Object.defineProperty(Gpio.prototype, 'value', { 189 | get: function(){ 190 | return this.activeLow ^ rpio.read(this.pin); 191 | }, 192 | set: function(value){ 193 | rpio.write(this.pin, this.activeLow ^ value); 194 | } 195 | }); 196 | 197 | Object.defineProperty(Gpio.prototype, 'mode', { 198 | get: function(){ 199 | return this._mode; 200 | }, 201 | set: function(mode){ 202 | this._mode = mode; 203 | rpio.mode(this.pin, mode); 204 | } 205 | }); 206 | 207 | Object.defineProperty(Gpio.prototype, 'state', { 208 | get: function(){ 209 | if(this.mode === Gpio.INPUT){ 210 | return this._state; 211 | }else{ 212 | return this.value; 213 | } 214 | }, 215 | set: function(state){ 216 | if(this.mode === Gpio.INPUT){ 217 | this._state = state; 218 | rpio.pud(this.pin, state); 219 | }else{ 220 | this.value = state; 221 | } 222 | } 223 | }); 224 | 225 | module.exports = Gpio; 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rpio2 2 | 3 | [![npm status](https://img.shields.io/npm/v/rpio2.svg)](https://www.npmjs.org/package/rpio2) 4 | [![build status](https://api.travis-ci.org/akira-cn/rpio2.svg?branch=master)](https://travis-ci.org/akira-cn/rpio2) 5 | [![dependency status](https://david-dm.org/akira-cn/rpio2.svg)](https://david-dm.org/akira-cn/rpio2) 6 | [![coverage status](https://img.shields.io/coveralls/akira-cn/rpio2.svg)](https://coveralls.io/github/akira-cn/rpio2) 7 | 8 | Export elegant OOP APIs to control Raspberry Pi GPIO pins with Node.js. Based on [node-rpio](https://github.com/jperkin/node-rpio) which is a high performace library. 9 | 10 | ## Installation 11 | 12 | ```bash 13 | npm install rpio2 --production 14 | ``` 15 | 16 | By default the module will use `/dev/gpiomem` when using simple GPIO access. 17 | To access this device, your user will need to be a member of the `gpio` group, 18 | and you may need to configure udev with the following rule (as root): 19 | 20 | ```console 21 | $ cat >/etc/udev/rules.d/20-gpiomem.rules < 164 | 165 | + 3.3v12+ 5v 166 | 167 | I2C SDA / GPIO 23 168 | 4+ 5v 169 | 170 | I2C SCL / GPIO 356Ground 171 | 172 | Clock / GPIO 478TX / GPIO 14 173 | 174 | --910RX / GPIO 15 175 | 176 | GPIO 171112GPIO 18 177 | 178 | GPIO 271314-- 179 | 180 | GPIO 221516GPIO 23 181 | 182 | + 3.3V1718GPIO 24 183 | 184 | SPI MOSI / GPIO 101920-- 185 | 186 | SPI MISO / GPIO 92122GPIO 25 187 | 188 | SPI SCLK / GPIO 112324SPI CE0 / GPIO 8 189 | 190 | --2526SPI CE1 / GPIO 7 191 | 192 | Model A+ and Model B+ additional pins 193 | 194 | ID_SD2728ID_SC 195 | 196 | GPIO 52930-- 197 | 198 | GPIO 63132GPIO 12 199 | 200 | GPIO 133334-- 201 | 202 | GPIO 193536GPIO 16 203 | 204 | GPIO 263738GPIO 20 205 | 206 | --3940GPIO 21 207 | 208 | 209 | If you want to map to gpio number directly, see [Gpio.init(options)](#gpioinitoptions) 210 | 211 | --- 212 | 213 | ### Methods 214 | 215 | ##### open(mode[, state]) 216 | 217 | Open a pin for input or output. Valid modes are: 218 | 219 | - Gpio.INPUT: pin is input (read-only). 220 | - Gpio.OUTPUT: pin is output (read-write). 221 | 222 | For output pins, the second parameter defines the initial value of the pin, rather than having to issue a separate .write() call. This can be critical for devices which must have a stable value, rather than relying on the initial floating value when a pin is enabled for output but hasn't yet been configured with a value. 223 | 224 | For input pins, the second parameter can be used to configure the internal pullup or pulldown resistors state, see [mode:0|1](#mode01) [state:0|1](#state01) for more details. 225 | 226 | ##### close() 227 | 228 | Unexports a GPIO from userspace and release all resources. 229 | 230 | ##### read() 231 | 232 | Set a velue to a GPIO. 233 | 234 | ##### write(value) 235 | 236 | Set a velue to a GPIO. 237 | 238 | ##### toggle() 239 | 240 | Change GPIO value. 241 | 242 | ##### sleep(ms[,async]) 243 | 244 | Sleep for a few milliseconds. If async is `true`, it will return a promise. 245 | 246 | ##### createReadStream(pin[, options]) 247 | 248 | Experimental. See the following example: 249 | 250 | **log input value to stdout** 251 | 252 | ```js 253 | const Gpio = require('../lib/index.js').Gpio; 254 | 255 | var gs = Gpio.createReadStream(32, {throttle: 100}); 256 | 257 | gs.pipe(process.stdout); 258 | 259 | process.on("SIGINT", function(){ 260 | gs.end(); 261 | process.exit(0); 262 | }); 263 | ``` 264 | 265 | ##### createWriteStream(pin[, options]) 266 | 267 | Experimental. See the following example: 268 | 269 | **read from stdin and set value** 270 | 271 | ```js 272 | const Gpio = require('../lib/index.js').Gpio; 273 | 274 | var gs = Gpio.createWriteStream(40, { 275 | mode: Gpio.OUTPUT, 276 | state: Gpio.HIGH 277 | }); 278 | 279 | console.log('Please input value of P40.'); 280 | 281 | process.stdin.pipe(gs); 282 | 283 | process.on("SIGINT", function(){ 284 | gs.end(); 285 | process.exit(0); 286 | }); 287 | ``` 288 | 289 | **trace input/output pins** 290 | 291 | ```js 292 | const Gpio = require('../lib/index.js').Gpio; 293 | 294 | var input = Gpio.createReadStream(32, {throttle: 100}); 295 | 296 | var output = Gpio.createWriteStream(40); 297 | 298 | input.pipe(output); 299 | 300 | process.on("SIGINT", function(){ 301 | input.end(); 302 | output.end(); 303 | process.exit(0); 304 | }); 305 | ``` 306 | 307 | ##### group(pins[, activeLow]) 308 | 309 | Create GpioGroup instance. See [GpioGroup(pins[, activeLow]) - Constructor](#gpiogrouppins-activelow). 310 | 311 | --- 312 | 313 | ### Properties 314 | 315 | ##### value:0|1 316 | 317 | Get or set a velue to a GPIO **synchronously**. 318 | 319 | ##### mode:0|1 320 | 321 | The pin direction, pass either Gpio.INPUT for read mode or Gpio.OUTPUT for write mode. 322 | 323 | ##### state:0|1 324 | 325 | The pin state. For input pins, state can be either Gpio.POLL\_HIGHT or Gpio.POLL\_LOW. For output pins, it is equivalent to `value` that state can be either Gpio.HIGH or Gpio.LOW. 326 | 327 | ##### activeLow: boolean 328 | 329 | Specifies whether the values read from or written to the GPIO should be inverted. The interrupt generating edge for the GPIO also follow this this setting. The valid values for activeLow are true and false. Setting activeLow to true inverts. The default value is false. 330 | 331 | --- 332 | 333 | ### Statics 334 | 335 | ##### Gpio.init([options]) 336 | 337 | Initialise the bcm2835 library. This will be called automatically by `.open()` 338 | using the default option values if not called explicitly. The default values 339 | are: 340 | 341 | ```js 342 | var options = { 343 | gpiomem: true, /* Use /dev/gpiomem */ 344 | mapping: 'physical', /* Use the P1-P40 numbering scheme */ 345 | } 346 | ``` 347 | 348 | ##### `gpiomem` 349 | 350 | There are two device nodes for GPIO access. The default is `/dev/gpiomem` 351 | which, when configured with `gpio` group access, allows users in that group to 352 | read/write directly to that device. This removes the need to run as root, but 353 | is limited to GPIO functions. 354 | 355 | For non-GPIO functions (i²c, PWM, SPI) the `/dev/mem` device is required for 356 | full access to the Broadcom peripheral address range and the program needs to 357 | be executed as the root user (e.g. via sudo). If you do not explicitly call 358 | `.init()` when using those functions, the library will do it for you with 359 | `gpiomem: false`. 360 | 361 | You may also need to use `gpiomem: false` if you are running on an older Linux 362 | kernel which does not support the `gpiomem` module. 363 | 364 | rpio will throw an exception if you try to use one of the non-GPIO functions 365 | after already opening with `/dev/gpiomem`, as well as checking to see if you 366 | have the necessary permissions. 367 | 368 | Valid options: 369 | 370 | * `true`: use `/dev/gpiomem` for non-root but GPIO-only access 371 | * `false`: use `/dev/mem` for full access but requires root 372 | 373 | ##### `mapping` 374 | 375 | There are two naming schemes when referring to GPIO pins: 376 | 377 | * By their physical header location: Pins 1 to 26 (A/B) or Pins 1 to 40 (A+/B+) 378 | * Using the Broadcom hardware map: GPIO 0-25 (B rev1), GPIO 2-27 (A/B rev2, A+/B+) 379 | 380 | Confusingly however, the Broadcom GPIO map changes between revisions, so for 381 | example P3 maps to GPIO0 on Model B Revision 1 models, but maps to GPIO2 on all 382 | later models. 383 | 384 | This means the only sane default mapping is the physical layout, so that the 385 | same code will work on all models regardless of the underlying GPIO mapping. 386 | 387 | If you prefer to use the Broadcom GPIO scheme for whatever reason (e.g. to use 388 | the P5 header pins on the Raspberry Pi 1 revision 2.0 model which aren't 389 | currently mapped to the physical layout), you can set `mapping` to `gpio` to 390 | switch to the GPIOxx naming. 391 | 392 | Valid options: 393 | 394 | * `gpio`: use the Broadcom GPIOxx naming 395 | * `physical`: use the physical P01-P40 header layout 396 | 397 | ##### Gpio.sleep(ms[,async]) 398 | 399 | Sleep for a few milliseconds. If async is `true`, it will return a promise. 400 | 401 | --- 402 | 403 | ### Events 404 | 405 | If a pin is in direction of Gpio.DIR_IN. Three type of events can be fired when needed. 406 | 407 | ##### event:rising 408 | 409 | When register listener to `rising` event [the rising interrupt edges](https://www.raspberrypi.org/documentation/hardware/raspberrypi/gpio/README.md) should be configured implictly and the GPIO will trigger the `rising` event. 410 | 411 | ```js 412 | gpio.on('rising', function(){ 413 | console.log('A rising signal detected!'); 414 | }); 415 | ``` 416 | 417 | ##### event:falling 418 | 419 | When register listener to `falling` event [the falling interrupt edges](https://www.raspberrypi.org/documentation/hardware/raspberrypi/gpio/README.md) should be configured implictly and the GPIO will trigger the `falling` event. 420 | 421 | ##### event:change 422 | 423 | When register listener to `change` event [the both(rising and falling) interrupt edges](https://www.raspberrypi.org/documentation/hardware/raspberrypi/gpio/README.md) should be configured implictly and the GPIO will trigger the `change` event(on both rising and falling edges). 424 | 425 | ##### Note: 426 | 427 | Registering events to rising and falling will implictly change the interrupt edges as well as unregistering events: 428 | 429 | ```js 430 | let gpio = new Gpio(40); 431 | gpio.open(Gpio.INPUT); 432 | assertEqual(gpio.edge, Gpio.POLL_NONE); 433 | gpio.on('rising', function(){...}); 434 | assertEqual(gpio.edge, Gpio.POLL_HIGH); 435 | gpio.on('falling', function(){...}); 436 | assertEqual(gpio.edge, Gpio.POLL_BOTH); 437 | gpio.removeListener('rising'); 438 | assertEqual(gpio.edge, Gpio.POLL_LOW); 439 | gpio.removeListener('falling'); 440 | assertEqual(gpio.edge, Gpio.POLL_NONE); 441 | ``` 442 | 443 | --- 444 | ##### GpioGroup(pins, activeLow) 445 | 446 | Experimental. See the following example: 447 | 448 | ```js 449 | var GpioGroup = require('./lib/index.js').GpioGroup; 450 | var pins = [32, 40, 33]; //RGB 451 | var group = new GpioGroup(pins, true); 452 | group.open(GpioGroup.OUTPUT); 453 | 454 | var color = { 455 | yellow: 0b110, 456 | red: 0b100, 457 | green: 0b010 458 | }; 459 | 460 | function turn(color){ 461 | return new Promise(function(resolve, reject) { 462 | group.value = color; 463 | resolve(); 464 | }) 465 | } 466 | function wait(time){ 467 | return new Promise(function(resolve, reject) { 468 | setTimeout(resolve,time); 469 | }) 470 | } 471 | 472 | void function (){ 473 | turn(color.green) 474 | .then(wait.bind(null, 5000)) 475 | .then(turn.bind(null, color.yellow)) 476 | .then(wait.bind(null, 2000)) 477 | .then(turn.bind(null, color.red)) 478 | .then(wait.bind(null, 5000)) 479 | .then(arguments.callee) 480 | }(); 481 | 482 | process.on("SIGINT", function(){ 483 | group.close(); 484 | 485 | console.log('shutdown!'); 486 | process.exit(0); 487 | }); 488 | ``` 489 | 490 | ## LICENSE 491 | 492 | GPL 493 | 494 | -------------------------------------------------------------------------------- /test/lib/gpio.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | global._$jscoverage = global._$jscoverage || {}; 4 | _$jscoverage['gpio.js'] = []; 5 | _$jscoverage['gpio.js'][3] = 0; 6 | _$jscoverage['gpio.js'][7] = 0; 7 | _$jscoverage['gpio.js'][8] = 0; 8 | _$jscoverage['gpio.js'][12] = 0; 9 | _$jscoverage['gpio.js'][14] = 0; 10 | _$jscoverage['gpio.js'][15] = 0; 11 | _$jscoverage['gpio.js'][16] = 0; 12 | _$jscoverage['gpio.js'][17] = 0; 13 | _$jscoverage['gpio.js'][20] = 0; 14 | _$jscoverage['gpio.js'][21] = 0; 15 | _$jscoverage['gpio.js'][22] = 0; 16 | _$jscoverage['gpio.js'][23] = 0; 17 | _$jscoverage['gpio.js'][24] = 0; 18 | _$jscoverage['gpio.js'][25] = 0; 19 | _$jscoverage['gpio.js'][28] = 0; 20 | _$jscoverage['gpio.js'][30] = 0; 21 | _$jscoverage['gpio.js'][31] = 0; 22 | _$jscoverage['gpio.js'][32] = 0; 23 | _$jscoverage['gpio.js'][33] = 0; 24 | _$jscoverage['gpio.js'][35] = 0; 25 | _$jscoverage['gpio.js'][37] = 0; 26 | _$jscoverage['gpio.js'][38] = 0; 27 | _$jscoverage['gpio.js'][39] = 0; 28 | _$jscoverage['gpio.js'][40] = 0; 29 | _$jscoverage['gpio.js'][41] = 0; 30 | _$jscoverage['gpio.js'][43] = 0; 31 | _$jscoverage['gpio.js'][45] = 0; 32 | _$jscoverage['gpio.js'][46] = 0; 33 | _$jscoverage['gpio.js'][47] = 0; 34 | _$jscoverage['gpio.js'][48] = 0; 35 | _$jscoverage['gpio.js'][49] = 0; 36 | _$jscoverage['gpio.js'][51] = 0; 37 | _$jscoverage['gpio.js'][54] = 0; 38 | _$jscoverage['gpio.js'][55] = 0; 39 | _$jscoverage['gpio.js'][57] = 0; 40 | _$jscoverage['gpio.js'][61] = 0; 41 | _$jscoverage['gpio.js'][62] = 0; 42 | _$jscoverage['gpio.js'][63] = 0; 43 | _$jscoverage['gpio.js'][64] = 0; 44 | _$jscoverage['gpio.js'][66] = 0; 45 | _$jscoverage['gpio.js'][67] = 0; 46 | _$jscoverage['gpio.js'][70] = 0; 47 | _$jscoverage['gpio.js'][71] = 0; 48 | _$jscoverage['gpio.js'][75] = 0; 49 | _$jscoverage['gpio.js'][76] = 0; 50 | _$jscoverage['gpio.js'][78] = 0; 51 | _$jscoverage['gpio.js'][81] = 0; 52 | _$jscoverage['gpio.js'][87] = 0; 53 | _$jscoverage['gpio.js'][88] = 0; 54 | _$jscoverage['gpio.js'][90] = 0; 55 | _$jscoverage['gpio.js'][93] = 0; 56 | _$jscoverage['gpio.js'][99] = 0; 57 | _$jscoverage['gpio.js'][101] = 0; 58 | _$jscoverage['gpio.js'][102] = 0; 59 | _$jscoverage['gpio.js'][104] = 0; 60 | _$jscoverage['gpio.js'][106] = 0; 61 | _$jscoverage['gpio.js'][107] = 0; 62 | _$jscoverage['gpio.js'][108] = 0; 63 | _$jscoverage['gpio.js'][110] = 0; 64 | _$jscoverage['gpio.js'][111] = 0; 65 | _$jscoverage['gpio.js'][113] = 0; 66 | _$jscoverage['gpio.js'][117] = 0; 67 | _$jscoverage['gpio.js'][118] = 0; 68 | _$jscoverage['gpio.js'][119] = 0; 69 | _$jscoverage['gpio.js'][122] = 0; 70 | _$jscoverage['gpio.js'][123] = 0; 71 | _$jscoverage['gpio.js'][125] = 0; 72 | _$jscoverage['gpio.js'][126] = 0; 73 | _$jscoverage['gpio.js'][128] = 0; 74 | _$jscoverage['gpio.js'][129] = 0; 75 | _$jscoverage['gpio.js'][130] = 0; 76 | _$jscoverage['gpio.js'][134] = 0; 77 | _$jscoverage['gpio.js'][139] = 0; 78 | _$jscoverage['gpio.js'][141] = 0; 79 | _$jscoverage['gpio.js'][142] = 0; 80 | _$jscoverage['gpio.js'][143] = 0; 81 | _$jscoverage['gpio.js'][144] = 0; 82 | _$jscoverage['gpio.js'][145] = 0; 83 | _$jscoverage['gpio.js'][147] = 0; 84 | _$jscoverage['gpio.js'][149] = 0; 85 | _$jscoverage['gpio.js'][153] = 0; 86 | _$jscoverage['gpio.js'][155] = 0; 87 | _$jscoverage['gpio.js'][156] = 0; 88 | _$jscoverage['gpio.js'][157] = 0; 89 | _$jscoverage['gpio.js'][159] = 0; 90 | _$jscoverage['gpio.js'][160] = 0; 91 | _$jscoverage['gpio.js'][161] = 0; 92 | _$jscoverage['gpio.js'][163] = 0; 93 | _$jscoverage['gpio.js'][164] = 0; 94 | _$jscoverage['gpio.js'][165] = 0; 95 | _$jscoverage['gpio.js'][167] = 0; 96 | _$jscoverage['gpio.js'][170] = 0; 97 | _$jscoverage['gpio.js'][175] = 0; 98 | _$jscoverage['gpio.js'][176] = 0; 99 | _$jscoverage['gpio.js'][178] = 0; 100 | _$jscoverage['gpio.js'][179] = 0; 101 | _$jscoverage['gpio.js'][183] = 0; 102 | _$jscoverage['gpio.js'][184] = 0; 103 | _$jscoverage['gpio.js'][188] = 0; 104 | _$jscoverage['gpio.js'][190] = 0; 105 | _$jscoverage['gpio.js'][193] = 0; 106 | _$jscoverage['gpio.js'][197] = 0; 107 | _$jscoverage['gpio.js'][199] = 0; 108 | _$jscoverage['gpio.js'][202] = 0; 109 | _$jscoverage['gpio.js'][203] = 0; 110 | _$jscoverage['gpio.js'][207] = 0; 111 | _$jscoverage['gpio.js'][209] = 0; 112 | _$jscoverage['gpio.js'][210] = 0; 113 | _$jscoverage['gpio.js'][212] = 0; 114 | _$jscoverage['gpio.js'][216] = 0; 115 | _$jscoverage['gpio.js'][217] = 0; 116 | _$jscoverage['gpio.js'][218] = 0; 117 | _$jscoverage['gpio.js'][220] = 0; 118 | _$jscoverage['gpio.js'][225] = 0; 119 | _$jscoverage['gpio.js'].source = ['\'use strict\';', '', 'const rpio = require(\'rpio\'),', ' util = require(\'util\'),', ' EventEmitter = require(\'events\').EventEmitter;', '', 'function updateEdge(gpio, type){', ' var changes = gpio.listeners(\'change\').length,', ' risings = gpio.listeners(\'rising\').length,', ' fallings = gpio.listeners(\'falling\').length;', '', ' var edge = gpio.edge;', '', ' function triggerEvent(pin){', ' gpio.emit(\'change\', gpio, pin);', ' if(gpio.value) gpio.emit(\'rising\', gpio, pin);', ' else gpio.emit(\'falling\', gpio, pin); ', ' }', '', ' if(type === \'change\'){', ' changes ++;', ' }else if(type === \'rising\'){', ' risings ++;', ' }else if(type === \'falling\'){', ' fallings ++;', ' }', '', ' if(changes > 0 || ', ' risings > 0 && fallings > 0){', ' if(edge !== rpio.POLL_BOTH){', ' gpio.edge = rpio.POLL_BOTH;', ' if(edge !== rpio.POLL_NONE){', ' rpio.poll(gpio.pin, null);', ' }', ' rpio.poll(gpio.pin, triggerEvent, rpio.POLL_BOTH);', ' }', ' }else if(risings > 0){', ' if(edge !== rpio.POLL_HIGH){', ' gpio.edge = rpio.POLL_HIGH;', ' if(edge !== rpio.POLL_NONE){', ' rpio.poll(gpio.pin, null);', ' }', ' rpio.poll(gpio.pin, triggerEvent, rpio.POLL_HIGH); ', ' }', ' }else if(fallings > 0){', ' if(edge !== rpio.POLL_LOW){', ' gpio.edge = rpio.POLL_LOW;', ' if(edge !== rpio.POLL_NONE){', ' rpio.poll(gpio.pin, null);', ' }', ' rpio.poll(gpio.pin, triggerEvent, rpio.POLL_LOW);', ' } ', ' }else{', ' if(edge !== rpio.POLL_NONE){', ' rpio.poll(gpio.pin, null);', ' }', ' gpio.edge = rpio.POLL_NONE;', ' }', '}', '', 'function Gpio(pin, activeLow){', ' this.pin = pin;', ' this.edge = rpio.POLL_NONE;', ' this.activeLow = !!activeLow;', ' ', ' this.on(\'removeListener\', function(type){', ' updateEdge(this);', ' });', '', ' this.on(\'newListener\', function(type){', ' updateEdge(this, type);', ' });', '', ' //private properties', ' var mode = -1;', ' Object.defineProperty(this, \'_mode\', {', ' get: function(){', ' return mode;', ' },', ' set: function(value){', ' mode = value;', ' },', ' enumerable: false', ' });', '', ' //input state POLL_HIGH POLL_ROW resistors', ' var state = -1;', ' Object.defineProperty(this, \'_state\', {', ' get: function(){', ' return state;', ' },', ' set: function(value){', ' state = value;', ' },', ' enumerable: false', ' });', '}', '', 'util.inherits(Gpio, EventEmitter);', '', 'Gpio.init = rpio.init;', 'require(\'./gpio_util.js\').defineStaticProperties(Gpio);', '', 'Object.assign(Gpio.prototype, {', ' open: function(mode, value){', ' this._mode = mode;', ' if(mode === rpio.INPUT && value !== undefined){', ' this._state = value;', ' }', ' if(mode === rpio.OUTPUT){', ' return rpio.open(this.pin, mode, this.activeLow ^ value);', ' }else{', ' return rpio.open(this.pin, mode, value);', ' }', ' },', ' close: function(){', ' this.removeAllListeners();', ' this._mode = this._state = -1;', ' return rpio.close(this.pin);', ' },', ' read: function(length){', ' if(length === undefined){', ' return this.value;', ' }else{', ' var buf = new Buffer(length);', ' rpio.readbuf(this.pin, buf, length);', '', ' if(this.activeLow){', ' for(var i = 0; i < buf.length; i++){', ' buf[i] ^= 1;', ' }', ' }', '', ' return buf;', ' }', ' },', ' write: function(buf, length){', ' ', ' var self = this;', '', ' function writeData(){', ' if(self.activeLow){', ' var newBuf = new Buffer(length || buf.length);', ' for(var i = 0; i < newBuf.length; i++){', ' newBuf[i] = 1 ^ buf[i];', ' }', ' return rpio.writebuf(self.pin, newBuf, length);', ' }else{ ', ' return rpio.writebuf(self.pin, buf, length);', ' } ', ' }', '', ' if(length === undefined && buf === 0 || buf === 1){', ' //gpio.write(1)', ' this.value = buf;', ' return;', ' }else if(typeof buf === \'string\'){', ' //gpio.write(\'1010101\')', ' buf = new Buffer(buf.trim().split(\'\').map(function(i){return 0|i}));', ' return writeData();', ' }else if(typeof buf === \'number\'){', ' //gpio.write(0b10101010);', ' return this.write(buf.toString(2), length);', ' }else if(buf instanceof Buffer){', ' if(buf[0] !== 0 && buf[0] !== 1){', ' //Buffer<\'0\',\'1\',\'0\',\'1\'...>', ' return this.write(buf.toString(), length);', ' }else{', ' //Buffer<00,01,00,01...>', ' return writeData();', ' }', ' }', ' },', ' sleep: function(ms, async){', ' if(!async){', ' return rpio.msleep(ms);', ' }', ' return new Promise(function(resolve){', ' setTimeout(resolve, ms); ', ' });', ' },', ' toggle: function(){', ' this.value ^= 1;', ' return this.value;', ' }', '});', '', 'Object.defineProperty(Gpio.prototype, \'value\', {', ' get: function(){', ' return this.activeLow ^ rpio.read(this.pin);', ' },', ' set: function(value){', ' rpio.write(this.pin, this.activeLow ^ value);', ' }', '});', '', 'Object.defineProperty(Gpio.prototype, \'mode\', {', ' get: function(){', ' return this._mode;', ' },', ' set: function(mode){', ' this._mode = mode;', ' rpio.mode(this.pin, mode);', ' }', '});', '', 'Object.defineProperty(Gpio.prototype, \'state\', {', ' get: function(){', ' if(this.mode === Gpio.INPUT){', ' return this._state;', ' }else{', ' return this.value;', ' }', ' },', ' set: function(state){', ' if(this.mode === Gpio.INPUT){', ' this._state = state;', ' rpio.pud(this.pin, state);', ' }else{', ' this.value = state;', ' }', ' }', '});', '', 'module.exports = Gpio;', '']; 120 | _$jscoverage['gpio.js'][3]++; 121 | const rpio = require('../rpio_sim.js'), 122 | util = require('util'), 123 | EventEmitter = require('events').EventEmitter; 124 | 125 | _$jscoverage['gpio.js'][7]++; 126 | function updateEdge(gpio, type) { 127 | _$jscoverage['gpio.js'][8]++; 128 | 129 | var changes = gpio.listeners('change').length, 130 | risings = gpio.listeners('rising').length, 131 | fallings = gpio.listeners('falling').length; 132 | 133 | _$jscoverage['gpio.js'][12]++; 134 | var edge = gpio.edge; 135 | 136 | _$jscoverage['gpio.js'][14]++; 137 | function triggerEvent(pin) { 138 | _$jscoverage['gpio.js'][15]++; 139 | 140 | gpio.emit('change', gpio, pin); 141 | if (gpio.value) { 142 | _$jscoverage['gpio.js'][16]++; 143 | gpio.emit('rising', gpio, pin); 144 | } else { 145 | _$jscoverage['gpio.js'][17]++; 146 | gpio.emit('falling', gpio, pin); 147 | } 148 | } 149 | 150 | _$jscoverage['gpio.js'][20]++; 151 | if (type === 'change') { 152 | _$jscoverage['gpio.js'][21]++; 153 | 154 | changes++; 155 | } else { 156 | _$jscoverage['gpio.js'][22]++; 157 | if (type === 'rising') { 158 | _$jscoverage['gpio.js'][23]++; 159 | 160 | risings++; 161 | } else { 162 | _$jscoverage['gpio.js'][24]++; 163 | if (type === 'falling') { 164 | _$jscoverage['gpio.js'][25]++; 165 | 166 | fallings++; 167 | } 168 | } 169 | }_$jscoverage['gpio.js'][28]++; 170 | if (changes > 0 || risings > 0 && fallings > 0) { 171 | _$jscoverage['gpio.js'][30]++; 172 | 173 | if (edge !== rpio.POLL_BOTH) { 174 | _$jscoverage['gpio.js'][31]++; 175 | 176 | gpio.edge = rpio.POLL_BOTH; 177 | _$jscoverage['gpio.js'][32]++; 178 | if (edge !== rpio.POLL_NONE) { 179 | _$jscoverage['gpio.js'][33]++; 180 | 181 | rpio.poll(gpio.pin, null); 182 | } 183 | _$jscoverage['gpio.js'][35]++; 184 | rpio.poll(gpio.pin, triggerEvent, rpio.POLL_BOTH); 185 | } 186 | } else { 187 | _$jscoverage['gpio.js'][37]++; 188 | if (risings > 0) { 189 | _$jscoverage['gpio.js'][38]++; 190 | 191 | if (edge !== rpio.POLL_HIGH) { 192 | _$jscoverage['gpio.js'][39]++; 193 | 194 | gpio.edge = rpio.POLL_HIGH; 195 | _$jscoverage['gpio.js'][40]++; 196 | if (edge !== rpio.POLL_NONE) { 197 | _$jscoverage['gpio.js'][41]++; 198 | 199 | rpio.poll(gpio.pin, null); 200 | } 201 | _$jscoverage['gpio.js'][43]++; 202 | rpio.poll(gpio.pin, triggerEvent, rpio.POLL_HIGH); 203 | } 204 | } else { 205 | _$jscoverage['gpio.js'][45]++; 206 | if (fallings > 0) { 207 | _$jscoverage['gpio.js'][46]++; 208 | 209 | if (edge !== rpio.POLL_LOW) { 210 | _$jscoverage['gpio.js'][47]++; 211 | 212 | gpio.edge = rpio.POLL_LOW; 213 | _$jscoverage['gpio.js'][48]++; 214 | if (edge !== rpio.POLL_NONE) { 215 | _$jscoverage['gpio.js'][49]++; 216 | 217 | rpio.poll(gpio.pin, null); 218 | } 219 | _$jscoverage['gpio.js'][51]++; 220 | rpio.poll(gpio.pin, triggerEvent, rpio.POLL_LOW); 221 | } 222 | } else { 223 | _$jscoverage['gpio.js'][54]++; 224 | 225 | if (edge !== rpio.POLL_NONE) { 226 | _$jscoverage['gpio.js'][55]++; 227 | 228 | rpio.poll(gpio.pin, null); 229 | } 230 | _$jscoverage['gpio.js'][57]++; 231 | gpio.edge = rpio.POLL_NONE; 232 | } 233 | } 234 | } 235 | } 236 | 237 | _$jscoverage['gpio.js'][61]++; 238 | function Gpio(pin, activeLow) { 239 | _$jscoverage['gpio.js'][62]++; 240 | 241 | this.pin = pin; 242 | _$jscoverage['gpio.js'][63]++; 243 | this.edge = rpio.POLL_NONE; 244 | _$jscoverage['gpio.js'][64]++; 245 | this.activeLow = !!activeLow; 246 | 247 | _$jscoverage['gpio.js'][66]++; 248 | this.on('removeListener', function (type) { 249 | _$jscoverage['gpio.js'][67]++; 250 | 251 | updateEdge(this); 252 | }); 253 | 254 | _$jscoverage['gpio.js'][70]++; 255 | this.on('newListener', function (type) { 256 | _$jscoverage['gpio.js'][71]++; 257 | 258 | updateEdge(this, type); 259 | }); 260 | 261 | //private properties 262 | _$jscoverage['gpio.js'][75]++; 263 | var mode = -1; 264 | _$jscoverage['gpio.js'][76]++; 265 | Object.defineProperty(this, '_mode', { 266 | get: function () { 267 | _$jscoverage['gpio.js'][78]++; 268 | 269 | return mode; 270 | }, 271 | set: function (value) { 272 | _$jscoverage['gpio.js'][81]++; 273 | 274 | mode = value; 275 | }, 276 | enumerable: false 277 | }); 278 | 279 | //input state POLL_HIGH POLL_ROW resistors 280 | _$jscoverage['gpio.js'][87]++; 281 | var state = -1; 282 | _$jscoverage['gpio.js'][88]++; 283 | Object.defineProperty(this, '_state', { 284 | get: function () { 285 | _$jscoverage['gpio.js'][90]++; 286 | 287 | return state; 288 | }, 289 | set: function (value) { 290 | _$jscoverage['gpio.js'][93]++; 291 | 292 | state = value; 293 | }, 294 | enumerable: false 295 | }); 296 | } 297 | 298 | _$jscoverage['gpio.js'][99]++; 299 | util.inherits(Gpio, EventEmitter); 300 | 301 | _$jscoverage['gpio.js'][101]++; 302 | Gpio.init = rpio.init; 303 | _$jscoverage['gpio.js'][102]++; 304 | require('./gpio_util.js').defineStaticProperties(Gpio); 305 | 306 | _$jscoverage['gpio.js'][104]++; 307 | Object.assign(Gpio.prototype, { 308 | open: function (mode, value) { 309 | _$jscoverage['gpio.js'][106]++; 310 | 311 | this._mode = mode; 312 | _$jscoverage['gpio.js'][107]++; 313 | if (mode === rpio.INPUT && value !== undefined) { 314 | _$jscoverage['gpio.js'][108]++; 315 | 316 | this._state = value; 317 | } 318 | _$jscoverage['gpio.js'][110]++; 319 | if (mode === rpio.OUTPUT) { 320 | _$jscoverage['gpio.js'][111]++; 321 | 322 | return rpio.open(this.pin, mode, this.activeLow ^ value); 323 | } else { 324 | _$jscoverage['gpio.js'][113]++; 325 | 326 | return rpio.open(this.pin, mode, value); 327 | } 328 | }, 329 | close: function () { 330 | _$jscoverage['gpio.js'][117]++; 331 | 332 | this.removeAllListeners(); 333 | _$jscoverage['gpio.js'][118]++; 334 | this._mode = this._state = -1; 335 | _$jscoverage['gpio.js'][119]++; 336 | return rpio.close(this.pin); 337 | }, 338 | read: function (length) { 339 | _$jscoverage['gpio.js'][122]++; 340 | 341 | if (length === undefined) { 342 | _$jscoverage['gpio.js'][123]++; 343 | 344 | return this.value; 345 | } else { 346 | _$jscoverage['gpio.js'][125]++; 347 | 348 | var buf = new Buffer(length); 349 | _$jscoverage['gpio.js'][126]++; 350 | rpio.readbuf(this.pin, buf, length); 351 | 352 | _$jscoverage['gpio.js'][128]++; 353 | if (this.activeLow) { 354 | _$jscoverage['gpio.js'][129]++; 355 | 356 | for (var i = 0; i < buf.length; i++) { 357 | _$jscoverage['gpio.js'][130]++; 358 | 359 | buf[i] ^= 1; 360 | } 361 | } 362 | 363 | _$jscoverage['gpio.js'][134]++; 364 | return buf; 365 | } 366 | }, 367 | write: function (buf, length) { 368 | _$jscoverage['gpio.js'][139]++; 369 | 370 | 371 | var self = this; 372 | 373 | _$jscoverage['gpio.js'][141]++; 374 | function writeData() { 375 | _$jscoverage['gpio.js'][142]++; 376 | 377 | if (self.activeLow) { 378 | _$jscoverage['gpio.js'][143]++; 379 | 380 | var newBuf = new Buffer(length || buf.length); 381 | _$jscoverage['gpio.js'][144]++; 382 | for (var i = 0; i < newBuf.length; i++) { 383 | _$jscoverage['gpio.js'][145]++; 384 | 385 | newBuf[i] = 1 ^ buf[i]; 386 | } 387 | _$jscoverage['gpio.js'][147]++; 388 | return rpio.writebuf(self.pin, newBuf, length); 389 | } else { 390 | _$jscoverage['gpio.js'][149]++; 391 | 392 | return rpio.writebuf(self.pin, buf, length); 393 | } 394 | } 395 | 396 | _$jscoverage['gpio.js'][153]++; 397 | if (length === undefined && buf === 0 || buf === 1) { 398 | _$jscoverage['gpio.js'][155]++; 399 | 400 | //gpio.write(1) 401 | this.value = buf; 402 | _$jscoverage['gpio.js'][156]++; 403 | return; 404 | } else { 405 | _$jscoverage['gpio.js'][157]++; 406 | if (typeof buf === 'string') { 407 | //gpio.write('1010101') 408 | buf = new Buffer(buf.trim().split('').map(function (i) { 409 | _$jscoverage['gpio.js'][159]++; 410 | return 0 | i; 411 | })); 412 | _$jscoverage['gpio.js'][160]++; 413 | return writeData(); 414 | } else { 415 | _$jscoverage['gpio.js'][161]++; 416 | if (typeof buf === 'number') { 417 | _$jscoverage['gpio.js'][163]++; 418 | 419 | //gpio.write(0b10101010); 420 | return this.write(buf.toString(2), length); 421 | } else { 422 | _$jscoverage['gpio.js'][164]++; 423 | if (buf instanceof Buffer) { 424 | _$jscoverage['gpio.js'][165]++; 425 | 426 | if (buf[0] !== 0 && buf[0] !== 1) { 427 | _$jscoverage['gpio.js'][167]++; 428 | 429 | //Buffer<'0','1','0','1'...> 430 | return this.write(buf.toString(), length); 431 | } else { 432 | _$jscoverage['gpio.js'][170]++; 433 | 434 | //Buffer<00,01,00,01...> 435 | return writeData(); 436 | } 437 | } 438 | } 439 | } 440 | } 441 | }, 442 | sleep: function (ms, async) { 443 | _$jscoverage['gpio.js'][175]++; 444 | 445 | if (!async) { 446 | _$jscoverage['gpio.js'][176]++; 447 | 448 | return rpio.msleep(ms); 449 | } 450 | _$jscoverage['gpio.js'][178]++; 451 | return new Promise(function (resolve) { 452 | _$jscoverage['gpio.js'][179]++; 453 | 454 | setTimeout(resolve, ms); 455 | }); 456 | }, 457 | toggle: function () { 458 | _$jscoverage['gpio.js'][183]++; 459 | 460 | this.value ^= 1; 461 | _$jscoverage['gpio.js'][184]++; 462 | return this.value; 463 | } 464 | }); 465 | 466 | _$jscoverage['gpio.js'][188]++; 467 | Object.defineProperty(Gpio.prototype, 'value', { 468 | get: function () { 469 | _$jscoverage['gpio.js'][190]++; 470 | 471 | return this.activeLow ^ rpio.read(this.pin); 472 | }, 473 | set: function (value) { 474 | _$jscoverage['gpio.js'][193]++; 475 | 476 | rpio.write(this.pin, this.activeLow ^ value); 477 | } 478 | }); 479 | 480 | _$jscoverage['gpio.js'][197]++; 481 | Object.defineProperty(Gpio.prototype, 'mode', { 482 | get: function () { 483 | _$jscoverage['gpio.js'][199]++; 484 | 485 | return this._mode; 486 | }, 487 | set: function (mode) { 488 | _$jscoverage['gpio.js'][202]++; 489 | 490 | this._mode = mode; 491 | _$jscoverage['gpio.js'][203]++; 492 | rpio.mode(this.pin, mode); 493 | } 494 | }); 495 | 496 | _$jscoverage['gpio.js'][207]++; 497 | Object.defineProperty(Gpio.prototype, 'state', { 498 | get: function () { 499 | _$jscoverage['gpio.js'][209]++; 500 | 501 | if (this.mode === Gpio.INPUT) { 502 | _$jscoverage['gpio.js'][210]++; 503 | 504 | return this._state; 505 | } else { 506 | _$jscoverage['gpio.js'][212]++; 507 | 508 | return this.value; 509 | } 510 | }, 511 | set: function (state) { 512 | _$jscoverage['gpio.js'][216]++; 513 | 514 | if (this.mode === Gpio.INPUT) { 515 | _$jscoverage['gpio.js'][217]++; 516 | 517 | this._state = state; 518 | _$jscoverage['gpio.js'][218]++; 519 | rpio.pud(this.pin, state); 520 | } else { 521 | _$jscoverage['gpio.js'][220]++; 522 | 523 | this.value = state; 524 | } 525 | } 526 | }); 527 | 528 | _$jscoverage['gpio.js'][225]++; 529 | module.exports = Gpio; --------------------------------------------------------------------------------