UNPKG

6.4 kBJavaScriptView Raw
1var Board = require("./board");
2var Emitter = require("events").EventEmitter;
3var util = require("util");
4var Fn = require("./fn");
5var priv = new Map();
6var axes = ["x", "y"];
7
8function Multiplexer(options) {
9 this.pins = options.pins;
10 this.io = options.io;
11
12 // Setup these "analog" pins as digital output.
13 this.io.pinMode(this.pins[0], this.io.MODES.OUTPUT);
14 this.io.pinMode(this.pins[1], this.io.MODES.OUTPUT);
15 this.io.pinMode(this.pins[2], this.io.MODES.OUTPUT);
16 this.io.pinMode(this.pins[3], this.io.MODES.OUTPUT);
17}
18
19Multiplexer.prototype.select = function(channel) {
20 this.io.digitalWrite(this.pins[0], channel & 1 ? this.io.HIGH : this.io.LOW);
21 this.io.digitalWrite(this.pins[1], channel & 2 ? this.io.HIGH : this.io.LOW);
22 this.io.digitalWrite(this.pins[2], channel & 4 ? this.io.HIGH : this.io.LOW);
23 this.io.digitalWrite(this.pins[3], channel & 8 ? this.io.HIGH : this.io.LOW);
24};
25
26var Controllers = {
27 ANALOG: {
28 initialize: {
29 value: function(opts, dataHandler) {
30 var axisValues = {
31 x: null,
32 y: null
33 };
34
35 opts.pins.forEach(function(pin, index) {
36 this.io.pinMode(pin, this.io.MODES.ANALOG);
37 this.io.analogRead(pin, function(value) {
38 axisValues[axes[index]] = value;
39
40 if (axisValues.x !== null && axisValues.y !== null) {
41 dataHandler({
42 x: axisValues.x,
43 y: axisValues.y
44 });
45
46 axisValues.x = null;
47 axisValues.y = null;
48 }
49 }.bind(this));
50 }, this);
51 }
52 },
53 toAxis: {
54 value: function(raw, axis) {
55 var state = priv.get(this);
56 return Fn.constrain(Fn.fscale(raw - state[axis].zeroV, -511, 511, -1, 1), -1, 1);
57 }
58 }
59 },
60 ESPLORA: {
61 initialize: {
62 value: function(opts, dataHandler) {
63 // References:
64 //
65 // https://github.com/arduino/Arduino/blob/master/libraries/Esplora/src/Esplora.h
66 // https://github.com/arduino/Arduino/blob/master/libraries/Esplora/src/Esplora.cpp
67 //
68 var multiplexer = new Multiplexer({
69 // Since Multiplexer uses digitalWrite,
70 // we have to send the analog pin numbers
71 // in their "digital" pin order form.
72 pins: [18, 19, 20, 21],
73 io: this.io
74 });
75 var channels = [11, 12];
76 var index = 1;
77 var axisValues = {
78 x: null,
79 y: null
80 };
81
82 this.io.pinMode(4, this.io.MODES.ANALOG);
83
84 var handler = function(value) {
85 axisValues[axes[index]] = value;
86
87 if (axisValues.x !== null && axisValues.y !== null) {
88 dataHandler({
89 x: axisValues.x,
90 y: axisValues.y
91 });
92
93 axisValues.x = null;
94 axisValues.y = null;
95 }
96
97 // Remove this handler to all the multiplexer
98 // to setup the next pin for the next read.
99 this.io.removeListener("analog-read-4", handler);
100
101 setTimeout(read, 10);
102 }.bind(this);
103
104 var read = function() {
105 multiplexer.select(channels[index ^= 1]);
106 this.io.analogRead(4, handler);
107 }.bind(this);
108
109 read();
110 }
111 },
112 toAxis: {
113 value: function(raw, axis) {
114 var state = priv.get(this);
115 return Fn.constrain(Fn.fscale(raw - state[axis].zeroV, -511, 511, -1, 1), -1, 1);
116 }
117 }
118 }
119};
120
121
122/**
123 * Joystick
124 * @constructor
125 *
126 * five.Joystick([ x, y[, z] ]);
127 *
128 * five.Joystick({
129 * pins: [ x, y[, z] ]
130 * freq: ms
131 * });
132 *
133 *
134 * @param {Object} opts [description]
135 *
136 */
137function Joystick(opts) {
138 if (!(this instanceof Joystick)) {
139 return new Joystick(opts);
140 }
141
142 var controller = null;
143
144 var state = {
145 x: {
146 invert: false,
147 value: 0,
148 previous: 0,
149 zeroV: 0,
150 calibrated: false
151 },
152 y: {
153 invert: false,
154 value: 0,
155 previous: 0,
156 zeroV: 0,
157 calibrated: false
158 }
159 };
160
161 Board.Component.call(
162 this, opts = Board.Options(opts)
163 );
164
165 if (opts.controller && typeof opts.controller === "string") {
166 controller = Controllers[opts.controller.toUpperCase()];
167 } else {
168 controller = opts.controller;
169 }
170
171 if (controller == null) {
172 controller = Controllers.ANALOG;
173 }
174
175 Board.Controller.call(this, controller, opts);
176
177 if (!this.toAxis) {
178 this.toAxis = opts.toAxis || function(raw) {
179 return raw;
180 };
181 }
182
183 state.x.zeroV = opts.zeroV === undefined ? 0 : (opts.zeroV.x || 0);
184 state.y.zeroV = opts.zeroV === undefined ? 0 : (opts.zeroV.y || 0);
185
186 state.x.invert = opts.invertX || opts.invert || false;
187 state.y.invert = opts.invertY || opts.invert || false;
188
189 priv.set(this, state);
190
191 if (typeof this.initialize === "function") {
192 this.initialize(opts, function(data) {
193 var isChange = false;
194 var computed = {
195 x: null,
196 y: null
197 };
198
199 Object.keys(data).forEach(function(axis) {
200 var value = data[axis];
201 var sensor = state[axis];
202
203 // Set the internal ADC reading value...
204 sensor.value = value;
205
206 if (!state[axis].calibrated) {
207 state[axis].calibrated = true;
208 state[axis].zeroV = value;
209 isChange = true;
210 }
211
212 // ... Get the computed axis value.
213 computed[axis] = this[axis];
214
215 var absAxis = Math.abs(computed[axis]);
216 var absPAxis = Math.abs(sensor.previous);
217
218 if ((absAxis < absPAxis) ||
219 (absAxis > absPAxis)) {
220 isChange = true;
221 }
222
223 sensor.previous = computed[axis];
224 }, this);
225
226 this.emit("data", {
227 x: computed.x,
228 y: computed.y
229 });
230
231 if (isChange) {
232 this.emit("change", {
233 x: computed.x,
234 y: computed.y
235 });
236 }
237 }.bind(this));
238 }
239
240 Object.defineProperties(this, {
241 x: {
242 get: function() {
243 return this.toAxis(state.x.value, "x") * (state.x.invert ? -1 : 1);
244 }
245 },
246 y: {
247 get: function() {
248 return this.toAxis(state.y.value, "y") * (state.y.invert ? -1 : 1);
249 }
250 }
251 });
252}
253
254util.inherits(Joystick, Emitter);
255
256/* istanbul ignore else */
257if (!!process.env.IS_TEST_MODE) {
258 Joystick.Controllers = Controllers;
259 Joystick.purge = function() {
260 priv.clear();
261 };
262}
263
264module.exports = Joystick;