1 | var Board = require("./board");
|
2 | var Emitter = require("events").EventEmitter;
|
3 | var util = require("util");
|
4 | var Collection = require("./mixins/collection");
|
5 |
|
6 | var priv = new Map();
|
7 | var modes = {
|
8 | INPUT: 0x00,
|
9 | OUTPUT: 0x01,
|
10 | ANALOG: 0x02,
|
11 | PWM: 0x03,
|
12 | SERVO: 0x04
|
13 | };
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | function Pin(opts) {
|
25 | if (!(this instanceof Pin)) {
|
26 | return new Pin(opts);
|
27 | }
|
28 | if (opts === undefined || (typeof opts === "object" &&
|
29 | opts.addr === undefined && opts.pin === undefined)) {
|
30 | throw new Error("Pins must have a pin number");
|
31 | }
|
32 |
|
33 | var pinValue = typeof opts === "object" ? (opts.addr || opts.pin || 0) : opts;
|
34 | var isAnalogInput = Pin.isAnalog(opts);
|
35 | var isDTOA = false;
|
36 |
|
37 | Board.Component.call(
|
38 | this, opts = Board.Options(opts)
|
39 | );
|
40 |
|
41 | opts.addr = opts.addr || opts.pin;
|
42 |
|
43 | if (this.io.analogPins.includes(pinValue)) {
|
44 | isAnalogInput = false;
|
45 | isDTOA = true;
|
46 | }
|
47 |
|
48 | var isPin = typeof opts !== "object";
|
49 | var addr = isDTOA ? pinValue : (isPin ? opts : opts.addr);
|
50 | var type = opts.type || (isAnalogInput ? "analog" : "digital");
|
51 |
|
52 |
|
53 | var state = {
|
54 | mode: null,
|
55 | last: null,
|
56 | value: 0
|
57 | };
|
58 |
|
59 | priv.set(this, state);
|
60 |
|
61 |
|
62 | Object.defineProperties(this, {
|
63 | type: {
|
64 | get: function() {
|
65 | return type;
|
66 | }
|
67 | },
|
68 | addr: {
|
69 | get: function() {
|
70 | return addr;
|
71 | }
|
72 | },
|
73 | value: {
|
74 | get: function() {
|
75 | return state.value;
|
76 | }
|
77 | },
|
78 | mode: {
|
79 | set: function(mode) {
|
80 | var state = priv.get(this);
|
81 | state.mode = mode;
|
82 | this.io.pinMode(this.addr, mode);
|
83 | },
|
84 | get: function() {
|
85 | return priv.get(this).mode;
|
86 | }
|
87 | }
|
88 | });
|
89 |
|
90 | this.mode = typeof opts.as !== "undefined" ? opts.as :
|
91 | (typeof opts.mode !== "undefined" ? opts.mode : (isAnalogInput ? 0x02 : 0x01));
|
92 |
|
93 | this.freq = typeof opts.freq !== "undefined" ? opts.freq : 20;
|
94 |
|
95 | if (this.mode === 0 || this.mode === 2) {
|
96 | read(this);
|
97 | }
|
98 |
|
99 | if (type === "digital") {
|
100 | Object.defineProperties(this, {
|
101 | isHigh: {
|
102 | get: function() {
|
103 | return !!state.value;
|
104 | }
|
105 | },
|
106 | isLow: {
|
107 | get: function() {
|
108 | return !state.value;
|
109 | }
|
110 | },
|
111 | });
|
112 | }
|
113 | }
|
114 |
|
115 |
|
116 | function read(pin) {
|
117 | var state = priv.get(pin);
|
118 |
|
119 | pin.io[pin.type + "Read"](pin.addr, function(data) {
|
120 | state.value = data;
|
121 | });
|
122 |
|
123 | setInterval(function() {
|
124 | var isNot, emit;
|
125 |
|
126 | isNot = state.value ? "low" : "high";
|
127 | emit = state.value ? "high" : "low";
|
128 |
|
129 | if (state.mode === modes.INPUT) {
|
130 | if (state.last === null) {
|
131 | state.last = isNot;
|
132 | }
|
133 | if (state.last === isNot) {
|
134 | state.last = emit;
|
135 | pin.emit(emit, state.value);
|
136 | pin.emit("change", state.value);
|
137 | }
|
138 | }
|
139 | pin.emit("data", state.value);
|
140 | }, pin.freq);
|
141 | }
|
142 |
|
143 | util.inherits(Pin, Emitter);
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 | Object.keys(modes).forEach(function(mode) {
|
157 | Object.defineProperty(Pin, mode, {
|
158 | value: modes[mode]
|
159 | });
|
160 | });
|
161 |
|
162 |
|
163 | Pin.isAnalog = function(opts) {
|
164 | if (typeof opts === "string" && Pin.isPrefixed(opts, ["I", "A"])) {
|
165 | return true;
|
166 | }
|
167 |
|
168 | if (typeof opts === "object") {
|
169 | return Pin.isAnalog(
|
170 | typeof opts.addr !== "undefined" ? opts.addr : opts.pin
|
171 | );
|
172 | }
|
173 | };
|
174 |
|
175 | Pin.isPrefixed = function(value, prefixes) {
|
176 | value = value[0];
|
177 |
|
178 | return prefixes.reduce(function(resolution, prefix) {
|
179 | if (!resolution) {
|
180 | return prefix === value;
|
181 | }
|
182 | return resolution;
|
183 | }, false);
|
184 | };
|
185 |
|
186 | Pin.write = function(pin, val) {
|
187 | var state = priv.get(pin);
|
188 |
|
189 | state.value = val;
|
190 |
|
191 |
|
192 |
|
193 | pin.mode = modes.OUTPUT;
|
194 |
|
195 |
|
196 | pin.io[pin.type + "Write"](pin.addr, val);
|
197 |
|
198 | pin.emit("write", null, val);
|
199 | };
|
200 |
|
201 | Pin.read = function(pin, callback) {
|
202 |
|
203 |
|
204 |
|
205 | var isChanging = false;
|
206 |
|
207 | if (pin.type === "digital" && pin.mode !== 0) {
|
208 | isChanging = true;
|
209 | pin.mode = modes.INPUT;
|
210 | }
|
211 |
|
212 | if (pin.type === "analog" && pin.mode !== 2) {
|
213 | isChanging = true;
|
214 | pin.mode = modes.ANALOG;
|
215 | }
|
216 |
|
217 | if (isChanging) {
|
218 | read(pin);
|
219 | }
|
220 |
|
221 | pin.on("data", function() {
|
222 | callback.call(pin, null, pin.value);
|
223 | });
|
224 | };
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 | Pin.prototype.query = function(callback) {
|
255 | var index = this.addr;
|
256 |
|
257 | if (this.type === "analog") {
|
258 | index = this.io.analogPins[this.addr];
|
259 | }
|
260 |
|
261 | function handler() {
|
262 | callback(this.io.pins[index]);
|
263 | }
|
264 |
|
265 | this.io.queryPinState(index, handler.bind(this));
|
266 |
|
267 | return this;
|
268 | };
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 | Pin.prototype.high = function() {
|
276 | var value = this.type === "analog" ? 255 : 1;
|
277 | Pin.write(this, value);
|
278 | this.emit("high");
|
279 | return this;
|
280 | };
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 | Pin.prototype.low = function() {
|
288 | Pin.write(this, 0);
|
289 | this.emit("low");
|
290 | return this;
|
291 | };
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 | ["read", "write"].forEach(function(operation) {
|
303 | Pin.prototype[operation] = function(valOrCallback) {
|
304 | Pin[operation](this, valOrCallback);
|
305 | return this;
|
306 | };
|
307 | });
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 | function Pins(numsOrObjects) {
|
317 | if (!(this instanceof Pins)) {
|
318 | return new Pins(numsOrObjects);
|
319 | }
|
320 |
|
321 | Object.defineProperty(this, "type", {
|
322 | value: Pin
|
323 | });
|
324 |
|
325 | Collection.call(this, numsOrObjects);
|
326 | }
|
327 |
|
328 | util.inherits(Pins, Collection);
|
329 |
|
330 | [
|
331 | "high", "low", "write"
|
332 | ].forEach(function(method) {
|
333 | Pins.prototype[method] = function() {
|
334 | var length = this.length;
|
335 |
|
336 | for (var i = 0; i < length; i++) {
|
337 | this[i][method].apply(this[i], arguments);
|
338 | }
|
339 | return this;
|
340 | };
|
341 | });
|
342 |
|
343 |
|
344 |
|
345 |
|
346 | Pin.Array = Pins;
|
347 | Pin.Collection = Pins;
|
348 |
|
349 |
|
350 | if (!!process.env.IS_TEST_MODE) {
|
351 | Pin.purge = function() {
|
352 | priv.clear();
|
353 | };
|
354 | }
|
355 |
|
356 | module.exports = Pin;
|