UNPKG

johnny-five-electron

Version:

Temporary fork to support Electron (to be deprecated)

338 lines (267 loc) 6.58 kB
var IS_TEST_MODE = !!process.env.IS_TEST_MODE; var Board = require("../lib/board.js"); var Descriptor = require("descriptor"); var Emitter = require("events").EventEmitter; var util = require("util"); var Collection = require("../lib/mixins/collection"); var priv = new Map(); var modes = { INPUT: 0x00, OUTPUT: 0x01, ANALOG: 0x02, PWM: 0x03, SERVO: 0x04 }; /** * Pin * @constructor * * @description Direct Pin access objects * * @param {Object} opts Options: pin, freq, range */ function Pin(opts) { if (!(this instanceof Pin)) { return new Pin(opts); } if (opts === undefined || (typeof opts === "object" && opts.addr === undefined && opts.pin === undefined) ) { throw new Error("Pins must have a pin number"); } var pinValue = typeof opts === "object" ? (opts.addr || opts.pin || 0) : opts; var isAnalogInput = Pin.isAnalog(opts); var isDTOA = false; Board.Component.call( this, opts = Board.Options(opts) ); opts.addr = opts.addr || opts.pin; if (this.io.analogPins.includes(pinValue)) { isAnalogInput = false; isDTOA = true; } var isPin = typeof opts !== "object"; var addr = isDTOA ? pinValue : (isPin ? opts : opts.addr); var type = opts.type || (isAnalogInput ? "analog" : "digital"); // Create a private side table var state = { mode: null, last: null, value: 0 }; priv.set(this, state); // Create read-only "addr(address)" property Object.defineProperties(this, { type: new Descriptor(type), addr: new Descriptor(addr, "!writable"), value: { get: function() { return state.value; } }, mode: { set: function(mode) { var state = priv.get(this); state.mode = mode; this.io.pinMode(this.addr, mode); }, get: function() { return priv.get(this).mode; } } }); this.mode = typeof opts.as !== "undefined" ? opts.as : (typeof opts.mode !== "undefined" ? opts.mode : (isAnalogInput ? 0x02 : 0x01)); this.freq = typeof opts.freq !== "undefined" ? opts.freq : 20; if (this.mode === 0 || this.mode === 2) { read(this); } } function read(pin) { var state = priv.get(pin); pin.io[pin.type + "Read"](pin.addr, function(data) { state.value = data; }); setInterval(function() { var isNot, emit; isNot = state.value ? "low" : "high"; emit = state.value ? "high" : "low"; if (state.mode === modes.INPUT) { if (state.last === null) { state.last = isNot; } if (state.last === isNot) { state.last = emit; pin.emit(emit, state.value); pin.emit("change", state.value); } } pin.emit("data", state.value); }, pin.freq); } util.inherits(Pin, Emitter); /** * Pin.@@MODE * * Read-only constants * Pin.INPUT = 0x00 * Pin.OUTPUT = 0x01 * Pin.ANALOG = 0x02 * Pin.PWM = 0x03 * Pin.SERVO = 0x04 * */ Object.keys(modes).forEach(function(mode) { Object.defineProperty(Pin, mode, { value: modes[mode] }); }); Pin.isAnalog = function(opts) { if (typeof opts === "string" && Pin.isPrefixed(opts, ["I", "A"])) { return true; } if (typeof opts === "object") { return Pin.isAnalog( typeof opts.addr !== "undefined" ? opts.addr : opts.pin ); } }; Pin.isPrefixed = function(value, prefixes) { value = value[0]; return prefixes.reduce(function(resolution, prefix) { if (!resolution) { return prefix === value; } return resolution; }, false); }; Pin.write = function(pin, val) { var state = priv.get(pin); state.value = val; // Set the correct mode (OUTPUT) // This will only set if it needs to be set, otherwise a no-op pin.mode = modes.OUTPUT; // Create the correct type of write command pin.io[pin.type + "Write"](pin.addr, val); pin.emit("write", null, val); }; Pin.read = function(pin, callback) { // Set the correct mode (INPUT) // This will only set if it needs to be set, otherwise a no-op var isChanging = false; if (pin.type === "digital" && pin.mode !== 0) { isChanging = true; pin.mode = modes.INPUT; } if (pin.type === "analog" && pin.mode !== 2) { isChanging = true; pin.mode = modes.ANALOG; } if (isChanging) { read(pin); } pin.on("data", function() { callback.call(pin, null, pin.value); }); }; // Pin.prototype.isDigital = function() { // return this.addr > 1; // }; // Pin.prototype.isAnalog = function() { // return this.board > 1; // }; // Pin.prototype.isPWM = function() { // }; // Pin.prototype.isServo = function() { // }; // Pin.prototype.isI2C = function() { // }; // Pin.prototype.isSerial = function() { // }; // Pin.prototype.isInterrupt = function() { // }; // Pin.prototype.isVersion = function() { // }; Pin.prototype.query = function(callback) { var index = this.addr; if (this.type === "analog") { index = this.io.analogPins[this.addr]; } function handler() { callback(this.io.pins[index]); } this.io.queryPinState(index, handler.bind(this)); return this; }; /** * high Write high/1 to the pin * @return {Pin} */ Pin.prototype.high = function() { var value = this.type === "analog" ? 255 : 1; Pin.write(this, value); this.emit("high"); return this; }; /** * low Write low/0 to the pin * @return {Pin} */ Pin.prototype.low = function() { Pin.write(this, 0); this.emit("low"); return this; }; /** * read Read from the pin, value is passed to callback continuation * @return {Pin} */ /** * write Write to a pin * @return {Pin} */ ["read", "write"].forEach(function(operation) { Pin.prototype[operation] = function(valOrCallback) { Pin[operation](this, valOrCallback); return this; }; }); /** * Pins() * new Pins() * * Constructs an Array-like instance of all servos */ function Pins(numsOrObjects) { if (!(this instanceof Pins)) { return new Pins(numsOrObjects); } Object.defineProperty(this, "type", { value: Pin }); Collection.call(this, numsOrObjects); } Pins.prototype = Object.create(Collection.prototype, { constructor: { value: Pins } }); [ "high", "low", "write" ].forEach(function(method) { Pins.prototype[method] = function() { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }; }); if (IS_TEST_MODE) { Pin.purge = function() { priv.clear(); }; } // Assign Pins Collection class as static "method" of Pin. Pin.Array = Pins; module.exports = Pin;