rpi-ws281x
Version:
149 lines (113 loc) • 3.42 kB
JavaScript
var path = require('path');
//var addon = require(path.join(__dirname, 'build', 'Release', 'rpi-ws281x.node'));
var addon = require('bindings')('rpi-ws281x.node');
class Module {
constructor() {
this.map = undefined;
this.leds = undefined;
function cleanup() {
addon.reset();
process.exit();
}
process.on('SIGUSR1', cleanup);
process.on('SIGUSR2', cleanup);
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
}
configure(options) {
var { width, height, map, gamma, leds, ...options } = options;
this.leds = undefined;
this.map = undefined;
this.gamma = gamma;
if (width != undefined || height != undefined) {
if (width == undefined) {
throw new Error('Must specify width if height is specified.');
}
if (height == undefined) {
throw new Error('Must specify height if width is specified.');
}
if (leds != undefined) {
throw new Error('Please do not specify leds when both width and height are specified.');
}
leds = width * height;
if (map) {
if (map instanceof Uint32Array) {
if (map.length != leds) {
throw new Error('Pixel mapping array must be of the same size as the number of leds.');
}
this.map = map;
} else {
if (typeof map == 'string') {
if (map == 'alternating-matrix') {
map = new Uint32Array(width * height);
for (var i = 0; i < map.length; i++) {
var row = Math.floor(i / width),
col = i % width;
if (row % 2 === 0) {
map[i] = i;
} else {
map[i] = (row + 1) * width - (col + 1);
}
}
this.map = map;
}
}
}
}
}
// Make sure the number of leds are specified
if (leds == undefined) {
throw new Error('Number of leds must be defined. Either by leds or by width and height.');
}
this.leds = leds;
addon.configure({ ...options, leds: leds });
}
reset() {
if (this.leds == undefined) {
throw new Error('ws281x not configured.');
}
addon.reset();
}
sleep(ms) {
addon.sleep(ms);
}
render(pixels) {
let gammaCorrect = pixels => {
let gamma = this.gamma;
if (gamma == undefined) {
return pixels;
}
const output = new Uint32Array(pixels.length);
for (let i = 0; i < pixels.length; i++) {
const rgb = pixels[i] >>> 0; // 0xRRGGBB
const r1 = (rgb >>> 16) & 0xff;
const g1 = (rgb >>> 8) & 0xff;
const b1 = (rgb >>> 0) & 0xff;
const r2 = Math.min(255, Math.round(Math.pow(r1 / 255, gamma) * 255));
const g2 = Math.min(255, Math.round(Math.pow(g1 / 255, gamma) * 255));
const b2 = Math.min(255, Math.round(Math.pow(b1 / 255, gamma) * 255));
output[i] = ((r2 << 16) | (g2 << 8) | b2) >>> 0;
}
return output;
};
if (this.leds == undefined) {
throw new Error('ws281x not configured.');
}
if (!(pixels instanceof Uint32Array)) {
throw new Error('Pixels must be of type Uint32Array in render()');
}
if (this.leds != pixels.length) {
throw new Error('Pixels must be of same length as number of leds in render()');
}
if (this.map && this.map instanceof Uint32Array) {
var mapped = new Uint32Array(this.map.length);
for (var i = 0; i < mapped.length; i++) {
mapped[i] = pixels[this.map[i]];
}
addon.render(gammaCorrect(mapped));
} else {
addon.render(gammaCorrect(pixels));
}
}
}
module.exports = new Module();