i2c 0.2.5 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +36 -0
- package/README.md +83 -91
- package/binding.gyp +3 -4
- package/examples/accelerometer/accel.js +72 -0
- package/examples/blinkm/blinkm.js +69 -0
- package/lib/i2c.js +147 -0
- package/main.js +2 -4
- package/package.json +7 -8
- package/src/i2c.cc +814 -230
- package/test/i2c.test.js +445 -0
- package/examples/accelerometer/accel.coffee +0 -55
- package/examples/blinkm/blinkm.coffee +0 -57
- package/lib/i2c.coffee +0 -100
package/test/i2c.test.js
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
const { describe, it, beforeEach, afterEach } = require('node:test');
|
|
2
|
+
const assert = require('node:assert/strict');
|
|
3
|
+
const I2C = require('../lib/i2c');
|
|
4
|
+
|
|
5
|
+
function createMockDevice(overrides) {
|
|
6
|
+
const noop = () => {};
|
|
7
|
+
return {
|
|
8
|
+
open: (path, cb) => setImmediate(() => cb(null)),
|
|
9
|
+
close: noop,
|
|
10
|
+
setAddress: noop,
|
|
11
|
+
scan: noop,
|
|
12
|
+
read: noop,
|
|
13
|
+
readByte: noop,
|
|
14
|
+
readBlock: noop,
|
|
15
|
+
write: noop,
|
|
16
|
+
writeByte: noop,
|
|
17
|
+
writeBlock: noop,
|
|
18
|
+
writeWord: noop,
|
|
19
|
+
// tracking
|
|
20
|
+
_calls: {},
|
|
21
|
+
...overrides,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function trackCalls(device, method) {
|
|
26
|
+
const original = device[method];
|
|
27
|
+
const calls = [];
|
|
28
|
+
device[method] = function(...args) {
|
|
29
|
+
calls.push(args);
|
|
30
|
+
return original.apply(this, args);
|
|
31
|
+
};
|
|
32
|
+
device._calls[method] = calls;
|
|
33
|
+
return calls;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createWire(address, mockDevice, options) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
function MockDeviceClass() { return mockDevice; }
|
|
39
|
+
const wire = new I2C(address, { _DeviceClass: MockDeviceClass, ...options });
|
|
40
|
+
wire.on('open', () => resolve(wire));
|
|
41
|
+
wire.on('error', reject);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('I2C', () => {
|
|
46
|
+
let wire;
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
if (wire) {
|
|
50
|
+
wire.close();
|
|
51
|
+
wire = null;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('constructor', () => {
|
|
56
|
+
it('opens the device and sets address', async () => {
|
|
57
|
+
const md = createMockDevice();
|
|
58
|
+
const openCalls = trackCalls(md, 'open');
|
|
59
|
+
const addrCalls = trackCalls(md, 'setAddress');
|
|
60
|
+
|
|
61
|
+
wire = await createWire(0x18, md);
|
|
62
|
+
assert.equal(openCalls.length, 1);
|
|
63
|
+
assert.equal(openCalls[0][0], '/dev/i2c-1');
|
|
64
|
+
assert.equal(addrCalls.length, 1);
|
|
65
|
+
assert.equal(addrCalls[0][0], 0x18);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('uses custom device path from options', async () => {
|
|
69
|
+
const md = createMockDevice();
|
|
70
|
+
const openCalls = trackCalls(md, 'open');
|
|
71
|
+
|
|
72
|
+
wire = await createWire(0x18, md, { device: '/dev/i2c-0' });
|
|
73
|
+
assert.equal(openCalls[0][0], '/dev/i2c-0');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('emits error when open fails', async () => {
|
|
77
|
+
const md = createMockDevice({
|
|
78
|
+
open: (path, cb) => setImmediate(() => cb(new Error('No device'))),
|
|
79
|
+
});
|
|
80
|
+
const addrCalls = trackCalls(md, 'setAddress');
|
|
81
|
+
|
|
82
|
+
function MockDeviceClass() { return md; }
|
|
83
|
+
const wire2 = new I2C(0x18, { _DeviceClass: MockDeviceClass });
|
|
84
|
+
const err = await new Promise((resolve) => wire2.on('error', resolve));
|
|
85
|
+
assert.equal(err.message, 'No device');
|
|
86
|
+
assert.equal(addrCalls.length, 0);
|
|
87
|
+
wire2.close();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('setAddress', () => {
|
|
92
|
+
it('updates address on both JS and native side', async () => {
|
|
93
|
+
const md = createMockDevice();
|
|
94
|
+
const addrCalls = trackCalls(md, 'setAddress');
|
|
95
|
+
|
|
96
|
+
wire = await createWire(0x18, md);
|
|
97
|
+
wire.setAddress(0x20);
|
|
98
|
+
assert.equal(wire.address, 0x20);
|
|
99
|
+
assert.equal(addrCalls.length, 2);
|
|
100
|
+
assert.equal(addrCalls[1][0], 0x20);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('close', () => {
|
|
105
|
+
it('calls native close and removes exit listener', async () => {
|
|
106
|
+
const md = createMockDevice();
|
|
107
|
+
const closeCalls = trackCalls(md, 'close');
|
|
108
|
+
|
|
109
|
+
wire = await createWire(0x18, md);
|
|
110
|
+
const listenersBefore = process.listenerCount('exit');
|
|
111
|
+
wire.close();
|
|
112
|
+
assert.equal(closeCalls.length, 1);
|
|
113
|
+
assert.equal(process.listenerCount('exit'), listenersBefore - 1);
|
|
114
|
+
wire = null;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('stops streaming on close', async () => {
|
|
118
|
+
const md = createMockDevice({
|
|
119
|
+
readBlock: (cmd, len, cb) => setImmediate(() => cb(null, Buffer.from([1]))),
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
wire = await createWire(0x18, md);
|
|
123
|
+
wire.stream(0x01, 1, 10);
|
|
124
|
+
wire.close();
|
|
125
|
+
assert.equal(wire._streaming, false);
|
|
126
|
+
assert.equal(wire._streamTimer, null);
|
|
127
|
+
wire = null;
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('scan', () => {
|
|
132
|
+
it('filters negative values from scan results', async () => {
|
|
133
|
+
const md = createMockDevice({
|
|
134
|
+
scan: (cb) => {
|
|
135
|
+
const results = new Array(128).fill(-1);
|
|
136
|
+
results[0x18] = 0x18;
|
|
137
|
+
results[0x50] = 0x50;
|
|
138
|
+
setImmediate(() => cb(null, results));
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
wire = await createWire(0x18, md);
|
|
143
|
+
const devices = await new Promise((resolve, reject) => {
|
|
144
|
+
wire.scan((err, data) => err ? reject(err) : resolve(data));
|
|
145
|
+
});
|
|
146
|
+
assert.deepEqual(devices, [0x18, 0x50]);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('write', () => {
|
|
151
|
+
it('converts array to Buffer before writing', async () => {
|
|
152
|
+
const md = createMockDevice({
|
|
153
|
+
write: (buf, cb) => setImmediate(() => cb(null)),
|
|
154
|
+
});
|
|
155
|
+
const writeCalls = trackCalls(md, 'write');
|
|
156
|
+
|
|
157
|
+
wire = await createWire(0x18, md);
|
|
158
|
+
await new Promise((resolve, reject) => {
|
|
159
|
+
wire.write([0x01, 0x02], (err) => err ? reject(err) : resolve());
|
|
160
|
+
});
|
|
161
|
+
assert.ok(Buffer.isBuffer(writeCalls[0][0]));
|
|
162
|
+
assert.deepEqual([...writeCalls[0][0]], [0x01, 0x02]);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('passes Buffer directly', async () => {
|
|
166
|
+
const md = createMockDevice({
|
|
167
|
+
write: (buf, cb) => setImmediate(() => cb(null)),
|
|
168
|
+
});
|
|
169
|
+
const writeCalls = trackCalls(md, 'write');
|
|
170
|
+
const buf = Buffer.from([0xFF]);
|
|
171
|
+
|
|
172
|
+
wire = await createWire(0x18, md);
|
|
173
|
+
await new Promise((resolve, reject) => {
|
|
174
|
+
wire.write(buf, (err) => err ? reject(err) : resolve());
|
|
175
|
+
});
|
|
176
|
+
assert.strictEqual(writeCalls[0][0], buf);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('passes error to callback', async () => {
|
|
180
|
+
const md = createMockDevice({
|
|
181
|
+
write: (buf, cb) => setImmediate(() => cb(new Error('write failed'))),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
wire = await createWire(0x18, md);
|
|
185
|
+
const err = await new Promise((resolve) => {
|
|
186
|
+
wire.write([0x01], (e) => resolve(e));
|
|
187
|
+
});
|
|
188
|
+
assert.equal(err.message, 'write failed');
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe('writeByte', () => {
|
|
193
|
+
it('writes a single byte', async () => {
|
|
194
|
+
const md = createMockDevice({
|
|
195
|
+
writeByte: (byte, cb) => setImmediate(() => cb(null)),
|
|
196
|
+
});
|
|
197
|
+
const calls = trackCalls(md, 'writeByte');
|
|
198
|
+
|
|
199
|
+
wire = await createWire(0x18, md);
|
|
200
|
+
await new Promise((resolve, reject) => {
|
|
201
|
+
wire.writeByte(0xAB, (err) => err ? reject(err) : resolve());
|
|
202
|
+
});
|
|
203
|
+
assert.equal(calls[0][0], 0xAB);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe('writeBytes', () => {
|
|
208
|
+
it('converts array to Buffer and calls writeBlock', async () => {
|
|
209
|
+
const md = createMockDevice({
|
|
210
|
+
writeBlock: (cmd, buf, cb) => setImmediate(() => cb(null)),
|
|
211
|
+
});
|
|
212
|
+
const calls = trackCalls(md, 'writeBlock');
|
|
213
|
+
|
|
214
|
+
wire = await createWire(0x18, md);
|
|
215
|
+
await new Promise((resolve, reject) => {
|
|
216
|
+
wire.writeBytes(0x10, [0x01, 0x02, 0x03], (err) => err ? reject(err) : resolve());
|
|
217
|
+
});
|
|
218
|
+
assert.equal(calls[0][0], 0x10);
|
|
219
|
+
assert.ok(Buffer.isBuffer(calls[0][1]));
|
|
220
|
+
assert.deepEqual([...calls[0][1]], [0x01, 0x02, 0x03]);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe('read', () => {
|
|
225
|
+
it('reads data from device', async () => {
|
|
226
|
+
const data = [1, 2, 3];
|
|
227
|
+
const md = createMockDevice({
|
|
228
|
+
read: (len, cb) => setImmediate(() => cb(null, data)),
|
|
229
|
+
});
|
|
230
|
+
const calls = trackCalls(md, 'read');
|
|
231
|
+
|
|
232
|
+
wire = await createWire(0x18, md);
|
|
233
|
+
const result = await new Promise((resolve, reject) => {
|
|
234
|
+
wire.read(3, (err, d) => err ? reject(err) : resolve(d));
|
|
235
|
+
});
|
|
236
|
+
assert.deepEqual(result, data);
|
|
237
|
+
assert.equal(calls[0][0], 3);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('readByte', () => {
|
|
242
|
+
it('reads a single byte', async () => {
|
|
243
|
+
const md = createMockDevice({
|
|
244
|
+
readByte: (cb) => setImmediate(() => cb(null, 0x42)),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
wire = await createWire(0x18, md);
|
|
248
|
+
const data = await new Promise((resolve, reject) => {
|
|
249
|
+
wire.readByte((err, d) => err ? reject(err) : resolve(d));
|
|
250
|
+
});
|
|
251
|
+
assert.equal(data, 0x42);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
describe('readBytes', () => {
|
|
256
|
+
it('reads a block of bytes from a register', async () => {
|
|
257
|
+
const buf = Buffer.from([0x10, 0x20, 0x30]);
|
|
258
|
+
const md = createMockDevice({
|
|
259
|
+
readBlock: (cmd, len, cb) => setImmediate(() => cb(null, buf)),
|
|
260
|
+
});
|
|
261
|
+
const calls = trackCalls(md, 'readBlock');
|
|
262
|
+
|
|
263
|
+
wire = await createWire(0x18, md);
|
|
264
|
+
const data = await new Promise((resolve, reject) => {
|
|
265
|
+
wire.readBytes(0x01, 3, (err, d) => err ? reject(err) : resolve(d));
|
|
266
|
+
});
|
|
267
|
+
assert.deepEqual(data, buf);
|
|
268
|
+
assert.equal(calls[0][0], 0x01);
|
|
269
|
+
assert.equal(calls[0][1], 3);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe('stream', () => {
|
|
274
|
+
it('emits data events repeatedly and stops with stopStream', async () => {
|
|
275
|
+
let callCount = 0;
|
|
276
|
+
const md = createMockDevice({
|
|
277
|
+
readBlock: (cmd, len, cb) => {
|
|
278
|
+
callCount++;
|
|
279
|
+
const c = callCount;
|
|
280
|
+
setImmediate(() => cb(null, Buffer.from([c])));
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
wire = await createWire(0x18, md);
|
|
285
|
+
const received = await new Promise((resolve) => {
|
|
286
|
+
const items = [];
|
|
287
|
+
wire.on('data', (evt) => {
|
|
288
|
+
items.push(evt.data[0]);
|
|
289
|
+
if (items.length === 3) {
|
|
290
|
+
wire.stopStream();
|
|
291
|
+
resolve(items);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
wire.stream(0x01, 1, 10);
|
|
295
|
+
});
|
|
296
|
+
assert.deepEqual(received, [1, 2, 3]);
|
|
297
|
+
assert.equal(wire._streaming, false);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('emits error events on read failure', async () => {
|
|
301
|
+
const md = createMockDevice({
|
|
302
|
+
readBlock: (cmd, len, cb) => {
|
|
303
|
+
setImmediate(() => cb(new Error('read error')));
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
wire = await createWire(0x18, md);
|
|
308
|
+
const err = await new Promise((resolve) => {
|
|
309
|
+
wire.on('error', (e) => {
|
|
310
|
+
wire.stopStream();
|
|
311
|
+
resolve(e);
|
|
312
|
+
});
|
|
313
|
+
wire.stream(0x01, 1, 10);
|
|
314
|
+
});
|
|
315
|
+
assert.equal(err.message, 'read error');
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('includes metadata in data events', async () => {
|
|
319
|
+
const md = createMockDevice({
|
|
320
|
+
readBlock: (cmd, len, cb) => {
|
|
321
|
+
setImmediate(() => cb(null, Buffer.from([0xFF])));
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
wire = await createWire(0x18, md);
|
|
326
|
+
const evt = await new Promise((resolve) => {
|
|
327
|
+
wire.on('data', (e) => {
|
|
328
|
+
wire.stopStream();
|
|
329
|
+
resolve(e);
|
|
330
|
+
});
|
|
331
|
+
wire.stream(0x02, 1, 10);
|
|
332
|
+
});
|
|
333
|
+
assert.equal(evt.address, 0x18);
|
|
334
|
+
assert.equal(evt.cmd, 0x02);
|
|
335
|
+
assert.equal(evt.length, 1);
|
|
336
|
+
assert.equal(typeof evt.timestamp, 'number');
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('uses default delay of 100ms when not specified', async () => {
|
|
340
|
+
const md = createMockDevice({
|
|
341
|
+
readBlock: (cmd, len, cb) => {
|
|
342
|
+
setImmediate(() => cb(null, Buffer.from([1])));
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
wire = await createWire(0x18, md);
|
|
347
|
+
wire.on('data', () => wire.stopStream());
|
|
348
|
+
wire.stream(0x01, 1);
|
|
349
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
describe('no listener leak', () => {
|
|
354
|
+
it('does not accumulate exit listeners across multiple instances', async () => {
|
|
355
|
+
const before = process.listenerCount('exit');
|
|
356
|
+
const instances = [];
|
|
357
|
+
|
|
358
|
+
for (let i = 0; i < 5; i++) {
|
|
359
|
+
const md = createMockDevice();
|
|
360
|
+
instances.push(await createWire(0x18 + i, md));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
assert.equal(process.listenerCount('exit'), before + 5);
|
|
364
|
+
|
|
365
|
+
for (const inst of instances) {
|
|
366
|
+
inst.close();
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
assert.equal(process.listenerCount('exit'), before);
|
|
370
|
+
wire = null;
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
describe('double close safety', () => {
|
|
375
|
+
it('calling close() twice does not throw', async () => {
|
|
376
|
+
const md = createMockDevice();
|
|
377
|
+
const closeCalls = trackCalls(md, 'close');
|
|
378
|
+
|
|
379
|
+
wire = await createWire(0x18, md);
|
|
380
|
+
wire.close();
|
|
381
|
+
wire.close(); // should not throw or double-remove listener
|
|
382
|
+
assert.equal(closeCalls.length, 1); // native close called only once
|
|
383
|
+
wire = null;
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
describe('double stream guard', () => {
|
|
388
|
+
it('calling stream() twice does not start parallel loops', async () => {
|
|
389
|
+
let callCount = 0;
|
|
390
|
+
const md = createMockDevice({
|
|
391
|
+
readBlock: (cmd, len, cb) => {
|
|
392
|
+
callCount++;
|
|
393
|
+
setImmediate(() => cb(null, Buffer.from([callCount])));
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
wire = await createWire(0x18, md);
|
|
398
|
+
wire.on('data', () => {}); // consume events
|
|
399
|
+
wire.stream(0x01, 1, 50);
|
|
400
|
+
wire.stream(0x01, 1, 50); // should be ignored
|
|
401
|
+
await new Promise((r) => setTimeout(r, 30));
|
|
402
|
+
wire.stopStream();
|
|
403
|
+
// If double-stream started two loops, callCount would be > 1
|
|
404
|
+
assert.equal(callCount, 1);
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
describe('scan error handling', () => {
|
|
409
|
+
it('passes error to callback without crashing on undefined data', async () => {
|
|
410
|
+
const md = createMockDevice({
|
|
411
|
+
scan: (cb) => {
|
|
412
|
+
setImmediate(() => cb(new Error('scan failed')));
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
wire = await createWire(0x18, md);
|
|
417
|
+
const err = await new Promise((resolve) => {
|
|
418
|
+
wire.scan((err) => resolve(err));
|
|
419
|
+
});
|
|
420
|
+
assert.equal(err.message, 'scan failed');
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
describe('optional callbacks', () => {
|
|
425
|
+
it('write works without callback', async () => {
|
|
426
|
+
const md = createMockDevice({
|
|
427
|
+
write: (buf, cb) => setImmediate(() => cb(null)),
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
wire = await createWire(0x18, md);
|
|
431
|
+
wire.write([0x01]);
|
|
432
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('read works without callback', async () => {
|
|
436
|
+
const md = createMockDevice({
|
|
437
|
+
read: (len, cb) => setImmediate(() => cb(null, [1])),
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
wire = await createWire(0x18, md);
|
|
441
|
+
wire.read(1);
|
|
442
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
Wire = require '../../main'
|
|
2
|
-
|
|
3
|
-
# for AK8975
|
|
4
|
-
# info: https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/AK8975/AK8975.cpp
|
|
5
|
-
# http://stackoverflow.com/questions/4768933/read-two-bytes-into-an-integer
|
|
6
|
-
|
|
7
|
-
RANGE_BWIDTH = 0x14
|
|
8
|
-
RANGE_BIT = 0x04
|
|
9
|
-
RANGE_LENGTH = 0x02
|
|
10
|
-
RANGE_2G = 0x00
|
|
11
|
-
BANDWIDTH_BIT = 0x02
|
|
12
|
-
BANDWIDTH_LENGTH = 0x03
|
|
13
|
-
BW_25HZ = 0x00
|
|
14
|
-
GET_ID = 0x00
|
|
15
|
-
|
|
16
|
-
class Accelerometer
|
|
17
|
-
|
|
18
|
-
constructor: (@address) ->
|
|
19
|
-
@wire = new Wire @address
|
|
20
|
-
|
|
21
|
-
@setRange()
|
|
22
|
-
@setBandwidth()
|
|
23
|
-
|
|
24
|
-
@wire.on 'data', (data) ->
|
|
25
|
-
console.log data
|
|
26
|
-
|
|
27
|
-
setRange: ->
|
|
28
|
-
@wire.write(RANGE_BWIDTH, [RANGE_BIT, RANGE_LENGTH, RANGE_2G], null)
|
|
29
|
-
|
|
30
|
-
testConnection: (callback) ->
|
|
31
|
-
@getDeviceID (err, data) ->
|
|
32
|
-
data[0] == 0b010
|
|
33
|
-
|
|
34
|
-
getDeviceID: (callback) ->
|
|
35
|
-
@wire.read GET_ID, 1, callback
|
|
36
|
-
|
|
37
|
-
setBandwidth: ->
|
|
38
|
-
@wire.write(RANGE_BWIDTH, [BANDWIDTH_BIT, BANDWIDTH_LENGTH, BW_25HZ], null)
|
|
39
|
-
|
|
40
|
-
getHeading: ->
|
|
41
|
-
@wire.write(0x0A, 0x1);
|
|
42
|
-
setTimeout =>
|
|
43
|
-
@wire.read 0x03, 6, (err, buffer) ->
|
|
44
|
-
pos =
|
|
45
|
-
x: ((buffer[1]) << 8) | buffer[0]
|
|
46
|
-
y: ((buffer[3]) << 8) | buffer[2]
|
|
47
|
-
z: ((buffer[5]) << 8) | buffer[4]
|
|
48
|
-
console.log pos
|
|
49
|
-
, 10
|
|
50
|
-
getMotion: ->
|
|
51
|
-
@wire.stream 0x02, 6, 100
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
accel = new Accelerometer(56)
|
|
55
|
-
accel.getHeading()
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
Wire = require 'i2c'
|
|
2
|
-
_ = require 'underscore'
|
|
3
|
-
|
|
4
|
-
# BlinkM http://thingm.com/products/blinkm
|
|
5
|
-
# firmware http://code.google.com/p/codalyze/wiki/CyzRgb
|
|
6
|
-
|
|
7
|
-
TO_RGB = 0x6e
|
|
8
|
-
GET_RGB = 0x67
|
|
9
|
-
FADE_TO_RGB = 0x63
|
|
10
|
-
FADE_TO_HSB = 0x68
|
|
11
|
-
GET_ADDRESS = 0x61
|
|
12
|
-
SET_ADDRESS = 0x41
|
|
13
|
-
SET_FADE = 0x66
|
|
14
|
-
GET_VERSION = 0x5a
|
|
15
|
-
WRITE_SCRIPT = 0x57
|
|
16
|
-
READ_SCRIPT = 0x52
|
|
17
|
-
PLAY_SCRIPT = 0x70
|
|
18
|
-
STOP_SCRIPT = 0x0f
|
|
19
|
-
|
|
20
|
-
class Pixel
|
|
21
|
-
|
|
22
|
-
address: 0x01
|
|
23
|
-
|
|
24
|
-
constructor: (@address) ->
|
|
25
|
-
@wire = new Wire(@address);
|
|
26
|
-
|
|
27
|
-
off: ->
|
|
28
|
-
@setRGB(0, 0, 0)
|
|
29
|
-
|
|
30
|
-
getAddress: (callback) ->
|
|
31
|
-
@_read GET_ADDRESS, 1, callback
|
|
32
|
-
|
|
33
|
-
getVersion: (callback) ->
|
|
34
|
-
@_read GET_VERSION, 1, callback
|
|
35
|
-
|
|
36
|
-
setFadeSpeed: (speed) ->
|
|
37
|
-
@_send SET_FADE, speed
|
|
38
|
-
|
|
39
|
-
setRGB: (r, g, b) ->
|
|
40
|
-
@_send TO_RGB, [r, g, b]
|
|
41
|
-
|
|
42
|
-
getRGB: (callback) ->
|
|
43
|
-
setTimeout =>
|
|
44
|
-
@_read GET_RGB, 3, callback
|
|
45
|
-
, 200
|
|
46
|
-
|
|
47
|
-
fadeToRGB: (r, g, b) ->
|
|
48
|
-
@_send FADE_TO_RGB, [r, g, b]
|
|
49
|
-
|
|
50
|
-
fadeToHSB: (h, s, b) ->
|
|
51
|
-
@_send FADE_TO_HSB, [h, s, b]
|
|
52
|
-
|
|
53
|
-
_send: (cmd, values) ->
|
|
54
|
-
@wire.writeBytes cmd, values
|
|
55
|
-
|
|
56
|
-
_read: (cmd, length, callback) ->
|
|
57
|
-
@wire.readBytes cmd, length, callback
|
package/lib/i2c.coffee
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
_ = require 'underscore'
|
|
2
|
-
wire = require '../build/Release/i2c'
|
|
3
|
-
EventEmitter = require('events').EventEmitter
|
|
4
|
-
tick = setImmediate || process.nextTick
|
|
5
|
-
|
|
6
|
-
class i2c extends EventEmitter
|
|
7
|
-
|
|
8
|
-
history: []
|
|
9
|
-
|
|
10
|
-
constructor: (@address, @options = {}) ->
|
|
11
|
-
_.defaults @options,
|
|
12
|
-
debug: false
|
|
13
|
-
device: "/dev/i2c-1"
|
|
14
|
-
|
|
15
|
-
if @options.debug
|
|
16
|
-
require('repl').start(
|
|
17
|
-
prompt: "i2c > "
|
|
18
|
-
).context.wire = @
|
|
19
|
-
process.stdin.emit 'data', '' # trigger repl
|
|
20
|
-
|
|
21
|
-
process.on 'exit', => @close()
|
|
22
|
-
|
|
23
|
-
@on 'data', (data) =>
|
|
24
|
-
@history.push data
|
|
25
|
-
|
|
26
|
-
@on 'error', (err) ->
|
|
27
|
-
console.log "Error: #{err}"
|
|
28
|
-
|
|
29
|
-
@open @options.device, (err) =>
|
|
30
|
-
unless err then @setAddress @address
|
|
31
|
-
|
|
32
|
-
scan: (callback) ->
|
|
33
|
-
wire.scan (err, data) ->
|
|
34
|
-
tick ->
|
|
35
|
-
callback err, _.filter data, (num) -> return num >= 0
|
|
36
|
-
|
|
37
|
-
setAddress: (address) ->
|
|
38
|
-
wire.setAddress address
|
|
39
|
-
@address = address
|
|
40
|
-
|
|
41
|
-
open: (device, callback) ->
|
|
42
|
-
wire.open device, (err) ->
|
|
43
|
-
tick ->
|
|
44
|
-
callback err
|
|
45
|
-
|
|
46
|
-
close: ->
|
|
47
|
-
wire.close()
|
|
48
|
-
|
|
49
|
-
write: (buf, callback) ->
|
|
50
|
-
@setAddress @address
|
|
51
|
-
unless Buffer.isBuffer(buf) then buf = new Buffer(buf)
|
|
52
|
-
wire.write buf, (err) ->
|
|
53
|
-
tick ->
|
|
54
|
-
callback err
|
|
55
|
-
|
|
56
|
-
writeByte: (byte, callback) ->
|
|
57
|
-
@setAddress @address
|
|
58
|
-
wire.writeByte byte, (err) ->
|
|
59
|
-
tick ->
|
|
60
|
-
callback err
|
|
61
|
-
|
|
62
|
-
writeBytes: (cmd, buf, callback) ->
|
|
63
|
-
@setAddress @address
|
|
64
|
-
unless Buffer.isBuffer(buf) then buf = new Buffer(buf)
|
|
65
|
-
wire.writeBlock cmd, buf, (err) ->
|
|
66
|
-
tick ->
|
|
67
|
-
callback err
|
|
68
|
-
|
|
69
|
-
read: (len, callback) ->
|
|
70
|
-
@setAddress @address
|
|
71
|
-
wire.read len, (err, data) ->
|
|
72
|
-
tick ->
|
|
73
|
-
callback err, data
|
|
74
|
-
|
|
75
|
-
readByte: (callback) ->
|
|
76
|
-
@setAddress @address
|
|
77
|
-
wire.readByte (err, data) ->
|
|
78
|
-
tick ->
|
|
79
|
-
callback err, data
|
|
80
|
-
|
|
81
|
-
readBytes: (cmd, len, callback) ->
|
|
82
|
-
@setAddress @address
|
|
83
|
-
wire.readBlock cmd, len, null, (err, actualBuffer) ->
|
|
84
|
-
tick ->
|
|
85
|
-
callback err, actualBuffer
|
|
86
|
-
|
|
87
|
-
stream: (cmd, len, delay = 100) ->
|
|
88
|
-
@setAddress @address
|
|
89
|
-
wire.readBlock cmd, len, delay, (err, data) =>
|
|
90
|
-
if err
|
|
91
|
-
@emit 'error', err
|
|
92
|
-
else
|
|
93
|
-
@emit 'data',
|
|
94
|
-
address : @address
|
|
95
|
-
data : data
|
|
96
|
-
cmd : cmd
|
|
97
|
-
length : len
|
|
98
|
-
timestamp : Date.now()
|
|
99
|
-
|
|
100
|
-
module.exports = i2c
|