-
Notifications
You must be signed in to change notification settings - Fork 22
/
send-data.js
124 lines (110 loc) · 4.26 KB
/
send-data.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
const _ = require('lodash');
const config = require('./config');
const consoleOutput = require('./outputs/console-output');
var piOutput;
if (config.sendToPi) {
piOutput = require('./outputs/pi-output');
}
const websocketOutput = require('./outputs/websocket-output');
var sender;
const prepareFrame = function (raw, pixelsPerRow, zigzag = true) {
var groupBypPixel = _.chunk(raw, 3);
var groupByRow = _.chunk(groupBypPixel, pixelsPerRow);
if (zigzag) {
_.each(groupByRow, function (row, i) {
if (i % 2) { //row is even, reverse the pixels
groupByRow[i] = groupByRow[i].reverse();
}
});
}
return groupByRow;
};
const prepareFrameBuffer = function (raw, pixelsPerRow, zigzag = true, alpha = false) {
var buffer = new Buffer(raw.length + (alpha ? raw.length / 3 : 0));
var groupBypPixel = _.chunk(raw, 3);
var groupByRow = _.chunk(groupBypPixel, pixelsPerRow);
var x = 0;
_.each(groupByRow, function (row, i) { //for each group of rows
var loop = i % 2 ? zigzag ? _.eachRight: _.each : _.each;
loop(row, (pixel) => { //each row, in reverse for even rows
_.each(pixel, (rgb)=>{ //Every pixel array
buffer.writeUInt8(rgb, x++);
});
if (alpha) {
buffer.writeUInt8(255, x++);
}
});
});
return buffer;
};
// Return whether the current sender (if there is one) is able to stop
function canSendFrame (guid) {
return !sender || sender.guid == guid || sender && sender.canStopCb && sender.canStopCb();
}
// Push trigger functions to an array for any input that cannot be displayed due to the current sender being unable to stop
var queue = [];
var queueTriggered = false;
function addToQueue (type, trigger) {
console.log(`Queueing up ${type} input`);
queue.push(trigger);
}
var start;
var lastGUID;
function sendFrame (guid, frame, delay, cb, stopCb, canStopCb) {
//STEP 1: register sender as current, if there is an existing sender callback telling it to stop sending data
if (!sender) {
console.log('Sending', guid);
sender = { guid, stopCb, canStopCb };
}
else if (sender.guid != guid) {
if (lastGUID == guid && guid !== 'websocket-client') {
// Ignore it, got an extra frame from sender unexpectedly after stopping it
return;
}
queueTriggered = false;
if (sender.stopCb && sender.stopCb()) {
console.log('Stopping', sender.guid);
console.log('Sending', guid);
lastGUID = sender.guid;
sender = { guid, stopCb, canStopCb };
}
else {
// ignore it, unable to stop the current sender
return;
}
} else {
// As long as the sender can stop and we haven't already kicked off an input, kick off the first input in the queue
if (queue.length && sender.canStopCb() && !queueTriggered) {
queue.shift()();
queueTriggered = true;
}
}
//Step 2: chunk frame per row and reverse every other frame
if (!config.sendToWebsockets && !config.sendToConsole && !config.sendToPi) {
setTimeout(cb, delay);
return;
}
start = Date.now();
if (config.sendToWebsockets) {
// Send to websocket clients such as the mobile app
var preparedFrame = prepareFrameBuffer(frame, config.matrix.width, false, true);
websocketOutput.drawFrame(preparedFrame, (config.sendToPi || config.sendToConsole) ? false : () => {
setTimeout(cb, delay - (Date.now() - start));
});
}
if (config.sendToPi) {
//Option 1 draw to pixel wall
frame = prepareFrameBuffer(frame, config.matrix.width, true);
piOutput.drawFrame(frame, () => {
setTimeout(cb, delay - (Date.now() - start))
});
} else if (config.sendToConsole) {
//Option 2 draw to log
console.log('\x1Bc');
frame = prepareFrame(frame, config.matrix.width, false);
consoleOutput.drawFrame(frame);
setTimeout(cb, delay - (Date.now() - start));
}
};
//For each frame send image to the device, use (frame rate - previous frame duration) to animate smoothly
module.exports = { sendFrame, canSendFrame, addToQueue };