Initial commit - working Toy Pad interaction

This commit is contained in:
Nathan Kunicki 2016-06-18 00:11:35 +01:00
commit c403ec3f2b
No known key found for this signature in database
GPG Key ID: 9083521ACC71CB15
6 changed files with 218 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea/
node_modules/

1
.npmrc Normal file
View File

@ -0,0 +1 @@
save-exact=true

10
data/minifigs.json Normal file
View File

@ -0,0 +1,10 @@
{
"47 5c 0a 6e 40 81": "Batman",
"19 a9 7a 99 40 80": "Gandalf",
"11 d3 da 98 40 81": "Wyldstyle",
"d9 e6 52 5c 49 80": "Unikitty",
"40 42 b2 2a 49 80": "Slimer",
"ed 0c 32 75 40 84": "Bane",
"d4 61 82 55 42 80": "Lloyd",
"54 60 a2 5b 49 81": "Krusty-the-Clown"
}

24
main.js Normal file
View File

@ -0,0 +1,24 @@
let ToyPad = require("./src/toypad.js");
let toyPad = new ToyPad();
toyPad.on("connect", () => {
console.log("Toy Pad connected");
toyPad.setColor(ToyPad.Panel.CENTER, 0xffff44, 0.5);
});
toyPad.on("error", () => {
console.log("Toy Pad connection error");
});
toyPad.on("add", (data) => {
let name = ToyPad.minifigNameFromSignature(data.sig);
console.log(`Minifig added to panel ${data.panel} (${name})`);
});
toyPad.on("remove", (data) => {
let name = ToyPad.minifigNameFromSignature(data.sig);
console.log(`Minifig removed from panel ${data.panel} (${name})`);
});
toyPad.connect();

14
package.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "retrodimensions",
"version": "1.0.0",
"description": "Retro Dimensions",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Nathan Kunicki <me@nathankunicki.com>",
"license": "MIT",
"dependencies": {
"node-hid": "0.5.1"
}
}

167
src/toypad.js Normal file
View File

@ -0,0 +1,167 @@
let EventEmitter = require("events").EventEmitter,
HID = require("node-hid");
const minifigData = require("../data/minifigs.json");
let Minifig = {};
Object.keys(minifigData).forEach((sig) => {
Minifig[minifigData[sig].toUpperCase().replace(/\W+/g, "_")] = sig;
});
const Action = {
ADD: 0,
REMOVE: 1
};
const Command = {
CONNECTED: 0x19,
ACTION: 0x0b
};
const Panel = {
ALL: 0,
CENTER: 1,
LEFT: 2,
RIGHT: 3
};
class ToyPad extends EventEmitter {
constructor () {
super();
this._device = null;
this._requestId = 0;
}
static get Panel () {
return Panel;
}
static get Minifig () {
return Minifig;
}
static minifigNameFromSignature (sig) {
if (minifigData[sig]) {
return minifigData[sig];
} else {
return `Unknown - ${sig}`;
}
}
static _bufferToHexString (buf) {
let str = "";
for (let i = 0; i < buf.length; i++) {
str +=
((buf[i] >> 4) & 0xf).toString(16) +
(buf[i] & 0xf).toString(16) +
" ";
}
return str.trim();
}
static _checksum (data) {
let checksum = 0;
for (let i = 0; i < data.length; i++) {
checksum += data[i];
}
data.push(checksum & 0xFF);
return data;
}
static _pad (data) {
while (data.length < 32) {
data.push(0x00);
}
return data;
}
connect () {
try {
this._device = new HID.HID(3695, 577);
this._device.on("data", (data) => {
let cmd = data[1];
if (cmd == Command.CONNECTED) {
this.emit("connect");
} else if (cmd == Command.ACTION) {
let action = data[5];
let emitPayload = {
panel: data[2],
sig: ToyPad._bufferToHexString(data.slice(7, 13))
};
if (action == Action.ADD) {
this.emit("add", emitPayload);
} else if (action == Action.REMOVE) {
this.emit("remove", emitPayload);
}
}
});
this._device.on("error", (err) => {
this.emit(err);
});
// Wake the Toy Pad
this._device.write([0x00,
0x55, 0x0f, 0xb0, 0x01,
0x28, 0x63, 0x29, 0x20,
0x4c, 0x45, 0x47, 0x4f,
0x20, 0x32, 0x30, 0x31,
0x34, 0xf7, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00]);
} catch (err) {
this.emit("error");
}
}
setColor (panel, color, speed = 1) {
let data = [
this._requestId & 0xff,
panel,
((1 - speed) * 0xff) & 0xff,
0x01, (color >> 16) & 0xff,
(color >> 8) & 0xff,
color & 0xff
];
this._requestId++;
this._write([0x55, 0x08, 0xc2].concat(data));
};
_write (data) {
this._device.write([0x00].concat(ToyPad._pad(ToyPad._checksum(data))));
}
}
module.exports = ToyPad;