documented the frame format
created nodejs display server created html5 canvas visualizer of framesmaster
parent
16beb2f684
commit
050d0a0c1c
47
HACKING
47
HACKING
|
@ -13,3 +13,50 @@ Currently used versions of dependencies:
|
|||
-- Documentation: http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/
|
||||
|
||||
|
||||
Frame format (frame=all infos to display the windows and segments)
|
||||
The frames are separated in UDP packets, so each packet has one frame
|
||||
|
||||
Original format (this will be changed, see below):
|
||||
This is set in frameserver/defines.h
|
||||
* byte "abcdefghij" (10 chars)
|
||||
* byte z (indicates z level. 1=the most backwards)
|
||||
* byte '\n'
|
||||
* byte windows (width*height*channels) (so this starts 12 bytes from beginning)
|
||||
* byte segments (displays*segments*channels)
|
||||
|
||||
|
||||
|
||||
Proposed new format, to be able to treat a stream of frames
|
||||
* byte "s2l\n"
|
||||
* byte windows per row (i.e. max X) in ASCII. in our case 12 => '<'
|
||||
* byte rows (i.e. max Y) in ASCII. in our case 8 => '8'
|
||||
* byte displays per row (usually same as windows per row) '<'
|
||||
* byte disprows (how many rows of 7 segment displays). In our case always '1'
|
||||
* byte segments per display (can be 7,8,14 ... depending on the hardware)
|
||||
* byte reserved (future use) currently always set to 0x20 ' '
|
||||
* byte z (indicates z level. 1=the most backwards) this is in binary...
|
||||
* byte '\n'
|
||||
* byte windows (channels*width+1)*height (so this starts 12 bytes from beginning)
|
||||
* byte segments displays*(channels*segments+1)*disprows
|
||||
|
||||
channels??? Is always 4, means you send RGBA values. If the display is just
|
||||
greyscale the output from frameserver to display should be quantized
|
||||
accordingly. Best done in the display code. E.g. the building is B/W, then
|
||||
render RGB to HUE in the display client. The html simulator could output
|
||||
it as is, or do the conversion via a toggle button on the webpage.
|
||||
|
||||
+1??? Well looks like in the frameserver code and in the clients the
|
||||
"lines" of each frame are separated by a nice \n character.
|
||||
And the 7 segment displays are each separated by a \n
|
||||
Oh so why not? Let's have it display nicely on screen if dumped in
|
||||
a network trace.
|
||||
|
||||
so size max of a UDP packet is
|
||||
(full rgba) : 10+2+(4*12+1)*8+12*(4*8+1)*1=800 bytes
|
||||
|
||||
Note that the current code needs change of HASH define to
|
||||
"s2l\n<8<18 "
|
||||
as that value is always checked to validate a correct frame
|
||||
and the code does not use the infos to size buffers (else: buffer overrun hack)
|
||||
|
||||
|
||||
|
|
|
@ -4,3 +4,13 @@ the final setup will be a central server using node.js which gets it's data from
|
|||
and manages the multiple connections to web clients visualizing the virtual building
|
||||
|
||||
howto install node js: http://howtonode.org/how-to-install-nodejs
|
||||
|
||||
*run the latest demo
|
||||
** run the webserver/udp listener:
|
||||
nodejs ws_udp.js
|
||||
|
||||
** run the random data feeder
|
||||
./feed_stream.sh
|
||||
|
||||
** run the visualizer
|
||||
./firefox visionneuse.html
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
while true
|
||||
do
|
||||
frame="$(
|
||||
echo "s2l"
|
||||
printf "<8<18 "
|
||||
printf "1"
|
||||
echo ""
|
||||
a=$(date +%S)
|
||||
a=$((0+a))
|
||||
j=0
|
||||
while [ $j -lt 8 ]
|
||||
do
|
||||
i=0
|
||||
while [ $i -lt 12 ]
|
||||
do
|
||||
n=$((j*8+i))
|
||||
if [ $n -eq $a ]
|
||||
then
|
||||
printf "zzz "
|
||||
else
|
||||
printf "000 "
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
j=$((j+1))
|
||||
echo "" # next row
|
||||
done
|
||||
d=0
|
||||
while [ $d -lt 12 ]
|
||||
do
|
||||
s=0
|
||||
while [ $s -lt 8 ]
|
||||
do
|
||||
printf "1${s}1 "
|
||||
s=$((s+1))
|
||||
done
|
||||
d=$((d+1))
|
||||
echo "" # next display
|
||||
done
|
||||
)"
|
||||
echo "$frame"
|
||||
echo "$frame" | nc -w 1 -u localhost 4422
|
||||
sleep 1
|
||||
done
|
|
@ -0,0 +1,11 @@
|
|||
<?
|
||||
while (true) {
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
$('news').innerHTML = '<?= date(DATE_RFC822) ?>';
|
||||
</script>
|
||||
<?
|
||||
flush(); // Ensure the Javascript tag is written out immediately
|
||||
sleep(10);
|
||||
}
|
||||
?>
|
|
@ -11,16 +11,43 @@
|
|||
var message = document.getElementById('message').value;
|
||||
ws.send(message);
|
||||
}
|
||||
|
||||
// this displays a standard frame
|
||||
// header: 10 bytes. must be "s2l\n<8<18 "
|
||||
// z buffer: 1 byte
|
||||
// CR \n: 1 byte
|
||||
headersize=12;
|
||||
function connection() {
|
||||
ws = new WebSocket('ws://localhost:1234', 'echo-protocol');
|
||||
|
||||
ws.addEventListener("message", function(e) {
|
||||
// The data is simply the message that we're sending back
|
||||
var msg = e.data;
|
||||
|
||||
// Append the message
|
||||
document.getElementById('chatlog').innerHTML += '<br>' + msg;
|
||||
// The data is the message from stdin of the server
|
||||
var frame = e.data;
|
||||
// we got a frame here
|
||||
// the header is skipped (headersize)
|
||||
// we should test here if it's correct header
|
||||
// first the windows 8*(12*4+1) (8 rows of 12 windows with 4 valus plus a \n per row)
|
||||
for(y=0;y<8;y++)
|
||||
for(x=0;x<12;x++) {
|
||||
r=frame[headersize+y*(x*4+1)] // 4 because RGBA (we ignore A)
|
||||
g=frame[headersize+y*(x*4+1)]
|
||||
b=frame[headersize+y*(x*4+1)]
|
||||
//console.log("put on d="+d+" s="+s+" val="+r+","+g+","+b+"="+b.charCodeAt(0))
|
||||
lightWindow(x,y,r.charCodeAt(0),g.charCodeAt(0),b.charCodeAt(0));
|
||||
}
|
||||
// now the 7 segments display
|
||||
// it contains 12*(8*4+1) bytes for the 7 segments
|
||||
// bytes012: color of segment0, display0
|
||||
// bytes456: color of segment1, display0
|
||||
// bytes89a: color of segment2, display0
|
||||
headersize+=8*(12*4+1)
|
||||
for(d=0;d<12;d++)
|
||||
for(s=0;s<8;s++) {
|
||||
r=frame[headersize+d*(8*4+1)+s*4+0] // 4 because RGBA (we ignore A)
|
||||
g=frame[headersize+d*(8*4+1)+s*4+1]
|
||||
b=frame[headersize+d*(8*4+1)+s*4+2]
|
||||
//console.log("put on d="+d+" s="+s+" val="+r+","+g+","+b+"="+b.charCodeAt(0))
|
||||
lightSegment(d,s,r.charCodeAt(0),g.charCodeAt(0),b.charCodeAt(0));
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('connect_button').style.display = 'none';
|
||||
|
@ -30,6 +57,101 @@
|
|||
</script>
|
||||
</head>
|
||||
<body onload=connection()>
|
||||
<canvas id="myCanvas" width="1437" height="1051"></canvas>
|
||||
<script>
|
||||
var canvas = document.getElementById('myCanvas');
|
||||
var context = canvas.getContext('2d');
|
||||
var imageObj = new Image();
|
||||
imageObj.src = 'building-isometric_night.jpg';
|
||||
// windowTab[0][0]={x:488,y:265};
|
||||
// windowTab[1][0]={x:528,y:265};
|
||||
function lightWindowBW(x,y,r,g,b) {
|
||||
luminance = 0.299*r + 0.587*g + 0.114*Bb
|
||||
context.beginPath();
|
||||
context.rect(488+40.3*x, 265+87.4*y, 23, 34);
|
||||
context.fillStyle = 'rgb('+luminance+','+luminance+','+luminance+')';
|
||||
context.fill();
|
||||
}
|
||||
function lightWindow(x,y,r,g,b) {
|
||||
context.beginPath();
|
||||
context.rect(488+40.3*x, 265+87.4*y, 23, 34);
|
||||
context.fillStyle = 'rgb('+r+','+g+','+b+')';
|
||||
context.fill();
|
||||
}
|
||||
function lightSegment(display,segment,r,g,b) {
|
||||
context.beginPath();
|
||||
segx=488+40.3*display;
|
||||
segy=176
|
||||
switch(segment) {
|
||||
case 0: //segment 0
|
||||
context.moveTo(segx,segy);
|
||||
context.lineTo(segx+23,segy);
|
||||
break;
|
||||
case 1:
|
||||
context.moveTo(segx+23,segy);
|
||||
context.lineTo(segx+23,segy+17);
|
||||
break;
|
||||
case 2:
|
||||
context.moveTo(segx+23,segy+18);
|
||||
context.lineTo(segx+23,segy+34);
|
||||
break;
|
||||
case 3:
|
||||
context.moveTo(segx,segy+34);
|
||||
context.lineTo(segx+23,segy+34);
|
||||
break;
|
||||
case 4:
|
||||
context.moveTo(segx,segy+18);
|
||||
context.lineTo(segx,segy+34);
|
||||
break;
|
||||
case 5:
|
||||
context.moveTo(segx,segy);
|
||||
context.lineTo(segx,segy+17);
|
||||
break;
|
||||
case 6:
|
||||
context.moveTo(segx,segy+17);
|
||||
context.lineTo(segx+23,segy+17);
|
||||
break;
|
||||
case 7:
|
||||
context.moveTo(segx+23,segy+38);
|
||||
context.lineTo(segx+23,segy+42);
|
||||
break;
|
||||
}
|
||||
context.lineWidth=5;
|
||||
context.strokeStyle = 'rgb('+r+','+g+','+b+')';
|
||||
context.stroke();
|
||||
}
|
||||
var ascii2segments = new Array (
|
||||
0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02,
|
||||
0x80, 0x0f, 0x80, 0x80, 0x04, 0x40, 0x80, 0x80,
|
||||
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
|
||||
0x7F, 0x6F, 0x80, 0x80, 0x80, 0x48, 0x80, 0x27,
|
||||
0x80, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x3d,
|
||||
0x76, 0x30, 0x1E, 0x76, 0x38, 0x15, 0x37, 0x3f,
|
||||
0x73, 0x67, 0x31, 0x6d, 0x78, 0x3e, 0x1C, 0x2A,
|
||||
0x76, 0x6e, 0x5b, 0x39, 0x80, 0x0F, 0x80, 0x08,
|
||||
0x80, 0x5f, 0x7c, 0x58, 0x5e, 0x7b, 0x71, 0x6F,
|
||||
0x74, 0x30, 0x0E, 0x76, 0x06, 0x15, 0x54, 0x5c,
|
||||
0x73, 0x67, 0x50, 0x6d, 0x78, 0x1c, 0x1c, 0x2A,
|
||||
0x76, 0x6e, 0x5b, 0x39, 0x80, 0x0F, 0x80, 0x08
|
||||
);
|
||||
|
||||
imageObj.onload = function() {
|
||||
context.drawImage(imageObj, 0, 0);
|
||||
|
||||
for(x=0;x<12;x++)
|
||||
for(y=-1;y<8;y++)
|
||||
lightWindow(x,y,0,0,0);
|
||||
|
||||
};
|
||||
// delete segment s on display d (0=left, 11=right)
|
||||
// lightSegment(d,s,0,0,0);
|
||||
// color r g b of segment s on display d
|
||||
// lightSegment(d,s,r,g,b);
|
||||
// windows light
|
||||
// lightWindow(i,j,0) // switch off window i (0=left) in row j (0=top)
|
||||
// lightWindow(i,j,w) // switch on new window with brightness w
|
||||
|
||||
</script>
|
||||
<div>Received from server:</div>
|
||||
<div id='chatlog'></div>
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# udp
|
||||
|
||||
The correct name for Node.js's `dgram` module.
|
||||
|
||||
Documentation: http://api.nodejs.org/dgram.html
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "udp",
|
||||
"version": "1.0.0",
|
||||
"description": "The correct name for Node.js's `dgram` module.",
|
||||
"main": "udp.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/udp"
|
||||
},
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me",
|
||||
"url": "http://blog.izs.me/"
|
||||
},
|
||||
"license": "BSD-2-Clause",
|
||||
"readme": "# udp\n\nThe correct name for Node.js's `dgram` module.\n\nDocumentation: http://api.nodejs.org/dgram.html\n",
|
||||
"readmeFilename": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/udp/issues"
|
||||
},
|
||||
"_id": "udp@1.0.0",
|
||||
"dist": {
|
||||
"shasum": "728875c1a2855ccdd9af488749826b4502523182"
|
||||
},
|
||||
"_from": "udp@",
|
||||
"_resolved": "https://registry.npmjs.org/udp/-/udp-1.0.0.tgz"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
module.exports = require('dgram');
|
|
@ -1,4 +1,16 @@
|
|||
|
||||
// listener
|
||||
// it wants some binary data
|
||||
// who want to convert it from listening on stdin to listening on a TCP socket?
|
||||
//
|
||||
// data format
|
||||
// basically it's the frame format of the frame server
|
||||
// byte "s2l\n<8<18 "
|
||||
// byte z (can be ignored)
|
||||
// byte \n
|
||||
// byte windows 12*4 RGBA values '\n' repeated 8 times for the 8 rows
|
||||
// byte segments 8*4 RGBA values '\n' repeated 12 times for the top row
|
||||
|
||||
var count = 0;
|
||||
var clients = {};
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
// listener UDP version
|
||||
// it wants some binary data
|
||||
//
|
||||
// data format
|
||||
// basically it's the frame format of the frame server
|
||||
// byte "s2l\n<8<18 "
|
||||
// byte z (can be ignored)
|
||||
// byte \n
|
||||
// byte windows 12*4 RGBA values '\n' repeated 8 times for the 8 rows
|
||||
// byte segments 8*4 RGBA values '\n' repeated 12 times for the top row
|
||||
|
||||
var count = 0;
|
||||
var clients = {};
|
||||
|
||||
var http = require('http');
|
||||
var dgram=require('dgram');
|
||||
var server = http.createServer(function(request, response) {});
|
||||
|
||||
server.listen(1234, function() {
|
||||
console.log((new Date()) + ' Webserver is listening on port 1234');
|
||||
});
|
||||
|
||||
var WebSocketServer = require('websocket').server;
|
||||
wsServer = new WebSocketServer({
|
||||
httpServer: server
|
||||
});
|
||||
|
||||
var server = dgram.createSocket('udp4');
|
||||
server.bind(4422, '127.0.0.1');
|
||||
|
||||
console.log((new Date()) + ' UDP display is listening on port 4422');
|
||||
|
||||
|
||||
wsServer.on('request', function(r) {
|
||||
|
||||
var connection = r.accept('echo-protocol', r.origin);
|
||||
|
||||
// Specific id for this client & increment count
|
||||
var id = count++;
|
||||
|
||||
// Store the connection method so we can loop through & contact all clients
|
||||
clients[id] = connection
|
||||
|
||||
console.log((new Date()) + ' Connection accepted [' + id + ']');
|
||||
// clients[id].sendUTF("Welcome to the server. You are connected. This message has been pushed to you.");
|
||||
|
||||
// Create event listener
|
||||
connection.on('message', function(message) {
|
||||
|
||||
// The string message that was sent to us
|
||||
var msgString = message.utf8Data;
|
||||
|
||||
// Loop through all clients
|
||||
for(var i in clients){
|
||||
// Send a message to the client with the message
|
||||
clients[i].sendUTF(msgString);
|
||||
}
|
||||
});
|
||||
|
||||
// Create event listener for close
|
||||
connection.on('close', function(reasonCode, description) {
|
||||
delete clients[id];
|
||||
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
|
||||
});
|
||||
});
|
||||
|
||||
var sendTime = function () {
|
||||
var now, i = 0;
|
||||
|
||||
// get time now
|
||||
now = new Date();
|
||||
|
||||
// send time to all clients
|
||||
for(i in clients) {
|
||||
// Send a message to the client with the message
|
||||
clients[i].sendUTF(now);
|
||||
}
|
||||
|
||||
// repeat in 5 seconds
|
||||
setTimeout(sendTime, 5000);
|
||||
};
|
||||
|
||||
server.on("message", function (msg, rinfo) {
|
||||
console.log("server got: " + msg + " from " +
|
||||
rinfo.address + ":" + rinfo.port);
|
||||
for(i in clients) {
|
||||
// Send a message to the client with the message
|
||||
clients[i].sendUTF(msg);
|
||||
}
|
||||
});
|
||||
// every 5 seconds send the date/time
|
Loading…
Reference in New Issue