Last active
March 14, 2019 21:13
-
-
Save AlexJuarez/683fceeb995b1e779493fb871dc63c44 to your computer and use it in GitHub Desktop.
Mative ws2812b bindings wrapper.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const ws281x = require('rpi-ws281x-native'); | |
const EventEmitter = require('events'); | |
function parse(i, min, max) { | |
const num = Number(i); | |
if (isNaN((num))) { | |
return min; | |
} | |
return Math.min(max, Math.max(min, num)); | |
} | |
const DEFAULT_OPTIONS = { | |
frequency: 700000, | |
dmaNum: 10, | |
gpioPin: 18, | |
}; | |
const LED_MAX = 1000; | |
class FastPixel extends EventEmitter { | |
constructor() { | |
super(); | |
this.ledCount = 1; | |
this.pixelData = new Uint32Array(1); | |
this.brightness = 100; | |
this.timeout = null; | |
this.initalized = false; | |
} | |
setLedCount(str) { | |
const num = parse(str, 0, LED_MAX); | |
if (this.ledCount === num) { | |
return; | |
} | |
if (this.initalized) { | |
this.clearAnimation(); | |
this.pixelData = null; | |
ws281x.reset(); | |
} | |
try { | |
ws281x.init(num, DEFAULT_OPTIONS); | |
this.ledCount = num; | |
this.pixelData = new Uint32Array(num); | |
this.initalized = true; | |
} catch (e) { | |
this.emit('error', e.message); | |
} | |
} | |
setBrightness(percent) { | |
const num = parse(percent, 0, 100); | |
if (this.brightness === num) { | |
return; | |
} | |
const brightness = Math.floor(num * 255 / 100); | |
if (this.initalized) { | |
try { | |
ws281x.setBrightness(brightness); | |
this.brightness = num; | |
} catch (e) { | |
this.emit('error', e.message); | |
} | |
} | |
} | |
clearAnimation() { | |
if (this.timeout != null) { | |
clearTimeout(this.timeout); | |
this.timeout = null; | |
} | |
} | |
rgb2Int(r, g, b) { | |
return ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff); | |
} | |
setPixel(i, { r = 0, g = 0, b = 0 }) { | |
this.pixelData[i] = this.rgb2Int(r, g, b); | |
} | |
render() { | |
if (!this.initalized) { | |
return; | |
} | |
try { | |
ws281x.render(this.pixelData); | |
} catch (e) { | |
this.emit('error', e.message); | |
} | |
} | |
animate(fn, time = 1000/30) { | |
if (!this.initalized) { | |
this.emit('error', 'The driver has not been initialized.'); | |
return; | |
} | |
this.clearAnimation(); | |
const execute = () => { | |
const start = new Date(); | |
fn(this.pixelData, Math.floor(start / time)); | |
try { | |
ws281x.render(this.pixelData); | |
} catch (e) { | |
this.emit('error', e.message); | |
this.clearAnimation(); | |
} | |
const elapsed = new Date() - start; | |
if (elapsed < time) { | |
this.timeout = setTimeout(execute, time - elapsed); | |
} else { | |
this.emit('warn', `animation loop ran long ${elapsed}ms`); | |
execute(); | |
} | |
}; | |
execute(); | |
} | |
} | |
module.exports = new FastPixel(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment