johnny-five-electron
Version:
Temporary fork to support Electron (to be deprecated)
256 lines (215 loc) • 6.35 kB
JavaScript
var Board = require("../lib/board");
var Emitter = require("events").EventEmitter;
var util = require("util");
var __ = require("../lib/fn");
var priv = new Map();
var axes = ["x", "y"];
function Multiplexer(options) {
this.pins = options.pins;
this.io = options.io;
// Setup these "analog" pins as digital output.
this.io.pinMode(this.pins[0], this.io.MODES.OUTPUT);
this.io.pinMode(this.pins[1], this.io.MODES.OUTPUT);
this.io.pinMode(this.pins[2], this.io.MODES.OUTPUT);
this.io.pinMode(this.pins[3], this.io.MODES.OUTPUT);
}
Multiplexer.prototype.select = function(channel) {
this.io.digitalWrite(this.pins[0], channel & 1 ? this.io.HIGH : this.io.LOW);
this.io.digitalWrite(this.pins[1], channel & 2 ? this.io.HIGH : this.io.LOW);
this.io.digitalWrite(this.pins[2], channel & 4 ? this.io.HIGH : this.io.LOW);
this.io.digitalWrite(this.pins[3], channel & 8 ? this.io.HIGH : this.io.LOW);
};
var Controllers = {
ANALOG: {
initialize: {
value: function(opts, dataHandler) {
var axisValues = {
x: null,
y: null
};
opts.pins.forEach(function(pin, index) {
this.io.pinMode(pin, this.io.MODES.ANALOG);
this.io.analogRead(pin, function(value) {
axisValues[axes[index]] = value;
if (axisValues.x !== null && axisValues.y !== null) {
dataHandler({
x: axisValues.x,
y: axisValues.y
});
axisValues.x = null;
axisValues.y = null;
}
}.bind(this));
}, this);
}
},
toAxis: {
value: function(raw, axis) {
var state = priv.get(this);
return __.constrain(__.fscale(raw - state[axis].zeroV, -511, 511, -1, 1), -1, 1);
}
}
},
ESPLORA: {
initialize: {
value: function(opts, dataHandler) {
// References:
//
// https://github.com/arduino/Arduino/blob/master/libraries/Esplora/src/Esplora.h
// https://github.com/arduino/Arduino/blob/master/libraries/Esplora/src/Esplora.cpp
//
var multiplexer = new Multiplexer({
// Since Multiplexer uses digitalWrite,
// we have to send the analog pin numbers
// in their "digital" pin order form.
pins: [ 18, 19, 20, 21 ],
io: this.io
});
var channels = [ 11, 12 ];
var index = 1;
var axisValues = {
x: null,
y: null
};
this.io.pinMode(4, this.io.MODES.ANALOG);
var handler = function(value) {
axisValues[axes[index]] = value;
if (axisValues.x !== null && axisValues.y !== null) {
dataHandler({
x: axisValues.x,
y: axisValues.y
});
axisValues.x = null;
axisValues.y = null;
}
// Remove this handler to all the multiplexer
// to setup the next pin for the next read.
this.io.removeListener("analog-read-4", handler);
setTimeout(read, 10);
}.bind(this);
var read = function() {
multiplexer.select(channels[index ^= 1]);
this.io.analogRead(4, handler);
}.bind(this);
read();
}
},
toAxis: {
value: function(raw, axis) {
var state = priv.get(this);
return __.constrain(__.fscale(raw - state[axis].zeroV, -511, 511, -1, 1), -1, 1);
}
}
}
};
/**
* Joystick
* @constructor
*
* five.Joystick([ x, y[, z] ]);
*
* five.Joystick({
* pins: [ x, y[, z] ]
* freq: ms
* });
*
*
* @param {Object} opts [description]
*
*/
function Joystick(opts) {
if (!(this instanceof Joystick)) {
return new Joystick(opts);
}
var controller = null;
var state = {
x: {
invert: false,
value: 0,
previous: 0,
zeroV: 0,
calibrated: false
},
y: {
invert: false,
value: 0,
previous: 0,
zeroV: 0,
calibrated: false
}
};
Board.Component.call(
this, opts = Board.Options(opts)
);
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
controller = Controllers["ANALOG"];
}
Object.defineProperties(this, controller);
if (!this.toAxis) {
this.toAxis = opts.toAxis || function(raw) { return raw; };
}
this.threshold = opts.threshold === undefined ? 0.01 : opts.threshold;
state.x.zeroV = opts.zeroV === undefined ? 0 : (opts.zeroV.x || 0);
state.y.zeroV = opts.zeroV === undefined ? 0 : (opts.zeroV.y || 0);
state.x.invert = opts.invertX || opts.invert || false;
state.y.invert = opts.invertY || opts.invert || false;
priv.set(this, state);
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
var isChange = false;
var computed = {
x: null,
y: null
};
Object.keys(data).forEach(function(axis) {
var value = data[axis];
var sensor = state[axis];
// Set the internal ADC reading value...
sensor.value = value;
if (!state[axis].calibrated) {
state[axis].calibrated = true;
state[axis].zeroV = value;
isChange = true;
}
// ... Get the computed axis value.
computed[axis] = this[axis];
var absAxis = Math.abs(computed[axis]);
var absPAxis = Math.abs(sensor.previous);
if ((absAxis < absPAxis - this.threshold) ||
(absAxis > absPAxis + this.threshold)) {
isChange = true;
}
sensor.previous = computed[axis];
}, this);
this.emit("data", {
x: computed.x,
y: computed.y
});
if (isChange) {
this.emit("change", {
x: computed.x,
y: computed.y
});
}
}.bind(this));
}
Object.defineProperties(this, {
x: {
get: function() {
return this.toAxis(state.x.value, "x") * (state.x.invert ? -1 : 1);
}
},
y: {
get: function() {
return this.toAxis(state.y.value, "y") * (state.y.invert ? -1 : 1);
}
}
});
}
util.inherits(Joystick, Emitter);
module.exports = Joystick;