This commit is contained in:
2018-05-16 10:10:23 +02:00
commit 79abc63edd
597 changed files with 93351 additions and 0 deletions

273
node_modules/onoff/onoff.js generated vendored Normal file
View File

@ -0,0 +1,273 @@
"use strict";
const fs = require('fs');
const debounce = require('lodash.debounce');
const Epoll = require('epoll').Epoll;
const GPIO_ROOT_PATH = '/sys/class/gpio/';
// fs reads and writes use Buffers
const HIGH_BUF = Buffer.from('1');
const LOW_BUF = Buffer.from('0');
// lib returns numeric data and expects numeric data as arguments
const HIGH = 1;
const LOW = 0;
class Gpio {
constructor(gpio, direction, edge, options) {
if (typeof edge === 'object' && !options) {
options = edge;
edge = undefined;
}
options = options || {};
this._gpio = gpio;
this._gpioPath = GPIO_ROOT_PATH + 'gpio' + this._gpio + '/';
this._debounceTimeout = options.debounceTimeout || 0;
this._readBuffer = Buffer.alloc(16);
this._listeners = [];
if (!fs.existsSync(this._gpioPath)) {
// The pin hasn't been exported yet so export it
fs.writeFileSync(GPIO_ROOT_PATH + 'export', this._gpio);
// A hack to avoid the issue described here:
// https://github.com/raspberrypi/linux/issues/553
// I don't like this solution, but it enables compatibility with older
// versions of onoff, i.e., the Gpio constructor was and still is
// synchronous.
let permissionRequiredPaths = [
this._gpioPath + 'direction',
this._gpioPath + 'active_low',
this._gpioPath + 'value',
];
// On some systems the edge file will not exist if the GPIO does not
// support interrupts
// https://github.com/fivdi/onoff/issues/77#issuecomment-321980735
if (edge && direction === 'in') {
permissionRequiredPaths.push(this._gpioPath + 'edge');
}
permissionRequiredPaths.forEach((path) => {
let tries = 0;
while (true) {
try {
tries += 1;
const fd = fs.openSync(path, 'r+');
fs.closeSync(fd);
break;
} catch (e) {
if (tries === 10000) {
throw e;
}
}
}
});
fs.writeFileSync(this._gpioPath + 'direction', direction);
// On some systems writing to the edge file for an output GPIO will
// result in an "EIO, i/o error"
// https://github.com/fivdi/onoff/issues/87
if (edge && direction === 'in') {
fs.writeFileSync(this._gpioPath + 'edge', edge);
}
if (!!options.activeLow) {
fs.writeFileSync(this._gpioPath + 'active_low', HIGH_BUF);
}
} else {
// The pin has already been exported, perhaps by onoff itself, perhaps
// by quick2wire gpio-admin on the Pi, perhaps by the WiringPi gpio
// utility on the Pi, or perhaps by something else. In any case, an
// attempt is made to set the direction and edge to the requested
// values here. If quick2wire gpio-admin was used for the export, the
// user should have access to both direction and edge files. This is
// important as gpio-admin sets niether direction nor edge. If the
// WiringPi gpio utility was used, the user should have access to edge
// file, but not the direction file. This is also ok as the WiringPi
// gpio utility can set both direction and edge. If there are any
// errors while attempting to perform the modifications, just keep on
// truckin'.
try {
fs.writeFileSync(this._gpioPath + 'direction', direction);
} catch (ignore) {
}
try {
// On some systems writing to the edge file for an output GPIO will
// result in an "EIO, i/o error"
// https://github.com/fivdi/onoff/issues/87
if (edge && direction === 'in') {
fs.writeFileSync(this._gpioPath + 'edge', edge);
}
try {
fs.writeFileSync(this._gpioPath + 'active_low',
!!options.activeLow ? HIGH_BUF : LOW_BUF
);
} catch (ignore) {
}
} catch (ignore) {
}
}
// Cache fd for performance
this._valueFd = fs.openSync(this._gpioPath + 'value', 'r+');
{
// A poller is created for both inputs and outputs. A poller isn't
// actully needed for an output but the setDirection method can be
// invoked to change the direction of a GPIO from output to input and
// then a poller may be needed.
const pollerEventHandler = (err, fd, events) => {
const value = this.readSync();
if ((value === LOW && this._fallingEnabled) ||
(value === HIGH && this._risingEnabled)) {
this._listeners.slice(0).forEach((callback) => {
callback(err, value);
});
}
};
this._risingEnabled = edge === 'both' || edge == 'rising';
this._fallingEnabled = edge === 'both' || edge == 'falling';
// Read GPIO value before polling to prevent an initial unauthentic
// interrupt
this.readSync();
if (this._debounceTimeout > 0) {
const db = debounce(pollerEventHandler, this._debounceTimeout);
this._poller = new Epoll((err, fd, events) => {
this.readSync(); // Clear interrupt
db(err, fd, events);
});
} else {
this._poller = new Epoll(pollerEventHandler);
}
}
}
read(callback) {
fs.read(this._valueFd, this._readBuffer, 0, 1, 0, (err, bytes, buf) => {
if (typeof callback === 'function') {
if (err) {
return callback(err);
}
callback(null, buf[0] === HIGH_BUF[0] ? HIGH : LOW);
}
});
}
readSync() {
fs.readSync(this._valueFd, this._readBuffer, 0, 1, 0);
return this._readBuffer[0] === HIGH_BUF[0] ? HIGH : LOW;
}
write(value, callback) {
const writeBuffer = value === HIGH ? HIGH_BUF : LOW_BUF;
fs.write(this._valueFd, writeBuffer, 0, writeBuffer.length, 0, callback);
}
writeSync(value) {
const writeBuffer = value === HIGH ? HIGH_BUF : LOW_BUF;
fs.writeSync(this._valueFd, writeBuffer, 0, writeBuffer.length, 0);
}
watch(callback) {
this._listeners.push(callback);
if (this._listeners.length === 1) {
this._poller.add(this._valueFd, Epoll.EPOLLPRI);
}
}
unwatch(callback) {
if (this._listeners.length > 0) {
if (typeof callback !== 'function') {
this._listeners = [];
} else {
this._listeners = this._listeners.filter((listener) => {
return callback !== listener;
});
}
if (this._listeners.length === 0) {
this._poller.remove(this._valueFd);
}
}
}
unwatchAll() {
this.unwatch();
}
direction() {
return fs.readFileSync(this._gpioPath + 'direction').toString().trim();
}
setDirection(direction) {
fs.writeFileSync(this._gpioPath + 'direction', direction);
}
edge() {
return fs.readFileSync(this._gpioPath + 'edge').toString().trim();
}
setEdge(edge) {
fs.writeFileSync(this._gpioPath + 'edge', edge);
this._risingEnabled = edge === 'both' || edge == 'rising';
this._fallingEnabled = edge === 'both' || edge == 'falling';
}
activeLow() {
return fs.readFileSync(
this._gpioPath + 'active_low')[0] === HIGH_BUF[0] ? true : false;
}
setActiveLow(invert) {
fs.writeFileSync(this._gpioPath + 'active_low', !!invert ? HIGH_BUF : LOW_BUF);
}
unexport() {
this.unwatchAll();
fs.closeSync(this._valueFd);
try {
fs.writeFileSync(GPIO_ROOT_PATH + 'unexport', this._gpio);
} catch (ignore) {
// Flow of control always arrives here when cape_universal is enabled on
// the bbb.
}
}
static get accessible() {
let fd;
try {
fd = fs.openSync(GPIO_ROOT_PATH + 'export', 'w');
} catch(e) {
// e.code === 'ENOENT' / 'EACCES' are most common
// though any failure to open will also result in a gpio
// failure to export.
return false;
} finally {
if (fd) {
fs.closeSync(fd);
}
}
return true;
}
}
Gpio.HIGH = HIGH;
Gpio.LOW = LOW;
exports.Gpio = Gpio;