1
0
Fork 0
mirror of https://github.com/sexybiggetje/pixdisp.git synced 2024-11-22 03:31:03 +01:00

Working implementation of drivers, and drawing application. Things light up!

This commit is contained in:
Martijn de Boer 2017-12-18 20:39:51 +01:00
parent f93a20a627
commit 7c212e22ee
11 changed files with 236 additions and 25 deletions

3
.gitignore vendored
View file

@ -1,3 +1,6 @@
# Application data
config.json
# Logs # Logs
logs logs
*.log *.log

View file

@ -1,5 +1,7 @@
NEEDS BETTER README! NEEDS BETTER README!
Make sure you are on a recent nodejs version. Raspbian has old version. Use nodesource ;).
npm install npm install
node pixdisp.js node pixdisp.js

14
config.example.json Normal file
View file

@ -0,0 +1,14 @@
{
"bindAddr": "0.0.0.0",
"bindPort": 8080,
"driver": "dummy",
"matrix": {
"width": 16,
"height": 16,
"brightness": 1,
"flipHorizontal": false,
"flipVertical": false
}
}

View file

@ -0,0 +1,67 @@
"use strict";
class ApiController {
constructor( server, driver ) {
this.server = server;
this.driver = driver;
this.server.post( { path: '/api/writecanvas' }, this.writecanvas.bind( this ) );
this.server.get( { path: '/api/write' }, this.write.bind( this ) );
this.server.get( { path: '/api/setpixel/:x/:y/:r/:g/:b' }, this.setPixel.bind( this ) );
}
writecanvas( request, resource, next ) {
this.driver.clearMatrix();
resource.setHeader( 'Access-Control-Allow-Origin', '*' );
let data = JSON.parse( request.params.data );
for ( let obj of data) {
this.driver.setPixel( obj.y, obj.x, obj.r, obj.g, obj.b );
}
let buffer = this.driver.getBuffer();
this.driver.write( buffer );
resource.json( 200, { 'msg': 'Ok' } );
return next();
}
write( request, resource, next ) {
resource.setHeader( 'Access-Control-Allow-Origin', '*' );
let buffer = this.driver.getBuffer();
this.driver.write( buffer );
resource.json( 200, { 'msg': 'Ok' } );
return next();
}
setPixel( request, resource, next ) {
resource.setHeader( 'Access-Control-Allow-Origin', '*' );
this.driver.setPixel(
request.params.x,
request.params.y,
request.params.r,
request.params.g,
request.params.b
);
resource.json( 200, { 'msg': 'Ok' } );
return next();
}
}
exports.ApiController = ApiController;

View file

@ -10,6 +10,9 @@ class Driver {
this.setSize( 16, 16 ); this.setSize( 16, 16 );
this.setBrightness( 1 ); this.setBrightness( 1 );
this.flipHorizontal = false;
this.flipVertical = false;
} }
/** /**
@ -19,7 +22,7 @@ class Driver {
this.width = w; this.width = w;
this.height = h; this.height = h;
this.createMatrix(); this.clearMatrix();
} }
/** /**
@ -84,6 +87,8 @@ class Driver {
* @return {Buffer} * @return {Buffer}
*/ */
getBuffer() { getBuffer() {
this.flipMatrix( this.flipHorizontal, this.flipVertical );
let buffer = new Buffer( this.width * this.height * 3 ); let buffer = new Buffer( this.width * this.height * 3 );
let size = this.getSize(); let size = this.getSize();
@ -100,22 +105,38 @@ class Driver {
return buffer; return buffer;
} }
/**
* Write output to the device. Implement at driver level.
*/
write( buffer ) { write( buffer ) {
console.log( 'Driver should implement this' ); console.log( 'Driver should implement this' );
} }
/**
* Flip the matrix along it's axis.
*/
flipMatrix( horizontal, vertical ) {
if ( horizontal === true ) {
for ( let i = 0; i < this.matrix.length; i++ ) {
this.matrix[ i ].reverse();
}
}
if ( vertical === true ) {
this.matrix.reverse();
}
}
/** /**
* Create the internal frame * Create the internal frame
*/ */
createMatrix() { clearMatrix() {
this.matrix = []; this.matrix = [];
let size = this.getSize(); for ( let y = 0; y < this.height; y++ ) {
for ( let y = 0; y < size.height; y++ ) {
this.matrix.push( [] ); this.matrix.push( [] );
for ( let x = 0; x < size.width; x++ ) { for ( let x = 0; x < this.width; x++ ) {
this.matrix[ y ].push( { this.matrix[ y ].push( {
r: 0, r: 0,
g: 0, g: 0,

40
drivers/driverfactory.js Normal file
View file

@ -0,0 +1,40 @@
"use strict";
class DriverFactory {
constructor() {
}
createFromConfig( config ) {
let driver;
switch ( config.driver.toLowerCase() ) {
default:
console.warn( "Unknown driver defaulting to Dummy" );
case "dummy":
let { Dummy } = require( './dummy' );
driver = new Dummy();
break;
case "pimoroniunicorn":
let { PimoroniUnicorn } = require( './pimoroniunicorn' );
driver = new PimoroniUnicorn();
break;
}
driver.setSize( config.matrix.width, config.matrix.height );
driver.setBrightness( config.matrix.brightness );
driver.flipHorizontal = config.matrix.flipHorizontal;
driver.flipVertical = config.matrix.flipVertical;
return driver;
}
}
exports.DriverFactory = DriverFactory;

15
drivers/dummy.js Normal file
View file

@ -0,0 +1,15 @@
"use strict";
let { Driver } = require( './driver' );
class Dummy extends Driver {
constructor() {
super();
}
write( buffer ) {
console.log( buffer );
}
}
exports.Dummy = Dummy;

View file

@ -2,7 +2,7 @@
let { Driver } = require( './driver' ); let { Driver } = require( './driver' );
class UnicornHatHD extends Driver { class PimoroniUnicorn extends Driver {
constructor() { constructor() {
super(); super();
@ -26,4 +26,4 @@ class UnicornHatHD extends Driver {
} }
} }
exports.UnicornHatHD = UnicornHatHD; exports.PimoroniUnicorn = PimoroniUnicorn;

View file

@ -1,18 +1,36 @@
'use strict'; 'use strict';
let { UnicornHatHD } = require( './drivers/unicornhathd' ); let fs = require( 'fs' );
let config;
let api;
if ( fs.existsSync( 'config.json' ) ) {
let contents = fs.readFileSync( 'config.json' );
config = JSON.parse( contents );
} else {
let contents = fs.readFileSync( 'config.example.json' );
config = JSON.parse( contents );
}
let driver;
let { DriverFactory } = require( './drivers/driverfactory' );
let driverFactory = new DriverFactory();
let { ApiController } = require( './controllers/apicontroller' );
let restify = require( 'restify' ); let restify = require( 'restify' );
let bindAddr = '0.0.0.0'; let bindAddr = config.bindAddr;
let bindPort = 8080; let bindPort = config.bindPort;
let server = restify.createServer( { let server = restify.createServer( {
handleUpgrades: true handleUpgrades: true
} ); } );
server.use( restify.plugins.queryParser() ); server.use( restify.plugins.queryParser() );
server.use( restify.plugins.bodyParser() ); server.use( restify.plugins.bodyParser( {
mapParams: true
} ) );
server.use( restify.plugins.jsonp() ); server.use( restify.plugins.jsonp() );
server.use( restify.plugins.gzipResponse() ); server.use( restify.plugins.gzipResponse() );
server.use( restify.plugins.throttle( server.use( restify.plugins.throttle(
@ -23,6 +41,11 @@ server.use( restify.plugins.throttle(
} }
)); ));
driver = driverFactory.createFromConfig( config );
driver.write( driver.getBuffer() );
api = new ApiController( server, driver );
server.get(/.*/, restify.plugins.serveStatic({ server.get(/.*/, restify.plugins.serveStatic({
'directory': 'www', 'directory': 'www',
@ -37,12 +60,4 @@ server.listen( bindPort, bindAddr, function() {
console.log( '%s listening at %s ', server.name , server.url ); console.log( '%s listening at %s ', server.name , server.url );
console.log( 'Ready.' ); console.log( 'Ready.' );
// Some test code
let driver = new UnicornHatHD();
driver.setPixel( 1, 1, 255, 0, 0 );
driver.setPixel( 5, 5, 255, 0, 255 );
let buffer = driver.getBuffer();
driver.write( buffer );
}); });

View file

@ -19,10 +19,7 @@
</div> </div>
</section> </section>
<section class="section view"> <section class="section view">
<a class="button is-small is-link">Load current</a> <a class="button is-small is-success" id="submitImage">Submit</a>
<a class="button is-small is-link">Capture camera</a>
<a class="button is-small is-link">Browse history</a>
<a class="button is-small is-success">Submit</a>
<br /><br /> <br /><br />
<div class="columns"> <div class="columns">
<div class="column is-half" id="canvasHolder"> <div class="column is-half" id="canvasHolder">

View file

@ -18,6 +18,7 @@ class App
holder.appendChild( canvas ); holder.appendChild( canvas );
canvas.addEventListener( 'click', this.handleCanvas ); canvas.addEventListener( 'click', this.handleCanvas );
document.getElementById( 'submitImage' ).addEventListener( 'click', this.submitCanvas );
this.canvas = canvas; this.canvas = canvas;
this.context = canvas.getContext( '2d' ); this.context = canvas.getContext( '2d' );
@ -118,6 +119,42 @@ class App
} }
submitCanvas( ev ) {
if ( ev.preventDefault ) {
ev.preventDefault();
}
let imageData = app.context.getImageData( 0, 0, app.canvas.width, app.canvas.height );
let request = new XMLHttpRequest();
request.open( 'POST', '/api/writecanvas', true );
request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8' );
let obj = [];
for ( let x = 0; x < app.canvas.width; x++ ) {
for ( let y = 0; y < app.canvas.height; y++ ) {
let index = ( y * app.canvas.width + x ) * 4;
let r = imageData.data[ index ];
let g = imageData.data[ index + 1 ];
let b = imageData.data[ index + 2 ];
if ( r > 0 || g > 0 || b > 0 ) {
obj.push( {
x: x,
y: y,
r: r,
g: g,
b: b
} )
}
}
}
obj = encodeURI( 'data=' + JSON.stringify( obj ) );
request.send( obj );
}
} }
let app = new App(); let app = new App();