Fresh pull from upstream (stable) package feed
[librecmc/package-feed.git] / lang / node-arduino-firmata / files / usr / lib / node / arduino-firmata / lib / arduino-firmata.js
1 (function() {
2   'use strict';
3   var ArduinoFirmata, SerialPort, debug, events, exports, serialport,
4     extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
5     hasProp = {}.hasOwnProperty;
6
7   events = require('eventemitter2');
8
9   SerialPort = (serialport = require('serialport')).SerialPort;
10
11   debug = require('debug')('arduino-firmata');
12
13   exports = module.exports = ArduinoFirmata = (function(superClass) {
14     extend(ArduinoFirmata, superClass);
15
16     ArduinoFirmata.Status = {
17       CLOSE: 0,
18       OPEN: 1
19     };
20
21     ArduinoFirmata.INPUT = 0;
22
23     ArduinoFirmata.OUTPUT = 1;
24
25     ArduinoFirmata.ANALOG = 2;
26
27     ArduinoFirmata.PWM = 3;
28
29     ArduinoFirmata.SERVO = 4;
30
31     ArduinoFirmata.SHIFT = 5;
32
33     ArduinoFirmata.I2C = 6;
34
35     ArduinoFirmata.LOW = 0;
36
37     ArduinoFirmata.HIGH = 1;
38
39     ArduinoFirmata.MAX_DATA_BYTES = 32;
40
41     ArduinoFirmata.DIGITAL_MESSAGE = 0x90;
42
43     ArduinoFirmata.ANALOG_MESSAGE = 0xE0;
44
45     ArduinoFirmata.REPORT_ANALOG = 0xC0;
46
47     ArduinoFirmata.REPORT_DIGITAL = 0xD0;
48
49     ArduinoFirmata.SET_PIN_MODE = 0xF4;
50
51     ArduinoFirmata.REPORT_VERSION = 0xF9;
52
53     ArduinoFirmata.SYSTEM_RESET = 0xFF;
54
55     ArduinoFirmata.START_SYSEX = 0xF0;
56
57     ArduinoFirmata.END_SYSEX = 0xF7;
58
59     ArduinoFirmata.list = function(callback) {
60       return serialport.list(function(err, ports) {
61         var devices, j, len, port;
62         if (err) {
63           return callback(err);
64         }
65         devices = [];
66         for (j = 0, len = ports.length; j < len; j++) {
67           port = ports[j];
68           if (/usb|acm|com\d+/i.test(port.comName)) {
69             devices.push(port.comName);
70           }
71         }
72         return callback(null, devices);
73       });
74     };
75
76     function ArduinoFirmata() {
77       this.status = ArduinoFirmata.Status.CLOSE;
78       this.wait_for_data = 0;
79       this.execute_multi_byte_command = 0;
80       this.multi_byte_channel = 0;
81       this.stored_input_data = [];
82       this.parsing_sysex = false;
83       this.sysex_bytes_read = 0;
84       this.digital_output_data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
85       this.digital_input_data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
86       this.analog_input_data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
87       this.boardVersion = null;
88     }
89
90     ArduinoFirmata.prototype.isOldArduinoDevice = function() {
91       return /usbserial|USB/.test(this.serialport_name);
92     };
93
94     ArduinoFirmata.prototype.connect = function(serialport_name, opts) {
95       this.serialport_name = serialport_name;
96       if (opts == null) {
97         opts = {
98           baudrate: 57600
99         };
100       }
101       opts.parser = serialport.parsers.raw;
102       if (!this.serialport_name) {
103         ArduinoFirmata.list((function(_this) {
104           return function(err, devices) {
105             return _this.connect(devices[0], opts);
106           };
107         })(this));
108         return this;
109       }
110       this.once('boardReady', function() {
111         var io_init_wait;
112         debug('boardReady');
113         io_init_wait = this.isOldArduinoDevice() ? (debug("old arduino device found " + this.serialport_name), 3000) : (debug("new arduino device found " + this.serialport_name), 100);
114         debug("wait " + io_init_wait + "(msec)");
115         return setTimeout((function(_this) {
116           return function() {
117             var i, j, k;
118             for (i = j = 0; j < 6; i = ++j) {
119               _this.write([ArduinoFirmata.REPORT_ANALOG | i, 1]);
120             }
121             for (i = k = 0; k < 2; i = ++k) {
122               _this.write([ArduinoFirmata.REPORT_DIGITAL | i, 1]);
123             }
124             debug('init IO ports');
125             return _this.emit('connect');
126           };
127         })(this), io_init_wait);
128       });
129       this.serialport = new SerialPort(this.serialport_name, opts);
130       this.serialport.once('open', (function(_this) {
131         return function() {
132           var cid;
133           cid = setInterval(function() {
134             debug('request REPORT_VERSION');
135             return _this.write([ArduinoFirmata.REPORT_VERSION]);
136           }, 500);
137           _this.once('boardVersion', function(version) {
138             clearInterval(cid);
139             _this.status = ArduinoFirmata.Status.OPEN;
140             return _this.emit('boardReady');
141           });
142           return _this.serialport.on('data', function(data) {
143             var byte, j, len, results;
144             results = [];
145             for (j = 0, len = data.length; j < len; j++) {
146               byte = data[j];
147               results.push(_this.process_input(byte));
148             }
149             return results;
150           });
151         };
152       })(this));
153       return this;
154     };
155
156     ArduinoFirmata.prototype.isOpen = function() {
157       return this.status === ArduinoFirmata.Status.OPEN;
158     };
159
160     ArduinoFirmata.prototype.close = function(callback) {
161       this.status = ArduinoFirmata.Status.CLOSE;
162       return this.serialport.close(callback);
163     };
164
165     ArduinoFirmata.prototype.reset = function(callback) {
166       return this.write([ArduinoFirmata.SYSTEM_RESET], callback);
167     };
168
169     ArduinoFirmata.prototype.write = function(bytes, callback) {
170       return this.serialport.write(bytes, callback);
171     };
172
173     ArduinoFirmata.prototype.sysex = function(command, data, callback) {
174       var write_data;
175       if (data == null) {
176         data = [];
177       }
178       data = data.map(function(i) {
179         return i & 0x7f;
180       });
181       write_data = [ArduinoFirmata.START_SYSEX, command].concat(data, [ArduinoFirmata.END_SYSEX]);
182       return this.write(write_data, callback);
183     };
184
185     ArduinoFirmata.prototype.pinMode = function(pin, mode, callback) {
186       switch (mode) {
187         case true:
188           mode = ArduinoFirmata.OUTPUT;
189           break;
190         case false:
191           mode = ArduinoFirmata.INPUT;
192       }
193       return this.write([ArduinoFirmata.SET_PIN_MODE, pin, mode], callback);
194     };
195
196     ArduinoFirmata.prototype.digitalWrite = function(pin, value, callback) {
197       var port_num;
198       this.pinMode(pin, ArduinoFirmata.OUTPUT);
199       port_num = (pin >>> 3) & 0x0F;
200       if (value === 0 || value === false) {
201         this.digital_output_data[port_num] &= ~(1 << (pin & 0x07));
202       } else {
203         this.digital_output_data[port_num] |= 1 << (pin & 0x07);
204       }
205       return this.write([ArduinoFirmata.DIGITAL_MESSAGE | port_num, this.digital_output_data[port_num] & 0x7F, this.digital_output_data[port_num] >>> 7], callback);
206     };
207
208     ArduinoFirmata.prototype.analogWrite = function(pin, value, callback) {
209       value = Math.floor(value);
210       this.pinMode(pin, ArduinoFirmata.PWM);
211       return this.write([ArduinoFirmata.ANALOG_MESSAGE | (pin & 0x0F), value & 0x7F, value >>> 7], callback);
212     };
213
214     ArduinoFirmata.prototype.servoWrite = function(pin, angle, callback) {
215       this.pinMode(pin, ArduinoFirmata.SERVO);
216       return this.write([ArduinoFirmata.ANALOG_MESSAGE | (pin & 0x0F), angle & 0x7F, angle >>> 7], callback);
217     };
218
219     ArduinoFirmata.prototype.digitalRead = function(pin) {
220       return ((this.digital_input_data[pin >>> 3] >>> (pin & 0x07)) & 0x01) > 0;
221     };
222
223     ArduinoFirmata.prototype.analogRead = function(pin) {
224       return this.analog_input_data[pin];
225     };
226
227     ArduinoFirmata.prototype.process_input = function(input_data) {
228       var analog_value, command, diff, i, j, old_analog_value, results, stat, sysex_command, sysex_data;
229       if (this.parsing_sysex) {
230         if (input_data === ArduinoFirmata.END_SYSEX) {
231           this.parsing_sysex = false;
232           sysex_command = this.stored_input_data[0];
233           sysex_data = this.stored_input_data.slice(1, this.sysex_bytes_read);
234           return this.emit('sysex', {
235             command: sysex_command,
236             data: sysex_data
237           });
238         } else {
239           this.stored_input_data[this.sysex_bytes_read] = input_data;
240           return this.sysex_bytes_read += 1;
241         }
242       } else if (this.wait_for_data > 0 && input_data < 128) {
243         this.wait_for_data -= 1;
244         this.stored_input_data[this.wait_for_data] = input_data;
245         if (this.execute_multi_byte_command !== 0 && this.wait_for_data === 0) {
246           switch (this.execute_multi_byte_command) {
247             case ArduinoFirmata.DIGITAL_MESSAGE:
248               input_data = (this.stored_input_data[0] << 7) + this.stored_input_data[1];
249               diff = this.digital_input_data[this.multi_byte_channel] ^ input_data;
250               this.digital_input_data[this.multi_byte_channel] = input_data;
251               if (this.listeners('digitalChange').length > 0) {
252                 results = [];
253                 for (i = j = 0; j <= 13; i = ++j) {
254                   if (((0x01 << i) & diff) > 0) {
255                     stat = (input_data & diff) > 0;
256                     results.push(this.emit('digitalChange', {
257                       pin: i + this.multi_byte_channel * 8,
258                       value: stat,
259                       old_value: !stat
260                     }));
261                   } else {
262                     results.push(void 0);
263                   }
264                 }
265                 return results;
266               }
267               break;
268             case ArduinoFirmata.ANALOG_MESSAGE:
269               analog_value = (this.stored_input_data[0] << 7) + this.stored_input_data[1];
270               old_analog_value = this.analogRead(this.multi_byte_channel);
271               this.analog_input_data[this.multi_byte_channel] = analog_value;
272               if (old_analog_value !== analog_value) {
273                 return this.emit('analogChange', {
274                   pin: this.multi_byte_channel,
275                   value: analog_value,
276                   old_value: old_analog_value
277                 });
278               }
279               break;
280             case ArduinoFirmata.REPORT_VERSION:
281               this.boardVersion = this.stored_input_data[1] + "." + this.stored_input_data[0];
282               return this.emit('boardVersion', this.boardVersion);
283           }
284         }
285       } else {
286         if (input_data < 0xF0) {
287           command = input_data & 0xF0;
288           this.multi_byte_channel = input_data & 0x0F;
289         } else {
290           command = input_data;
291         }
292         if (command === ArduinoFirmata.START_SYSEX) {
293           this.parsing_sysex = true;
294           return this.sysex_bytes_read = 0;
295         } else if (command === ArduinoFirmata.DIGITAL_MESSAGE || command === ArduinoFirmata.ANALOG_MESSAGE || command === ArduinoFirmata.REPORT_VERSION) {
296           this.wait_for_data = 2;
297           return this.execute_multi_byte_command = command;
298         }
299       }
300     };
301
302     return ArduinoFirmata;
303
304   })(events.EventEmitter2);
305
306 }).call(this);