2015-04-15 12:49:12 +08:00
|
|
|
/* eslint no-sync: 0 */
|
|
|
|
|
2014-05-14 09:31:25 +08:00
|
|
|
"use strict";
|
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
var FS = require("fs"),
|
|
|
|
EventEmitter = require("events").EventEmitter;
|
2014-05-14 09:31:25 +08:00
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
var Utils = require("../utils");
|
2014-06-06 03:11:37 +08:00
|
|
|
|
2014-05-14 09:31:25 +08:00
|
|
|
var GPIO_PATH = "/sys/class/gpio";
|
|
|
|
|
|
|
|
var GPIO_READ = "in";
|
|
|
|
var GPIO_WRITE = "out";
|
|
|
|
|
2015-06-30 01:21:25 +08:00
|
|
|
/**
|
|
|
|
* The DigitalPin class provides an interface with the Linux GPIO system present
|
|
|
|
* in single-board computers such as Raspberry Pi, or Beaglebone Black.
|
|
|
|
*
|
|
|
|
* @constructor DigitalPin
|
|
|
|
* @param {Object} opts digital pin options
|
|
|
|
* @param {String} pin which pin number to use
|
|
|
|
* @param {String} mode which pin mode to use
|
|
|
|
*/
|
2014-05-14 09:31:25 +08:00
|
|
|
var DigitalPin = module.exports = function DigitalPin(opts) {
|
|
|
|
this.pinNum = opts.pin.toString();
|
2014-12-16 03:15:29 +08:00
|
|
|
this.status = "low";
|
2014-05-14 09:31:25 +08:00
|
|
|
this.ready = false;
|
|
|
|
this.mode = opts.mode;
|
2014-06-17 04:09:13 +08:00
|
|
|
};
|
2014-05-14 09:31:25 +08:00
|
|
|
|
2014-06-06 03:11:37 +08:00
|
|
|
Utils.subclass(DigitalPin, EventEmitter);
|
2014-05-14 09:31:25 +08:00
|
|
|
|
|
|
|
DigitalPin.prototype.connect = function(mode) {
|
2014-08-30 03:59:44 +08:00
|
|
|
if (this.mode == null) {
|
|
|
|
this.mode = mode;
|
|
|
|
}
|
2014-05-14 09:31:25 +08:00
|
|
|
|
|
|
|
FS.exists(this._pinPath(), function(exists) {
|
2014-12-16 03:15:29 +08:00
|
|
|
if (exists) {
|
|
|
|
this._openPin();
|
|
|
|
} else {
|
|
|
|
this._createGPIOPin();
|
|
|
|
}
|
2014-08-30 03:59:44 +08:00
|
|
|
}.bind(this));
|
2014-05-14 09:31:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype.close = function() {
|
|
|
|
FS.writeFile(this._unexportPath(), this.pinNum, function(err) {
|
2014-08-30 03:59:44 +08:00
|
|
|
this._closeCallback(err);
|
|
|
|
}.bind(this));
|
2014-05-14 09:31:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype.closeSync = function() {
|
|
|
|
FS.writeFileSync(this._unexportPath(), this.pinNum);
|
|
|
|
this._closeCallback(false);
|
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype.digitalWrite = function(value) {
|
2014-12-16 03:15:29 +08:00
|
|
|
if (this.mode !== "w") {
|
|
|
|
this._setMode("w");
|
2014-08-30 03:59:44 +08:00
|
|
|
}
|
2014-05-14 09:31:25 +08:00
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
this.status = value === 1 ? "high" : "low";
|
2014-05-14 09:31:25 +08:00
|
|
|
|
|
|
|
FS.writeFile(this._valuePath(), value, function(err) {
|
|
|
|
if (err) {
|
2014-12-16 03:15:29 +08:00
|
|
|
var str = "Error occurred while writing value ";
|
|
|
|
str += value + " to pin " + this.pinNum;
|
|
|
|
|
|
|
|
this.emit("error", str);
|
2014-05-14 09:31:25 +08:00
|
|
|
} else {
|
2014-12-16 03:15:29 +08:00
|
|
|
this.emit("digitalWrite", value);
|
2014-05-14 09:31:25 +08:00
|
|
|
}
|
2014-08-30 03:59:44 +08:00
|
|
|
}.bind(this));
|
2014-05-14 09:31:25 +08:00
|
|
|
|
|
|
|
return value;
|
|
|
|
};
|
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
// Public: Reads the digial pin"s value periodicly on a supplied interval,
|
2014-05-14 09:31:25 +08:00
|
|
|
// and emits the result or an error
|
|
|
|
//
|
|
|
|
// interval - time (in milliseconds) to read from the pin at
|
|
|
|
//
|
|
|
|
// Returns the defined interval
|
|
|
|
DigitalPin.prototype.digitalRead = function(interval) {
|
2014-12-16 03:15:29 +08:00
|
|
|
if (this.mode !== "r") { this._setMode("r"); }
|
2014-05-14 09:31:25 +08:00
|
|
|
|
2014-06-06 03:11:37 +08:00
|
|
|
Utils.every(interval, function() {
|
2014-08-30 03:59:44 +08:00
|
|
|
FS.readFile(this._valuePath(), function(err, data) {
|
2014-05-14 09:31:25 +08:00
|
|
|
if (err) {
|
2014-08-30 03:59:44 +08:00
|
|
|
var error = "Error occurred while reading from pin " + this.pinNum;
|
2014-12-16 03:15:29 +08:00
|
|
|
this.emit("error", error);
|
2014-05-14 09:31:25 +08:00
|
|
|
} else {
|
2015-04-15 12:49:12 +08:00
|
|
|
var readData = parseInt(data.toString(), 10);
|
2014-12-16 03:15:29 +08:00
|
|
|
this.emit("digitalRead", readData);
|
2014-05-14 09:31:25 +08:00
|
|
|
}
|
2014-08-30 03:59:44 +08:00
|
|
|
}.bind(this));
|
|
|
|
}.bind(this));
|
2014-05-14 09:31:25 +08:00
|
|
|
};
|
|
|
|
|
2014-08-30 03:59:44 +08:00
|
|
|
DigitalPin.prototype.setHigh = function() {
|
|
|
|
return this.digitalWrite(1);
|
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype.setLow = function() {
|
|
|
|
return this.digitalWrite(0);
|
|
|
|
};
|
2014-05-14 09:31:25 +08:00
|
|
|
|
|
|
|
DigitalPin.prototype.toggle = function() {
|
2014-12-16 03:15:29 +08:00
|
|
|
return (this.status === "low") ? this.setHigh() : this.setLow();
|
2014-05-14 09:31:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Creates the GPIO file to read/write from
|
|
|
|
DigitalPin.prototype._createGPIOPin = function() {
|
|
|
|
FS.writeFile(this._exportPath(), this.pinNum, function(err) {
|
|
|
|
if (err) {
|
2014-12-16 03:15:29 +08:00
|
|
|
this.emit("error", "Error while creating pin files");
|
2014-05-14 09:31:25 +08:00
|
|
|
} else {
|
2014-08-30 03:59:44 +08:00
|
|
|
this._openPin();
|
2014-05-14 09:31:25 +08:00
|
|
|
}
|
2014-08-30 03:59:44 +08:00
|
|
|
}.bind(this));
|
2014-05-14 09:31:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype._openPin = function() {
|
|
|
|
this._setMode(this.mode, true);
|
2014-12-16 03:15:29 +08:00
|
|
|
this.emit("open");
|
2014-05-14 09:31:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype._closeCallback = function(err) {
|
|
|
|
if (err) {
|
2014-12-16 03:15:29 +08:00
|
|
|
this.emit("error", "Error while closing pin files");
|
2014-05-14 09:31:25 +08:00
|
|
|
} else {
|
2014-12-16 03:15:29 +08:00
|
|
|
this.emit("close", this.pinNum);
|
2014-05-14 09:31:25 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
// Sets the mode for the pin by writing the values to the pin reference files
|
2014-05-14 09:31:25 +08:00
|
|
|
DigitalPin.prototype._setMode = function(mode, emitConnect) {
|
|
|
|
if (emitConnect == null) { emitConnect = false; }
|
|
|
|
|
|
|
|
this.mode = mode;
|
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
var data = (mode === "w") ? GPIO_WRITE : GPIO_READ;
|
2014-05-14 09:31:25 +08:00
|
|
|
|
|
|
|
FS.writeFile(this._directionPath(), data, function(err) {
|
2014-08-30 03:59:44 +08:00
|
|
|
this._setModeCallback(err, emitConnect);
|
|
|
|
}.bind(this));
|
2014-05-14 09:31:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype._setModeCallback = function(err, emitConnect) {
|
|
|
|
if (err) {
|
2014-12-16 03:15:29 +08:00
|
|
|
return this.emit("error", "Setting up pin direction failed");
|
2014-08-30 03:59:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
this.ready = true;
|
|
|
|
|
|
|
|
if (emitConnect) {
|
2014-12-16 03:15:29 +08:00
|
|
|
this.emit("connect", this.mode);
|
2014-05-14 09:31:25 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype._directionPath = function() {
|
|
|
|
return this._pinPath() + "/direction";
|
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype._valuePath = function() {
|
|
|
|
return this._pinPath() + "/value";
|
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype._pinPath = function() {
|
|
|
|
return GPIO_PATH + "/gpio" + this.pinNum;
|
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype._exportPath = function() {
|
|
|
|
return GPIO_PATH + "/export";
|
|
|
|
};
|
|
|
|
|
|
|
|
DigitalPin.prototype._unexportPath = function() {
|
|
|
|
return GPIO_PATH + "/unexport";
|
|
|
|
};
|