Sequencer added

This commit is contained in:
Matt 2016-04-14 00:17:42 -04:00
parent 70af44f5f5
commit b36082d0e7
8 changed files with 713 additions and 25 deletions

View File

@ -1,3 +1,8 @@
html,
body {
-webkit-overflow-scrolling: auto;
overflow-x: hidden;
}
input:focus { input:focus {
outline: none !important; outline: none !important;
} }
@ -12,6 +17,9 @@ footer {
width: 100%; width: 100%;
height: 150px; height: 150px;
} }
#screens {
overflow-x: hidden;
}
.screen { .screen {
display: none; display: none;
} }
@ -70,6 +78,187 @@ footer {
background-color: #000; background-color: #000;
float: right; float: right;
} }
#counters .cam,
#counters .proj {
width: 50%;
padding-bottom: 25px;
}
#counters .cam label,
#counters .proj label {
text-align: center;
font-size: 24px;
display: block;
}
#counters .cam input,
#counters .proj input {
background: rgba(255, 255, 255, 0.05);
color: #fff;
padding: 6px 12px;
font-size: 21px;
display: block;
margin: 0 auto;
text-align: center;
font-family: monospace;
}
#counters .cam input.changed,
#counters .proj input.changed {
color: #DAE035;
}
#counters .cam {
float: left;
}
#counters .proj {
float: right;
}
#seq_scroll {
width: 100%;
overflow-x: scroll;
}
#seq_scroll > div > div > div {
float: left;
}
#seq_scroll > div > div > div input {
float: none;
}
#seq_scroll > div > div > div > div {
font-size: 8px;
text-align: center;
color: #dcdcdc;
}
#actions {
padding: 20px;
}
#seq_stats {
width: 40%;
float: right;
padding: 20px;
margin-top: 57px;
}
#seq_stats span {
font-weight: 600;
float: right;
}
#seq_loop {
padding: 0 28px;
}
#seq_loop input {
font-family: monospace;
font-size: 23px;
width: 121px;
padding: 12px;
}
button {
display: block;
border-radius: 5px;
border: 2px solid #fff;
text-align: center;
background: transparent;
color: #fff;
padding: 8px 0;
font-size: 12px;
font-weight: 400;
display: inline-block;
padding: 4px 16px;
font-size: 14px;
}
button span {
display: block;
font-size: 16px;
font-weight: 200;
}
button:active,
button .active {
background: #fff;
color: #322b2f;
outline: none;
}
button:focus {
outline: none;
}
#sequence {
width: 970px;
padding-bottom: 25px;
padding-left: 70px;
height: 230px;
}
#sequence #cam_forward,
#sequence #proj_forward,
#sequence #black_forward {
clear: both;
}
#sequence #cam_forward input[type=checkbox],
#sequence #proj_forward input[type=checkbox],
#sequence #black_forward input[type=checkbox] {
border: 1px solid #00C4A0;
margin-right: 3px;
}
#sequence #cam_forward input[type=checkbox]:checked,
#sequence #proj_forward input[type=checkbox]:checked,
#sequence #black_forward input[type=checkbox]:checked {
background: #00C4A0;
}
#sequence #cam_forward > div,
#sequence #proj_forward > div,
#sequence #black_forward > div {
color: #00C4A0;
}
#sequence #cam_backward,
#sequence #proj_backward,
#sequence #black_backward {
clear: both;
}
#sequence #cam_backward input[type=checkbox],
#sequence #proj_backward input[type=checkbox],
#sequence #black_backward input[type=checkbox] {
border: 1px solid #AB1A25;
margin-right: 3px;
}
#sequence #cam_backward input[type=checkbox]:checked,
#sequence #proj_backward input[type=checkbox]:checked,
#sequence #black_backward input[type=checkbox]:checked {
background: #AB1A25;
}
#sequence #cam_backward > div,
#sequence #proj_backward > div,
#sequence #black_backward > div {
color: #AB1A25;
}
#sequence #cam_backward {
margin-top: 15px;
}
#sequence input[type=checkbox] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: transparent;
outline: none;
display: block;
width: 35px;
height: 35px;
border-radius: 5px;
margin: 0;
margin-bottom: 3px;
float: left;
box-sizing: border-box;
}
#sequence input.h {
border-color: #DAE035 !important;
}
#sequence input.h:checked {
background: #DAE035 !important;
}
#sequence #numbers {
clear: both;
}
#sequence #numbers > div {
width: 35px;
color: #fff;
font-family: monospace;
float: left;
margin: 3px;
text-align: center;
opacity: 0.5;
}
.cp-app { .cp-app {
position: relative !important; position: relative !important;
border-radius: 0px !important; border-radius: 0px !important;

View File

@ -1,3 +1,47 @@
@BG: rgb(50, 43, 47);
@COMMON: #fff;
@FORWARD: #00C4A0;
@BACKWARD: #AB1A25;
@SELECTED: #DAE035;
@SEQ: #3C3636;
@SCRIPT: rgb(39, 40, 34);
.monospace () {
font-family: monospace;
}
.button (@color: @COMMON) {
display: block;
border-radius: 5px;
border: 2px solid @color;
text-align: center;
background: transparent;
color: @color;
padding: 8px 0;
font-size: 12px;
font-weight: 400;
span{
display: block;
font-size: 16px;
font-weight: 200;
}
&:active,.active{
background: @color;
color: @BG;
outline: none;
}
&:focus{
outline: none;
}
}
html, body{
-webkit-overflow-scrolling: auto;
overflow-x: hidden;
}
input { input {
&:focus{ &:focus{
outline: none !important; outline: none !important;
@ -17,6 +61,10 @@ footer{
height: 150px; height: 150px;
} }
#screens{
overflow-x: hidden;
}
.screen{ .screen{
display: none; display: none;
} }
@ -77,6 +125,162 @@ footer{
float: right; float: right;
} }
#counters{
.cam,.proj{
width: 50%;
padding-bottom: 25px;
label{
text-align: center;
font-size: 24px;
display: block;
}
input{
background: rgba(255, 255, 255, 0.05);
color: @COMMON;
padding: 6px 12px;
font-size: 21px;
display: block;
margin: 0 auto;
text-align: center;
.monospace();
&.changed{
color: @SELECTED;
}
}
}
.cam{
float: left;
}
.proj{
float: right;
}
}
#seq_scroll{
width: 100%;
overflow-x: scroll;
>div>div>div{
float: left;
input{
float: none;
}
>div{
font-size: 8px;
text-align: center;
color: rgb(220, 220, 220);
}
}
}
#actions{
padding: 20px 0 0 55px;
}
#seq_stats{
width: 40%;
float: right;
padding: 20px;
margin-top: 57px;
span{
font-weight: 600;
float: right;
}
.timing{
}
}
#seq_loop{
padding: 0 28px;
input{
.monospace();
font-size: 23px;
width: 121px;
padding: 12px;
}
}
button{
.button();
display: inline-block;
padding: 4px 16px;
font-size: 14px;
}
#sequencer{
}
#sequence{
width: 970px;
padding-bottom: 25px;
padding-left: 70px;
height: 230px;
#cam_forward,
#proj_forward,
#black_forward{
clear: both;
input[type=checkbox]{
border: 1px solid @FORWARD;
margin-right: 3px;
&:checked{
background: @FORWARD;
//background: radial-gradient(circle at 25px 25px, #00C4A0, #343434);
}
}
>div{
color: @FORWARD;
}
}
#cam_backward,
#proj_backward,
#black_backward{
clear: both;
input[type=checkbox]{
border: 1px solid @BACKWARD;
margin-right: 3px;
&:checked{
background: @BACKWARD;
//background: radial-gradient(circle at 25px 25px, #AB1A25, #343434);
}
}
>div{
color: @BACKWARD;
}
}
#cam_backward{
margin-top: 15px;
}
input[type=checkbox]{
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: transparent;
outline: none;
display: block;
width: 35px;
height: 35px;
border-radius: 5px;
margin: 0;
margin-bottom: 3px;
float: left;
box-sizing: border-box;
}
input.h{
//background: @SELECTED !important;
border-color: @SELECTED !important;
&:checked{
background: @SELECTED !important;
}
}
#numbers{
clear: both;
> div{
width: 35px;
color: @COMMON;
font-family: monospace;
float: left;
margin: 3px;
text-align: center;
opacity: 0.5;
}
}
}
.cp-app{ .cp-app{
position: relative !important; position: relative !important;
border-radius: 0px !important; border-radius: 0px !important;

View File

@ -12,6 +12,47 @@
<body onload="init();"> <body onload="init();">
<nav id="toolbar"></nav> <nav id="toolbar"></nav>
<div id="screens"> <div id="screens">
<div id="sequencer" class="screen" style="display: block;">
<div id="counters">
<div class="cam">
<label>CAMERA</label>
<input type="number" id="seq_cam_count" class="count" value="00000" onchange="mcopy.gui.trad.counterFormat(this, mcopy.state.camera.pos);" onblur="mcopy.gui.trad.updateCam(this);" />
</div>
<div class="proj">
<label>PROJECTOR</label>
<input type="number" id="seq_proj_count" class="count" value="00000" onchange="mcopy.gui.trad.counterFormat(this, mcopy.state.projector.pos);" onblur="mcopy.gui.trad.updateProj(this);" />
</div>
</div>
<div id="seq_scroll">
<div id="sequence">
<div id="cam_forward" class="row" y="0"></div>
<div id="proj_forward" class="row" y="1"></div>
<div id="black_forward" class="row" y="2"></div>
<div id="cam_backward" class="row" y="0"></div>
<div id="proj_backward" class="row" y="1"></div>
<div id="black_backward" class="row" y="2"></div>
</div>
</div>
<div id="seq_stats">
<h3>STATS</h3>
<div class="seq_count">Number of instructions: <span>0</span></div>
<div class="timing">Time to complete: <span>0 ms</span></div>
<div class="cam_end">Camera end position: <span>00000</span></div>
<div class="proj_end">Projector end position: <span>00000</span></div>
</div>
<div id="actions">
<button id="seq_run" onclick="mcopy.seq.init();">RUN</button>
<button id="seq_stop" onclick="mcopy.seq.stop(true);">STOP</button>
<button id="seq_clear" onclick="mcopy.gui.grid.clear();">CLEAR</button>
<button id="seq_plus24" onclick="mcopy.gui.grid.plus_24();">+ 24</button>
<button id="seq_mscript" onclick="mcopy.gui.mscript.generate(mcopy.state.sequence.arr);">TO SCRIPT</button>
</div>
<div id="seq_loop">
<h3>LOOPS</h3>
<input type="number" min="1" id="seq_loop" value="00001" onchange="this.value = mcopy.fmtZero(this.value, 6); mcopy.gui.grid.loopChange(this);"/>
</div>
</div>
<div id="script" class="screen"></div>
<div id="controls" class="screen"> <div id="controls" class="screen">
<footer> <footer>
<div id="log"></div> <div id="log"></div>

File diff suppressed because one or more lines are too long

View File

@ -115,6 +115,30 @@ mcopy.arduino.connect = function (callback) {
}); });
}; };
mcopy.arduino.fakeConnect = function (callback) {
console.log('Connecting to fake arduino...');
mcopy.arduino.serial = {
write : function (cmd, res) {
var t = {
c : mcopy.cfg.arduino.cam.time + mcopy.cfg.arduino.cam.delay,
p : mcopy.cfg.arduino.proj.time + mcopy.cfg.arduino.proj.delay
},
timeout = t[cmd];
if (typeof timeout === 'undefined') timeout = 500;
mcopy.arduino.timer = +new Date();
setTimeout(function () {
mcopy.arduino.end(cmd);
}, timeout);
},
string : function (str) {
//do nothing
return true;
}
};
console.log('Connected to fake arduino! Not real! Doesn\'t exist!');
if (callback) callback();
};
if (typeof module !== 'undefined' && module.parent) { if (typeof module !== 'undefined' && module.parent) {
module.exports = function (cfg) { module.exports = function (cfg) {
mcopy.cfg = cfg; mcopy.cfg = cfg;

View File

@ -7,6 +7,7 @@ var electron = require('electron'),
uuid = require('node-uuid'), uuid = require('node-uuid'),
winston = require('winston'), winston = require('winston'),
moment = require('moment'), moment = require('moment'),
Q = require('q'),
mcopy = {}; mcopy = {};
mcopy.cfg = JSON.parse(fs.readFileSync('./cfg.json', 'utf8')); mcopy.cfg = JSON.parse(fs.readFileSync('./cfg.json', 'utf8'));
@ -22,6 +23,9 @@ var init = function () {
mcopy.arduino.init(function (err, device) { mcopy.arduino.init(function (err, device) {
if (err) { if (err) {
log.info(err, 'SERIAL', false, true); log.info(err, 'SERIAL', false, true);
mcopy.arduino.fakeConnect(function () {
log.info('Connected to fake USB device', 'SERIAL', true, true);
});
} else { } else {
log.info('Found device ' + device, 'SERIAL', true, true); log.info('Found device ' + device, 'SERIAL', true, true);
mcopy.arduino.connect(function () { mcopy.arduino.connect(function () {
@ -67,13 +71,16 @@ ipcMain.on('light', function(event, arg) {
var light = {}; var light = {};
light.set = function (obj) { light.set = function (rgb) {
'use strict'; 'use strict';
var str = obj.rgb.join(','); var str = rgb.join(','),
deferred = Q.defer();
mcopy.arduino.send(mcopy.cfg.arduino.cmd.light, function () { mcopy.arduino.send(mcopy.cfg.arduino.cmd.light, function () {
log.info('Light set to ' + str, 'LIGHT', true, true); log.info('Light set to ' + str, 'LIGHT', true, true);
return deferred.resolve(mcopy.cfg.arduino.cmd.light);
}); });
mcopy.arduino.string(str); mcopy.arduino.string(str);
return deferred.promise;
}; };
var log = {}; var log = {};

View File

@ -34,6 +34,7 @@
"moment": "^2.12.0", "moment": "^2.12.0",
"node-notifier": "^4.5.0", "node-notifier": "^4.5.0",
"node-uuid": "^1.4.7", "node-uuid": "^1.4.7",
"q": "^1.4.1",
"serialport": "^2.1.0", "serialport": "^2.1.0",
"winston": "^2.2.0" "winston": "^2.2.0"
} }

View File

@ -1,11 +1,50 @@
var remote = require('remote'), var remote = require('remote'),
fs = require('fs'),
uuid = require('node-uuid'), uuid = require('node-uuid'),
ipcRenderer = require('electron').ipcRenderer, ipcRenderer = require('electron').ipcRenderer,
mcopy = {},
light = {}, light = {},
nav = {}, nav = {},
gui = {},
log = {}; log = {};
//console.log(ipcRenderer.sendSync('light', { 'fuck' : true }) ); //console.log(ipcRenderer.sendSync('light', { 'fuck' : true }) );
mcopy.cfg = JSON.parse(fs.readFileSync('./cfg.json'), 'utf8');
/******
State shared by ALL interfaces
*******/
mcopy.state = {
version : 'alpha', //use for file compatibility check
camera : {
pos : 0,
direction: true
},
projector : {
pos : 0,
direction: true
},
sequence : {
size : 24,
arr : ['CF', 'PF'],
cmd : {
camera: mcopy.cfg.arduino.cmd.camera,
projector: mcopy.cfg.arduino.cmd.projector,
cam_direction: mcopy.cfg.arduino.cmd.cam_direction,
cam_direction: mcopy.cfg.arduino.cmd.proj_direction
},
pads: {
cam_forward: 'CF',
proj_forward : 'PF',
black_forward : 'BF',
cam_backward: 'CB',
proj_backward : 'PB',
black_backward : 'BB'
}
}
};
log.time = 'MM/DD/YY-HH:mm:ss'; log.time = 'MM/DD/YY-HH:mm:ss';
log.count = 0; log.count = 0;
log.init = function () { log.init = function () {
@ -24,7 +63,6 @@ log.init = function () {
log.info('Started app', 'MAIN', true); log.info('Started app', 'MAIN', true);
log.listen(); log.listen();
}; };
log.listen = function () { log.listen = function () {
'use strict'; 'use strict';
ipcRenderer.on('log', function (event, arg) { ipcRenderer.on('log', function (event, arg) {
@ -32,7 +70,6 @@ log.listen = function () {
return event.returnValue = true; return event.returnValue = true;
}); });
}; };
log.display = function (action, service, status, time) { log.display = function (action, service, status, time) {
'use strict'; 'use strict';
var obj = { var obj = {
@ -53,12 +90,10 @@ log.display = function (action, service, status, time) {
}, 100); }, 100);
return obj; return obj;
}; };
log.report = function (obj) { log.report = function (obj) {
'use strict'; 'use strict';
ipcRenderer.sendSync('log', obj); ipcRenderer.sendSync('log', obj);
}; };
log.info = function (action, service, status, time) { log.info = function (action, service, status, time) {
'use strict'; 'use strict';
var obj = log.display(action, service, status, time); var obj = log.display(action, service, status, time);
@ -66,6 +101,86 @@ log.info = function (action, service, status, time) {
console.log(obj); console.log(obj);
}; };
/******
Sequencer grid
*******/
gui.grid = {};
gui.grid.layout = function () {
'use strict';
gui.grid.refresh();
mcopy.seq.stats();
};
gui.grid.state = function (i) {
'use strict';
if (mcopy.state.sequence.arr[i] !== undefined) {
$('input[x=' + i + ']').prop('checked', false);
$('.' + mcopy.state.sequence.arr[i] + '[x=' + i + ']').prop('checked', true);
}
};
gui.grid.refresh = function () {
'use strict';
var cmds = ['cam_forward', 'proj_forward', 'black_forward', 'cam_backward', 'proj_backward', 'black_backward'],
check = '',
width = 970 + ((940 / 24) * Math.abs(24 - mcopy.state.sequence.size));
$('#sequence').width(width + 'px');
for (var i = 0; i < cmds.length; i++) {
$('#' + cmds[i]).empty();
for (var x = 0; x < mcopy.state.sequence.size; x++) {
check = '<input type="checkbox" x="xxxx" />'.replace('xxxx', x);
if (i === cmds.length - 1) {
$('#' + cmds[i]).append($('<div>').append($(check).addClass(mcopy.state.sequence.pads[cmds[i]])).append($('<div>').text(x)));
} else {
$('#' + cmds[i]).append($(check).addClass(mcopy.state.sequence.pads[cmds[i]]));
}
gui.grid.state(x);
}
}
};
gui.grid.click = function (t) {
'use strict';
var i = parseInt($(t).attr('x'));
if ($(t).prop('checked')) {
mcopy.log( $(t).attr('class').replace('.', ''));
mcopy.state.sequence.arr[i] = $(t).attr('class').replace('.', '');
gui.grid.state(i);
} else {
mcopy.state.sequence.arr[i] = undefined;
delete mcopy.state.sequence.arr[i];
}
mcopy.seq.stats();
};
gui.grid.clear = function () {
'use strict';
var doit = confirm('Are you sure you want to clear this sequence?');
if (doit) {
mcopy.seq.clear();
gui.grid.refresh();
mcopy.seq.stats();
mcopy.log('Sequencer cleared');
}
};
gui.grid.loopChange = function (t) {
'use strict';
count = parseInt(t.value);
mcopy.loop = count;
mcopy.log('Loop count set to ' + mcopy.loop);
mcopy.seq.stats();
};
gui.grid.plus_24 = function () {
'use strict';
mcopy.state.sequence.size += 24;
gui.grid.refresh();
mcopy.log('Sequencer expanded to ' + mcopy.state.sequence.size + ' steps');
};
gui.grid.events = function () {
'use strict';
$(document.body).on('click', 'input[type=checkbox]', function () {
gui.grid.click(this);
});
};
//LIGHT //LIGHT
light.preview = false; light.preview = false;
light.color = [0, 0, 0]; //preview status light.color = [0, 0, 0]; //preview status
@ -161,20 +276,12 @@ light.init = function () {
} }
}); });
}; };
light.lock = false;
light.waiting = {};
//rgb = [0,0,0] //rgb = [0,0,0]
light.set = function (rgb) { light.set = function (rgb) {
'use strict'; 'use strict';
var cmd = {
id : uuid.v4(),
rgb : rgb
}
light.current = rgb; light.current = rgb;
console.dir(rgb); return ipcRenderer.sendSync('light', rgb);
ipcRenderer.sendSync('light', rgb);
}; };
light.display = function (rgb) { light.display = function (rgb) {
'use strict'; 'use strict';
var str, var str,
@ -194,6 +301,7 @@ light.color_init = function () {
'use strict'; 'use strict';
if (!light.color_on) { if (!light.color_on) {
$('#rgb').focus(); $('#rgb').focus();
light.color_on = true;
} }
}; };
@ -214,7 +322,6 @@ nav.init = function () {
} }
}); });
}; };
nav.change = function (id) { nav.change = function (id) {
'use strict'; 'use strict';
$('.screen').hide(); $('.screen').hide();
@ -229,6 +336,7 @@ nav.change = function (id) {
var init = function () { var init = function () {
'use strict'; 'use strict';
nav.init(); nav.init();
gui.grid.layout();
log.init(); log.init();
light.init(); light.init();
}; };