-
Notifications
You must be signed in to change notification settings - Fork 8
/
index.js
158 lines (147 loc) · 5.18 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
var fs = require('fs'),
microtime = require('microtime'),
nanotimer = require('nanotimer')
function LedStripe(){
this.spiDevice = '/dev/spidev0.0';
this.numLEDs = 23;
this.spiFd = null; //filedescriptor for spidevice
this.gamma = 2.5;
this.gammatable = new Array(256);
this.bytePerPixel = 3; //RGB
this.rowResetTime = 1000; // number of us CLK has to be pulled low (=no writes) for frame reset
// manual of WS2801 says 500 is enough, however we need at least 1000
this.lastWriteTime = microtime.now()-this.rowResetTime-1; //last time something was written to SPI
//required for save WS2801 reset
this.sendRgbBuf = null; //function for writing to stripe, depends on stripe type
}
LedStripe.prototype = {
/*
* connect to SPI port
*/
connect: function(numLEDs,stripeType,spiDevice, gamma){
// sanity check for params
if ((numLEDs !== parseInt(numLEDs)) || (numLEDs<1)) {
console.error("invalid param for number of LEDs, plz use integer >0");
return false;
}
if ((stripeType != 'WS2801') && (stripeType != 'LPD8806')){
console.error("invalid param for stripe type, only WS2801 and LPD8806 are suported");
return false;
}
if (spiDevice) this.spiDevice = spiDevice;
// connect synchronously
try{
this.spiFd = fs.openSync(this.spiDevice, 'w');
} catch (err) {
console.error("error opening SPI device "+this.spiDevice, err);
return false;
}
this.sendRgbBuf = (stripeType == 'WS2801') ? this.sendRgbBufWS2801 : this.sendRgbBufLPD8806;
this.numLEDs = numLEDs;
this.gamma = gamma ? gamma : 2.5; //set gamma correction value
// compute gamma correction table
for (var i=0; i<256; i++)
this.gammatable[i] = Math.round(255*Math.pow(i/255, this.gamma));
//console.log("gammatable" + this.gammatable);
},
/*
* disconnect from SPI port
*/
disconnect : function(){
if (this.spiFd) fs.closeSync(this.spiFd);
},
sendRgbBufLPD8806 : function(buffer){
var bufSize = this.numLEDs * this.bytePerPixel;
if (buffer.length != bufSize) {
console.log ("buffer length (" + buffer.lenght +" byte) does not match LED stripe size ("+
this.numLEDs + " LEDs x " + this.bytePerPixel + " colors)");
return;
} // end if (buffer.length != bufSize)
if (this.spiFd) {
var numLeadingZeros = Math.ceil(this.numLEDs / 32); //number of zeros to "reset" LPD8806 stripe
// mind the last zero byte for latching the last blue LED
var aBuf = new Buffer (numLeadingZeros + bufSize + 1);
// prime the stripe with zeros
for (var i=0; i<numLeadingZeros; i++){
aBuf[i] =0x00;
};
// transform color values
for (var i=0; i<(bufSize); i+=3){
var r = (this.gammatable[buffer[i+0]]>>1)+0x80;
var g = (this.gammatable[buffer[i+1]]>>1)+0x80;
var b = (this.gammatable[buffer[i+2]]>>1)+0x80;
aBuf[i+numLeadingZeros+0]=g;
aBuf[i+numLeadingZeros+1]=r;
aBuf[i+numLeadingZeros+2]=b;
};
// trailing zero
aBuf[bufSize+numLeadingZeros] = 0x00;
fs.writeSync(this.spiFd, aBuf, 0, aBuf.length, null);
} //end if (this.spiFd)
}, // end sendRgbBufLPD8806
/*
* send buffer with RGB values to LPD 8806 stripe
*/
sendRgbBufWS2801 : function(buffer){
// checking if enough time passed for resetting stripe
if (microtime.now() > (this.lastWriteTime + this.rowResetTime)){
// yes, its o.k., lets write
// but first do gamma correction
var adjustedBuffer = new Buffer(buffer.length);
for (var i=0; i < buffer.length; i++){
adjustedBuffer[i]=this.gammatable[buffer[i]];
}
fs.writeSync(this.spiFd, adjustedBuffer, 0, buffer.length, null);
this.lastWriteTime = microtime.now();
return true;
}
console.log('writing to fast, data dropped');
return false;
}, // end sendRgbBufWS2801
/*
* fill whole stripe with one color
*/
fill : function(r,g,b){
if (this.spiFd) {
var bufSize = this.numLEDs * this.bytePerPixel;
var aBuf = new Buffer(bufSize);
for (var i=0; i<(bufSize); i+=3){
aBuf[i+0]=r;
aBuf[i+1]=g;
aBuf[i+2]=b;
}
this.sendRgbBuf(aBuf);
}
}, //end fill
/*
* play an animation from RGB buffer
* - buffersize must be a multiple of one frame
* - delay between frames is given in microtimers format,
* e.g. 10m for 10 milliseconds
*/
animate : function(buffer,frameDelay, callback){
var row = 0;
var rows = buffer.length/(this.numLEDs*this.bytePerPixel);
if (rows != Math.ceil(rows)) {
console.log("buffer size is not a multiple of frame size");
return false;
}
var myTimer = new nanotimer();
console.log("Writing " + rows + " rows for " + this.numLEDs + " LEDs with delay " + frameDelay);
myTimer.setInterval(function(){
if (row>=rows){
myTimer.clearInterval();
if (callback)
callback();
} else {
this.sendRgbBuf(buffer.slice(row * this.numLEDs * this.bytePerPixel, (row + 1) * this.numLEDs * this.bytePerPixel));
row++;
}
}.bind(this), null, frameDelay, function(err) {
if(err) {
//error
}
});
} //end animate
}
module.exports = new LedStripe();