Initial commit - working Toy Pad interaction
This commit is contained in:
commit
c403ec3f2b
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.idea/
|
||||
node_modules/
|
10
data/minifigs.json
Normal file
10
data/minifigs.json
Normal 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
24
main.js
Normal 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
14
package.json
Normal 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
167
src/toypad.js
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user