diff --git a/app/.gitignore b/app/.gitignore index e608ce6..d33aa83 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,4 +1,3 @@ -data/cfg.json node_modules/* logs/* data/transfer*.json \ No newline at end of file diff --git a/app/build_linux.sh b/app/build_linux.sh index 0c532c3..cd81e37 100644 --- a/app/build_linux.sh +++ b/app/build_linux.sh @@ -1,3 +1,6 @@ #!/bin/bash -electron-packager . mcopy --overwrite --asar=true --platform=linux --arch=x64 --icon=assets/icons/icon.png --prune=true --out=../dist +#package app +./node_modules/.bin/electron-packager . mcopy --overwrite --asar=true --platform=linux --arch=x64 --icon=assets/icons/icon.png --prune=true --out=../dist +#build a .deb installer +./node_modules/.bin/electron-installer-debian --src ../dist/mcopy-linux-x64/ --dest ../dist/installers/ --arch amd64 \ No newline at end of file diff --git a/app/build_mac.sh b/app/build_mac.sh index ba26fb1..67c38ab 100644 --- a/app/build_mac.sh +++ b/app/build_mac.sh @@ -1,3 +1,9 @@ #!/bin/bash -electron-packager . --overwrite --platform=darwin --arch=x64 --icon=assets/icons/icon.icns --prune=true --out=../dist +./node_modules/.bin/electron-packager . --overwrite --platform=darwin --arch=x64 --icon=assets/icons/icon.icns --prune=true --out=../dist +#build dmg for mac install +mkdir ../dist/installers +./node_modules/.bin/electron-installer-dmg ../dist/mcopy-darwin-x64 mcopy --out=../dist/installers --icon=assets/icons/icon.icns Path to the icon file that will be the app icon in the DMG window. +# --icon-size= How big to make the icon for the app in the DMG. [Default: `80`]. +# --background= Path to a PNG image to use as the background of the DMG. +#--overwrite Overwrite any existing DMG. \ No newline at end of file diff --git a/app/build_win.sh b/app/build_win.sh index 9924bcc..336cc8a 100644 --- a/app/build_win.sh +++ b/app/build_win.sh @@ -1,3 +1,5 @@ #!/bin/bash -electron-packager . mcopy --overwrite --asar=true --platform=win32 --arch=x64 --icon=assets/icons/win/icon.ico --prune=true --out=../dist --version-string.CompanyName="sixteenmillimeter.com" --version-string.FileDescription="Open Source Optical Printer Platform" --version-string.ProductName="mcopy" \ No newline at end of file +./node_modules/.bin/electron-packager . mcopy --overwrite --asar=true --platform=win32 --arch=x64 --icon=assets/icons/win/icon.ico --prune=true --out=../dist --version-string.CompanyName="sixteenmillimeter.com" --version-string.FileDescription="Open Source Optical Printer Platform" --version-string.ProductName="mcopy" + +mkdir ../dist/installers \ No newline at end of file diff --git a/app/css/app.css b/app/css/app.css index b0a1eab..e5c49b9 100644 --- a/app/css/app.css +++ b/app/css/app.css @@ -545,6 +545,7 @@ button:focus { .cmd { width: 240px; text-align: center; + margin: 0 auto; } .cmd i { float: left; @@ -589,6 +590,58 @@ button:focus { ::-webkit-scrollbar-thumb:window-inactive { background: rgba(0, 0, 0, 0.05); } +#settings > div { + width: 300px; + margin: 0 auto; +} +#settings > div > div { + width: 360px; +} +#settings input[type=text], +#settings select { + 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: 6px 12px; + font-size: 21px; + min-width: 300px; +} +#settings input[type=text] span, +#settings select span { + display: block; + font-size: 16px; + font-weight: 200; +} +#settings input[type=text]:active, +#settings select:active, +#settings input[type=text] .active, +#settings select .active { + background: #fff; + color: #272b30; + outline: none; +} +#settings input[type=text]:focus, +#settings select:focus { + outline: none; +} +#settings button { + margin-top: -1px; + float: right; +} +#settings input[type=radio] { + float: right; + margin-right: 20px; +} +#settings .spacer { + margin-top: 10px; +} #log { position: fixed; width: 100%; diff --git a/app/data/cfg.json b/app/data/cfg.json new file mode 100644 index 0000000..46b7bf2 --- /dev/null +++ b/app/data/cfg.json @@ -0,0 +1,46 @@ +{ + "version" : "2.0.0", + "ext_port" : 1111, + "arduino" : { + "baud" : 57600, + "board" : "uno", + "serialDelay" : 20, + "sequenceDelay" : 100, + "cam" : { + "time" : 750, + "delay" : 50, + "momentary" : 300 + }, + "proj" : { + "time" : 1300, + "delay" : 50, + "momentary" : 300 + }, + "black" : { + "before" : 250, + "after" : 250 + }, + "cmd" : { + "debug" : "d", + "connect": "i", + "light" : "l", + "camera" : "c", + "projector" : "p", + "black" : "b", + "cam_forward" : "e", + "cam_backward" : "f", + "proj_forward" : "g", + "proj_backward" : "h", + "proj_identifier" : "j", + "cam_identifier" : "k", + "mcopy_identifier" : "m", + "cam_timed" : "n", + "proj_identifier" : "j", + "cam_identifier" : "k", + "light_identifier" : "o", + "proj_light_identifier" : "q", + "proj_cam_light_identifier" : "r", + "proj_cam_identifier" : "s" + } + } +} \ No newline at end of file diff --git a/app/index.html b/app/index.html index 23322dd..28d8275 100644 --- a/app/index.html +++ b/app/index.html @@ -11,7 +11,7 @@ - +
@@ -213,24 +213,38 @@
-

Devices

- - -

Projector

- -

Camera

- - -

Light

- +
+
+

Devices

+ + +
+
+

Projector

+ +
+
+

Camera

+ + +
+
+ + +
+
+

Light

+ +
+
diff --git a/app/install.sh b/app/install.sh index 27ed944..d7d13a1 100644 --- a/app/install.sh +++ b/app/install.sh @@ -3,4 +3,3 @@ npm install -g gulp electron npm install ./node_modules/.bin/electron-rebuild -mkdir logs diff --git a/app/less/app.less b/app/less/app.less index 9813cf7..e230c10 100644 --- a/app/less/app.less +++ b/app/less/app.less @@ -6,6 +6,7 @@ @import "./seq.less"; @import "./cmd.less"; @import "./scroll.less"; +@import "./settings.less"; #log{ position: fixed; diff --git a/app/less/cmd.less b/app/less/cmd.less index 5341c98..141b14f 100644 --- a/app/less/cmd.less +++ b/app/less/cmd.less @@ -8,6 +8,7 @@ .cmd{ width: 240px; text-align: center; + margin: 0 auto; i{ float: left; margin-right: 5px; diff --git a/app/less/settings.less b/app/less/settings.less new file mode 100644 index 0000000..2cc2ed3 --- /dev/null +++ b/app/less/settings.less @@ -0,0 +1,27 @@ +#settings{ + > div{ + width: 300px; + margin: 0 auto; + } + > div > div{ + width: 360px; + } + input[type=text], select{ + .button(); + display: inline-block; + padding: 6px 12px; + font-size: 21px; + min-width: 300px; + } + button{ + margin-top: -1px; + float: right; + } + input[type=radio]{ + float: right; + margin-right: 20px; + } + .spacer{ + margin-top: 10px; + } +} \ No newline at end of file diff --git a/app/lib/arduino/index.js b/app/lib/arduino/index.js index 9271150..139ccb6 100644 --- a/app/lib/arduino/index.js +++ b/app/lib/arduino/index.js @@ -1,7 +1,11 @@ 'use strict' const SerialPort = require('serialport') +const Readline = SerialPort.parsers.Readline const exec = require('child_process').exec +const parser = new Readline('') +const newlineRe = new RegExp('\n', 'g') +const returnRe = new RegExp('\r', 'g') let eventEmitter const mcopy = {} @@ -109,8 +113,8 @@ mcopy.arduino.connect = function (serial, device, confirm, callback) { mcopy.arduino.alias[serial] = device; mcopy.arduino.serial[device] = new SerialPort(mcopy.arduino.path[serial], { autoOpen : false, - baudrate: mcopy.cfg.arduino.baud, - parser: SerialPort.parsers.readline("\n") + baudRate: mcopy.cfg.arduino.baud, + parser: parser }); mcopy.arduino.serial[device].open(error => { if (error) { @@ -120,13 +124,15 @@ mcopy.arduino.connect = function (serial, device, confirm, callback) { console.log(`Opened connection with ${mcopy.arduino.path[serial]} as ${serial}`); if (!confirm) { mcopy.arduino.serial[device].on('data', data => { - data = data.replace('\r', '') - mcopy.arduino.end(data) + let d = data.toString('utf8') + d = d.replace(newlineRe, '').replace(returnRe, '') + mcopy.arduino.end(d) }) } else { mcopy.arduino.serial[device].on('data', data => { - data = data.replace('\r', '') - mcopy.arduino.confirmEnd(data) + let d = data.toString('utf8') + d = d.replace(newlineRe, '').replace(returnRe, '') + mcopy.arduino.confirmEnd(d) }) } if (callback) { @@ -138,6 +144,7 @@ mcopy.arduino.connect = function (serial, device, confirm, callback) { mcopy.arduino.confirmExec = {}; mcopy.arduino.confirmEnd = function (data) { + //console.dir(data) if (data === mcopy.cfg.arduino.cmd.connect || data === mcopy.cfg.arduino.cmd.proj_identifier || data === mcopy.cfg.arduino.cmd.cam_identifier diff --git a/app/lib/database/index.js b/app/lib/database/index.js index 88d0f7f..6e8a29e 100644 --- a/app/lib/database/index.js +++ b/app/lib/database/index.js @@ -1,9 +1,12 @@ 'use strict' const os = require('os') +const path = require('os') const sqlite3 = require('sqlite3') const squel = require('squel') +const PATH = path.join(os.homedir(), '.mcopy/mcopy.db') + const actionTable = `CREATE TABLE IF NOT EXISTS actions ( time INTEGER PRIMARY KEY, type TEXT, @@ -11,6 +14,21 @@ const actionTable = `CREATE TABLE IF NOT EXISTS actions ( counter INTEGER, light TEXT, dir INTEGER, - sequence INTEGER + sequence INTEGER, + device TEXT +);` -);` \ No newline at end of file +var checkDir = function () { + const dir = path.join(os.homedir(), '.mcopy/') + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } +} + +class DB { + constructor () { + + } +} + +module.exports = DB diff --git a/app/lib/intval/index.js b/app/lib/intval/index.js index 526921d..d7a836d 100644 --- a/app/lib/intval/index.js +++ b/app/lib/intval/index.js @@ -11,7 +11,7 @@ class Intval { const timeStart = +new Date() const baseUrl = devices[device] const url = `${baseUrl}/frame` - console.log(url) + //console.log(url) req(url, (err, res, body) => { let ms = (+new Date()) - timeStart if (err) { @@ -24,7 +24,7 @@ class Intval { const timeStart = +new Date() const baseUrl = devices[device] const url = `${baseUrl}/dir?dir=${dir}` - console.log(url) + //console.log(url) req(url, (err, res, body) => { let ms = (+new Date()) - timeStart if (err) { @@ -38,7 +38,7 @@ class Intval { const timeStart = +new Date() const baseUrl = devices[device] const url = `${baseUrl}/exposure?exposure=${exposure}` - console.log(url) + //console.log(url) req(url, (err, res, body) => { let ms = (+new Date()) - timeStart if (err) { diff --git a/app/lib/server/index.js b/app/lib/server/index.js index 31ec748..c1a1f1c 100644 --- a/app/lib/server/index.js +++ b/app/lib/server/index.js @@ -9,63 +9,67 @@ let proj let light class Server { - constructor (mcopy) { + constructor (camera, projector, light) { restify = require('restify') os = require('os') - app = express() + app = restify.createServer({ + name: 'mcopy-server', + version: '2.0.0' + }) + this.ip = this.getIp() - this.getIp() - app.get('/', function (req, res) { + /*app.get('/', function (req, res) { mcopy.mobile.log('Device connected'); res.send(fs.readFileSync('tmpl/mcopy_index.html', 'utf8')); + }) + app.get('/js/mcopy_mobile.js', function (req, res) { + res.send(fs.readFileSync('js/mcopy_mobile.js', 'utf8')); }); - app.get('/js/mcopy_mobile.js', function (req, res) { - res.send(fs.readFileSync('js/mcopy_mobile.js', 'utf8')); - }); - app.get('/js/jquery.js', function (req, res) { - res.send(fs.readFileSync('js/jquery.js', 'utf8')); - }); - app.get('/cmd/:cmd', function (req, res) { - var cmd, - success = function (res) { - var obj = { - success: true, - cmd : cmd, - cam : mcopy.state.camera, - proj : mcopy.state.projector + app.get('/js/jquery.js', function (req, res) { + res.send(fs.readFileSync('js/jquery.js', 'utf8')); + }); + app.get('/cmd/:cmd', function (req, res) { + var cmd, + success = function (res) { + var obj = { + success: true, + cmd : cmd, + cam : mcopy.state.camera, + proj : mcopy.state.projector + } + res.json(obj); + }; + if (typeof req.params.cmd !== 'undefined') { + mcopy.log('Receiving command from mobile: ' + req.params.cmd); + cmd = req.params.cmd; + if (cmd === 'CF'){ + mcopy.cmd.cam_forward(success); + } else if (cmd === 'CB') { + mcopy.cmd.cam_backward(success); + } else if (cmd === 'PF') { + mcopy.cmd.proj_forward(success); + } else if (cmd === 'PB') { + mcopy.cmd.proj_backward(success); + } else { + mcopy.mobile.fail(res, 'Command ' + cmd + ' not found'); } - res.json(obj); - }; - if (typeof req.params.cmd !== 'undefined') { - mcopy.log('Receiving command from mobile: ' + req.params.cmd); - cmd = req.params.cmd; - if (cmd === 'CF'){ - mcopy.cmd.cam_forward(success); - } else if (cmd === 'CB') { - mcopy.cmd.cam_backward(success); - } else if (cmd === 'PF') { - mcopy.cmd.proj_forward(success); - } else if (cmd === 'PB') { - mcopy.cmd.proj_backward(success); } else { - mcopy.mobile.fail(res, 'Command ' + cmd + ' not found'); + mcopy.mobile.fail(res, 'No command provided'); } - } else { - mcopy.mobile.fail(res, 'No command provided'); - } - }); - app.get('/state', function (req, res) { - res.json({ - cam: mcopy.state.camera, - proj: mcopy.state.projector }); - }); - var http = require('http'); - http.createServer(app).listen(mcopy.cfg.ext_port); + app.get('/state', function (req, res) { + res.json({ + cam: mcopy.state.camera, + proj: mcopy.state.projector + }); + });*/ + + } end () { app.close() + app = null } } diff --git a/app/lib/settings/index.js b/app/lib/settings/index.js index 0725ffd..78b1256 100644 --- a/app/lib/settings/index.js +++ b/app/lib/settings/index.js @@ -1,5 +1,3 @@ -'use strict' - const os = require('os'); const path = require('path'); const fs = require('fs'); @@ -11,42 +9,61 @@ settings.state = { port : 1111, enabled : true }, + devices : [], camera : {}, projector : {}, light : {} } settings.checkDir = function () { - const dir = path.join(os.homedir(), '.mcopy/') + 'use strict' + const dir = path.join(os.homedir(), '.mcopy/'); if (!fs.existsSync(dir)) { fs.mkdirSync(dir); } } settings.save = function () { + 'use strict' const str = JSON.stringify(settings.state, null, '\t'); - settings.checkDir() + settings.checkDir(); fs.writeFile(settings.file, str, 'utf8', (err) => { if (err) console.error(err); }) } settings.update = function (key, val) { - settings.state[key] = val + 'use strict' + settings.state[key] = val; } settings.get = function (key) { - return settings.state[key] + 'use strict' + return settings.state[key]; +} + +settings.all = function () { + 'use strict' + return settings.state; } settings.restore = function () { - let str - settings.checkDir() + 'use strict' + let str; + settings.checkDir(); if (fs.existsSync(settings.file)) { str = fs.readFileSync(settings.file, 'utf8') - settings.state = JSON.parse(str) + settings.state = JSON.parse(str); } else { - settings.save() + settings.save(); } } +settings.reset = function () { + 'use strict' + if (fs.existsSync(settings.file)) { + fs.unlinkSync(settings.file); + } + settings.restore(); +}; + module.exports = settings \ No newline at end of file diff --git a/app/lib/ui/cmd.js b/app/lib/ui/cmd.js index a8b9a80..9996bbf 100644 --- a/app/lib/ui/cmd.js +++ b/app/lib/ui/cmd.js @@ -3,9 +3,11 @@ var cmd = {}; cmd.proj_forward = function (callback) { 'use strict'; var res = function (ms) { + $('#cmd_proj_forward').removeClass('active'); gui.updateState(); if (callback) { callback(ms); } }; + $('#cmd_proj_forward').addClass('active'); if (!mcopy.state.projector.direction) { proj.set(true, function (ms) { setTimeout(function () { @@ -21,9 +23,11 @@ cmd.proj_forward = function (callback) { cmd.proj_backward = function (callback) { 'use strict'; var res = function (ms) { + $('#cmd_proj_backward').removeClass('active'); gui.updateState(); if (callback) { callback(ms); } }; + $('#cmd_proj_backward').addClass('active'); if (mcopy.state.projector.direction) { proj.set(false, function (ms) { setTimeout(function () { @@ -38,15 +42,18 @@ cmd.proj_backward = function (callback) { }; cmd.cam_forward = function (rgb, callback) { 'use strict'; + var off = [0, 0, 0]; var res = function (ms) { gui.updateState(); setTimeout(function () { - light.display([0,0,0]); - light.set([0, 0, 0], function () { + light.display(off); + light.set(off, function () { + $('#cmd_cam_forward').removeClass('active'); if (callback) { callback(ms); } }); }, mcopy.cfg.arduino.serialDelay); }; + $('#cmd_cam_forward').addClass('active'); if (!mcopy.state.camera.direction) { cam.set(true, function () { setTimeout( function () { @@ -70,17 +77,43 @@ cmd.cam_forward = function (rgb, callback) { cmd.black_forward = function (callback) { 'use strict'; var off = [0, 0, 0]; - cmd.cam_forward(off, callback); + var res = function (ms) { + $('#cmd_black_forward').removeClass('active'); + gui.updateState(); + }; + $('#cmd_black_forward').addClass('active'); + if (!mcopy.state.camera.direction) { + cam.set(true, function () { + setTimeout( function () { + light.display(off); + light.set(off, function () { + setTimeout( function () { + cam.move(res); + }, mcopy.cfg.arduino.serialDelay); + }); + }, mcopy.cfg.arduino.serialDelay); + }); + } else { + light.display(off); + light.set(off, function () { + setTimeout(function () { + cam.move(res); + }, mcopy.cfg.arduino.serialDelay); + }); + } }; cmd.cam_backward = function (rgb, callback) { 'use strict'; + var off = [0, 0, 0]; var res = function (ms) { gui.updateState(); - light.display([0,0,0]); - light.set([0, 0, 0], function () { + light.display(off); + light.set(off, function () { + $('#cmd_cam_backward').removeClass('active'); if (callback) { callback(ms); } }); }; + $('#cmd_cam_backward').addClass('active'); if (mcopy.state.camera.direction) { cam.set(false, function () { setTimeout(function () { @@ -102,7 +135,28 @@ cmd.cam_backward = function (rgb, callback) { cmd.black_backward = function (callback) { 'use strict'; var off = [0, 0, 0]; - cmd.cam_backward(off, callback); + var res = function (ms) { + $('#cmd_black_backward').removeClass('active'); + gui.updateState(); + }; + $('#cmd_black_backward').addClass('active'); + if (mcopy.state.camera.direction) { + cam.set(false, function () { + setTimeout(function () { + light.display(off); + light.set(off, function () { + cam.move(res); + }); + }, mcopy.cfg.arduino.serialDelay); + }); + } else { + setTimeout(function () { + light.display(off); + light.set(off, function () { + cam.move(res); + }); + }, mcopy.cfg.arduino.serialDelay); + } }; module.exports = cmd; \ No newline at end of file diff --git a/app/lib/ui/devices.js b/app/lib/ui/devices.js index 4db67ae..25055c6 100644 --- a/app/lib/ui/devices.js +++ b/app/lib/ui/devices.js @@ -8,22 +8,22 @@ devices.init = function () { }; devices.listen = function () { 'use strict'; - let opt - ipcRenderer.on('ready', function (event, arg) { - opt = $('