Port shared modules to typescript. Migrate shared modules first, then look at individual needs of sub-projects.
This commit is contained in:
parent
806342b623
commit
aa5bbfc9fd
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,82 @@
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><a href="#delay">delay(ms)</a> ⇒ <code>Promise</code></dt>
|
||||||
|
<dd><p>Pause the process for X milliseconds in async/await functions</p>
|
||||||
|
</dd>
|
||||||
|
<dt><a href="#send">send(device, cmd)</a> ⇒ <code>Promise</code></dt>
|
||||||
|
<dd><p>Send a command to an Arduino using async/await</p>
|
||||||
|
</dd>
|
||||||
|
<dt><a href="#write">write(device, str)</a> ⇒ <code>Promise</code></dt>
|
||||||
|
<dd><p>Send a string to an Arduino using async/await</p>
|
||||||
|
</dd>
|
||||||
|
<dt><a href="#open">open(device)</a> ⇒ <code>Promise</code></dt>
|
||||||
|
<dd><p>Connect to an Arduino using async/await</p>
|
||||||
|
</dd>
|
||||||
|
<dt><a href="#close">close(device)</a> ⇒ <code>Promise</code></dt>
|
||||||
|
<dd><p>Close a connection to an Arduino using async/await</p>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<a name="delay"></a>
|
||||||
|
|
||||||
|
## delay(ms) ⇒ <code>Promise</code>
|
||||||
|
Pause the process for X milliseconds in async/await functions
|
||||||
|
|
||||||
|
**Kind**: global function
|
||||||
|
**Returns**: <code>Promise</code> - Resolves after wait
|
||||||
|
|
||||||
|
| Param | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| ms | <code>integer</code> | milliseconds |
|
||||||
|
|
||||||
|
<a name="send"></a>
|
||||||
|
|
||||||
|
## send(device, cmd) ⇒ <code>Promise</code>
|
||||||
|
Send a command to an Arduino using async/await
|
||||||
|
|
||||||
|
**Kind**: global function
|
||||||
|
**Returns**: <code>Promise</code> - Resolves after sending
|
||||||
|
|
||||||
|
| Param | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| device | <code>string</code> | Arduino identifier |
|
||||||
|
| cmd | <code>string</code> | Single character command to send |
|
||||||
|
|
||||||
|
<a name="write"></a>
|
||||||
|
|
||||||
|
## write(device, str) ⇒ <code>Promise</code>
|
||||||
|
Send a string to an Arduino using async/await
|
||||||
|
|
||||||
|
**Kind**: global function
|
||||||
|
**Returns**: <code>Promise</code> - Resolves after sending
|
||||||
|
|
||||||
|
| Param | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| device | <code>string</code> | Arduino identifier |
|
||||||
|
| str | <code>string</code> | String to send |
|
||||||
|
|
||||||
|
<a name="open"></a>
|
||||||
|
|
||||||
|
## open(device) ⇒ <code>Promise</code>
|
||||||
|
Connect to an Arduino using async/await
|
||||||
|
|
||||||
|
**Kind**: global function
|
||||||
|
**Returns**: <code>Promise</code> - Resolves after opening
|
||||||
|
|
||||||
|
| Param | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| device | <code>string</code> | Arduino identifier |
|
||||||
|
|
||||||
|
<a name="close"></a>
|
||||||
|
|
||||||
|
## close(device) ⇒ <code>Promise</code>
|
||||||
|
Close a connection to an Arduino using async/await
|
||||||
|
|
||||||
|
**Kind**: global function
|
||||||
|
**Returns**: <code>Promise</code> - Resolves after closing
|
||||||
|
|
||||||
|
| Param | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| device | <code>string</code> | Arduino identifier |
|
||||||
|
|
|
@ -0,0 +1,372 @@
|
||||||
|
'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;
|
||||||
|
let cfg;
|
||||||
|
/**
|
||||||
|
* Pause the process for X milliseconds in async/await functions
|
||||||
|
*
|
||||||
|
* @param {integer} ms milliseconds
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after wait
|
||||||
|
**/
|
||||||
|
async function delay(ms) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
return setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Send a command to an Arduino using async/await
|
||||||
|
*
|
||||||
|
* @param {string} device Arduino identifier
|
||||||
|
* @param {string} cmd Single character command to send
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after sending
|
||||||
|
**/
|
||||||
|
async function send(device, cmd) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
arduino.queue[cmd] = (ms) => {
|
||||||
|
return resolve(ms);
|
||||||
|
};
|
||||||
|
return arduino.serial[device].write(cmd, (err, results) => {
|
||||||
|
if (err) {
|
||||||
|
//console.error(err)
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Send a string to an Arduino using async/await
|
||||||
|
*
|
||||||
|
* @param {string} device Arduino identifier
|
||||||
|
* @param {string} str String to send
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after sending
|
||||||
|
**/
|
||||||
|
async function write(device, str) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
arduino.serial[device].write(str, function (err, results) {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
//console.log('sent: ' + str)
|
||||||
|
return resolve(results);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Connect to an Arduino using async/await
|
||||||
|
*
|
||||||
|
* @param {string} device Arduino identifier
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after opening
|
||||||
|
**/
|
||||||
|
async function openArduino(device) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
return arduino.serial[device].open(error => {
|
||||||
|
if (error) {
|
||||||
|
return reject(error);
|
||||||
|
}
|
||||||
|
return resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Close a connection to an Arduino using async/await
|
||||||
|
*
|
||||||
|
* @param {string} device Arduino identifier
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after closing
|
||||||
|
**/
|
||||||
|
async function closeArduino(device) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
return arduino.serial[device].close((err) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
return resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/******
|
||||||
|
Arduino handlers
|
||||||
|
*******/
|
||||||
|
const arduino = {
|
||||||
|
path: {},
|
||||||
|
known: [
|
||||||
|
'/dev/tty.usbmodem1a161',
|
||||||
|
'/dev/tty.usbserial-A800f8dk',
|
||||||
|
'/dev/tty.usbserial-A900cebm',
|
||||||
|
'/dev/tty.usbmodem1a131',
|
||||||
|
'/dev/tty.usbserial-a900f6de',
|
||||||
|
'/dev/tty.usbmodem1a141',
|
||||||
|
'/dev/ttyACM0',
|
||||||
|
'COM3'
|
||||||
|
],
|
||||||
|
alias: {},
|
||||||
|
serial: {
|
||||||
|
connect: {},
|
||||||
|
projector: {},
|
||||||
|
camera: {},
|
||||||
|
light: {}
|
||||||
|
},
|
||||||
|
baud: 57600,
|
||||||
|
queue: {},
|
||||||
|
timer: 0,
|
||||||
|
lock: false,
|
||||||
|
locks: {}
|
||||||
|
};
|
||||||
|
arduino.enumerate = async function () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
return SerialPort.list((err, ports) => {
|
||||||
|
let matches = [];
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
ports.forEach(port => {
|
||||||
|
if (arduino.known.indexOf(port.comName) !== -1) {
|
||||||
|
matches.push(port.comName);
|
||||||
|
}
|
||||||
|
else if ((port.manufacturer + '').toLowerCase().indexOf('arduino') !== -1) {
|
||||||
|
matches.push(port.comName);
|
||||||
|
}
|
||||||
|
else if ((port.comName + '').toLowerCase().indexOf('usbserial') !== -1) {
|
||||||
|
matches.push(port.comName);
|
||||||
|
}
|
||||||
|
else if ((port.comName + '').toLowerCase().indexOf('usbmodem') !== -1) {
|
||||||
|
matches.push(port.comName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (matches.length === 0) {
|
||||||
|
return reject('No USB devices found');
|
||||||
|
}
|
||||||
|
else if (matches.length > 0) {
|
||||||
|
return resolve(matches);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//commands which respond to a sent char
|
||||||
|
arduino.send = async function (serial, cmd, res) {
|
||||||
|
const device = arduino.alias[serial];
|
||||||
|
let results;
|
||||||
|
if (arduino.locks[serial]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
arduino.locks[serial] = true;
|
||||||
|
await delay(cfg.arduino.serialDelay);
|
||||||
|
try {
|
||||||
|
results = await send(device, cmd);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return console.error(e);
|
||||||
|
}
|
||||||
|
arduino.locks[serial] = false;
|
||||||
|
arduino.timer = new Date().getTime();
|
||||||
|
return await eventEmitter.emit('arduino_send', cmd);
|
||||||
|
};
|
||||||
|
//send strings, after char triggers firmware to accept
|
||||||
|
arduino.string = async function (serial, str) {
|
||||||
|
const device = arduino.alias[serial];
|
||||||
|
let writeSuccess;
|
||||||
|
await delay(cfg.arduino.serialDelay);
|
||||||
|
if (typeof arduino.serial[device].fake !== 'undefined'
|
||||||
|
&& arduino.serial[device].fake) {
|
||||||
|
return arduino.serial[device].string(str);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
writeSuccess = await write(device, str);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return console.error(e);
|
||||||
|
}
|
||||||
|
return writeSuccess;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//respond with same char over serial when done
|
||||||
|
arduino.end = async function (serial, data) {
|
||||||
|
const end = new Date().getTime();
|
||||||
|
const ms = end - arduino.timer;
|
||||||
|
let complete;
|
||||||
|
if (arduino.queue[data] !== undefined) {
|
||||||
|
arduino.locks[serial] = false;
|
||||||
|
//console.log('Command ' + data + ' took ' + ms + 'ms');
|
||||||
|
complete = arduino.queue[data](ms); //execute callback
|
||||||
|
eventEmitter.emit('arduino_end', data);
|
||||||
|
delete arduino.queue[data];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//console.log('Received stray "' + data + '"'); //silent to user
|
||||||
|
}
|
||||||
|
return complete;
|
||||||
|
};
|
||||||
|
arduino.alias = function (serial, device) {
|
||||||
|
console.log(`Making "${serial}" an alias of ${device}`);
|
||||||
|
arduino.alias[serial] = device;
|
||||||
|
};
|
||||||
|
arduino.connect = async function (serial, device, confirm) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let connectSuccess;
|
||||||
|
arduino.path[serial] = device;
|
||||||
|
arduino.alias[serial] = device;
|
||||||
|
arduino.serial[device] = new SerialPort(arduino.path[serial], {
|
||||||
|
autoOpen: false,
|
||||||
|
baudRate: cfg.arduino.baud,
|
||||||
|
parser: parser
|
||||||
|
});
|
||||||
|
arduino.locks[device] = false;
|
||||||
|
try {
|
||||||
|
connectSuccess = await openArduino(device);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error('failed to open: ' + e);
|
||||||
|
return reject(e);
|
||||||
|
}
|
||||||
|
console.log(`Opened connection with ${arduino.path[serial]} as ${serial}`);
|
||||||
|
if (!confirm) {
|
||||||
|
arduino.serial[device].on('data', async (data) => {
|
||||||
|
let d = data.toString('utf8');
|
||||||
|
d = d.replace(newlineRe, '').replace(returnRe, '');
|
||||||
|
return await arduino.end(serial, d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arduino.serial[device].on('data', async (data) => {
|
||||||
|
let d = data.toString('utf8');
|
||||||
|
d = d.replace(newlineRe, '').replace(returnRe, '');
|
||||||
|
return await arduino.confirmEnd(d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return resolve(arduino.path[serial]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
arduino.confirmExec = {};
|
||||||
|
arduino.confirmEnd = function (data) {
|
||||||
|
//console.dir(data)
|
||||||
|
if (data === cfg.arduino.cmd.connect
|
||||||
|
|| data === cfg.arduino.cmd.proj_identifier
|
||||||
|
|| data === cfg.arduino.cmd.cam_identifier
|
||||||
|
|| data === cfg.arduino.cmd.light_identifier
|
||||||
|
|| data === cfg.arduino.cmd.proj_light_identifier
|
||||||
|
|| data === cfg.arduino.cmd.proj_cam_light_identifier
|
||||||
|
|| data === cfg.arduino.cmd.proj_cam_identifier) {
|
||||||
|
arduino.confirmExec(null, data);
|
||||||
|
arduino.confirmExec = {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
arduino.verify = async function () {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const device = arduino.alias['connect'];
|
||||||
|
let writeSuccess;
|
||||||
|
arduino.confirmExec = function (err, data) {
|
||||||
|
if (data === cfg.arduino.cmd.connect) {
|
||||||
|
return resolve(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return reject('Wrong data returned');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await delay(cfg.arduino.serialDelay);
|
||||||
|
try {
|
||||||
|
writeSuccess = await send(device, cfg.arduino.cmd.connect);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return reject(e);
|
||||||
|
}
|
||||||
|
return resolve(writeSuccess);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
arduino.distinguish = async function () {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const device = arduino.alias['connect'];
|
||||||
|
let writeSuccess;
|
||||||
|
let type;
|
||||||
|
arduino.confirmExec = function (err, data) {
|
||||||
|
if (data === cfg.arduino.cmd.proj_identifier) {
|
||||||
|
type = 'projector';
|
||||||
|
}
|
||||||
|
else if (data === cfg.arduino.cmd.cam_identifier) {
|
||||||
|
type = 'camera';
|
||||||
|
}
|
||||||
|
else if (data === cfg.arduino.cmd.light_identifier) {
|
||||||
|
type = 'light';
|
||||||
|
}
|
||||||
|
else if (data === cfg.arduino.cmd.proj_light_identifier) {
|
||||||
|
type = 'projector,light';
|
||||||
|
}
|
||||||
|
else if (data === cfg.arduino.cmd.proj_cam_light_identifier) {
|
||||||
|
type = 'projector,camera,light';
|
||||||
|
}
|
||||||
|
else if (data === cfg.arduino.cmd.proj_cam_identifier) {
|
||||||
|
type = 'projector,camera';
|
||||||
|
}
|
||||||
|
else if (data === cfg.ardino.cmd.proj_second_identifier) {
|
||||||
|
type = 'projector_second';
|
||||||
|
}
|
||||||
|
return resolve(type);
|
||||||
|
};
|
||||||
|
await delay(cfg.arduino.serialDelay);
|
||||||
|
try {
|
||||||
|
writeSuccess = await send(device, cfg.arduino.cmd.mcopy_identifier);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
arduino.close = async function (callback) {
|
||||||
|
const device = arduino.alias['connect'];
|
||||||
|
let closeSuccess;
|
||||||
|
try {
|
||||||
|
closeSuccess = await closeArduino(device);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return console.error(e);
|
||||||
|
}
|
||||||
|
return closeSuccess;
|
||||||
|
};
|
||||||
|
arduino.fakeConnect = async function (serial) {
|
||||||
|
//console.log('Connecting to fake arduino...');
|
||||||
|
const device = '/dev/fake';
|
||||||
|
arduino.alias[serial] = device;
|
||||||
|
arduino.serial[device] = {
|
||||||
|
write: function (cmd, cb) {
|
||||||
|
const t = {
|
||||||
|
c: cfg.arduino.cam.time + cfg.arduino.cam.delay,
|
||||||
|
p: cfg.arduino.proj.time + cfg.arduino.proj.delay
|
||||||
|
};
|
||||||
|
let timeout = t[cmd];
|
||||||
|
let end;
|
||||||
|
if (typeof timeout === 'undefined')
|
||||||
|
timeout = 10;
|
||||||
|
arduino.timer = +new Date();
|
||||||
|
setTimeout(() => {
|
||||||
|
arduino.end(serial, cmd);
|
||||||
|
return cb();
|
||||||
|
}, timeout);
|
||||||
|
},
|
||||||
|
string: async function (str) {
|
||||||
|
//do nothing
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
fake: true
|
||||||
|
};
|
||||||
|
//console.log('Connected to fake arduino! Not real! Doesn\'t exist!');
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (typeof module !== 'undefined' && module.parent) {
|
||||||
|
module.exports = function (c, ee) {
|
||||||
|
eventEmitter = ee;
|
||||||
|
cfg = c;
|
||||||
|
return arduino;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "arduino",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
<a name="module_lib/mscript"></a>
|
||||||
|
|
||||||
|
## lib/mscript
|
||||||
|
|
||||||
|
* [lib/mscript](#module_lib/mscript)
|
||||||
|
* [~Mscript](#module_lib/mscript..Mscript)
|
||||||
|
* [.clear()](#module_lib/mscript..Mscript+clear)
|
||||||
|
* [.interpret()](#module_lib/mscript..Mscript+interpret)
|
||||||
|
* [.basic_cmd()](#module_lib/mscript..Mscript+basic_cmd)
|
||||||
|
* [.new_loop()](#module_lib/mscript..Mscript+new_loop)
|
||||||
|
* [.end_loop()](#module_lib/mscript..Mscript+end_loop)
|
||||||
|
* [.move_cam()](#module_lib/mscript..Mscript+move_cam)
|
||||||
|
* [.move_proj()](#module_lib/mscript..Mscript+move_proj)
|
||||||
|
* [.set_state()](#module_lib/mscript..Mscript+set_state)
|
||||||
|
* [.last_loop()](#module_lib/mscript..Mscript+last_loop)
|
||||||
|
* [.parent_loop()](#module_lib/mscript..Mscript+parent_loop)
|
||||||
|
* [.loop_count()](#module_lib/mscript..Mscript+loop_count)
|
||||||
|
* [.fade()](#module_lib/mscript..Mscript+fade)
|
||||||
|
* [.fade_count()](#module_lib/mscript..Mscript+fade_count)
|
||||||
|
* [.fade_start()](#module_lib/mscript..Mscript+fade_start)
|
||||||
|
* [.fade_end()](#module_lib/mscript..Mscript+fade_end)
|
||||||
|
* [.update()](#module_lib/mscript..Mscript+update)
|
||||||
|
* [.str_to_arr()](#module_lib/mscript..Mscript+str_to_arr)
|
||||||
|
* [.light_to_arr()](#module_lib/mscript..Mscript+light_to_arr)
|
||||||
|
* [.light_state()](#module_lib/mscript..Mscript+light_state)
|
||||||
|
* [.fail()](#module_lib/mscript..Mscript+fail)
|
||||||
|
* [~startsWith()](#module_lib/mscript..startsWith)
|
||||||
|
|
||||||
|
<a name="module_lib/mscript..Mscript"></a>
|
||||||
|
|
||||||
|
### lib/mscript~Mscript
|
||||||
|
class Mscript
|
||||||
|
|
||||||
|
**Kind**: inner class of [<code>lib/mscript</code>](#module_lib/mscript)
|
||||||
|
|
||||||
|
* [~Mscript](#module_lib/mscript..Mscript)
|
||||||
|
* [.clear()](#module_lib/mscript..Mscript+clear)
|
||||||
|
* [.interpret()](#module_lib/mscript..Mscript+interpret)
|
||||||
|
* [.basic_cmd()](#module_lib/mscript..Mscript+basic_cmd)
|
||||||
|
* [.new_loop()](#module_lib/mscript..Mscript+new_loop)
|
||||||
|
* [.end_loop()](#module_lib/mscript..Mscript+end_loop)
|
||||||
|
* [.move_cam()](#module_lib/mscript..Mscript+move_cam)
|
||||||
|
* [.move_proj()](#module_lib/mscript..Mscript+move_proj)
|
||||||
|
* [.set_state()](#module_lib/mscript..Mscript+set_state)
|
||||||
|
* [.last_loop()](#module_lib/mscript..Mscript+last_loop)
|
||||||
|
* [.parent_loop()](#module_lib/mscript..Mscript+parent_loop)
|
||||||
|
* [.loop_count()](#module_lib/mscript..Mscript+loop_count)
|
||||||
|
* [.fade()](#module_lib/mscript..Mscript+fade)
|
||||||
|
* [.fade_count()](#module_lib/mscript..Mscript+fade_count)
|
||||||
|
* [.fade_start()](#module_lib/mscript..Mscript+fade_start)
|
||||||
|
* [.fade_end()](#module_lib/mscript..Mscript+fade_end)
|
||||||
|
* [.update()](#module_lib/mscript..Mscript+update)
|
||||||
|
* [.str_to_arr()](#module_lib/mscript..Mscript+str_to_arr)
|
||||||
|
* [.light_to_arr()](#module_lib/mscript..Mscript+light_to_arr)
|
||||||
|
* [.light_state()](#module_lib/mscript..Mscript+light_state)
|
||||||
|
* [.fail()](#module_lib/mscript..Mscript+fail)
|
||||||
|
|
||||||
|
<a name="module_lib/mscript..Mscript+clear"></a>
|
||||||
|
|
||||||
|
#### mscript.clear()
|
||||||
|
Clear the state of the script
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+interpret"></a>
|
||||||
|
|
||||||
|
#### mscript.interpret()
|
||||||
|
Main function, accepts multi-line string, parses into lines
|
||||||
|
and interprets the instructions from the text. Returns an array
|
||||||
|
of steps to be fed into the mcopy.
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+basic_cmd"></a>
|
||||||
|
|
||||||
|
#### mscript.basic\_cmd()
|
||||||
|
Apply a basic two character command
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+new_loop"></a>
|
||||||
|
|
||||||
|
#### mscript.new\_loop()
|
||||||
|
Start a new loop
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+end_loop"></a>
|
||||||
|
|
||||||
|
#### mscript.end\_loop()
|
||||||
|
Close the most recent loop
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+move_cam"></a>
|
||||||
|
|
||||||
|
#### mscript.move\_cam()
|
||||||
|
Move camera to explicitly-defined frame
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+move_proj"></a>
|
||||||
|
|
||||||
|
#### mscript.move\_proj()
|
||||||
|
Move projector to explicitly-defined frame
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+set_state"></a>
|
||||||
|
|
||||||
|
#### mscript.set\_state()
|
||||||
|
Set the state of either the cam or projector
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+last_loop"></a>
|
||||||
|
|
||||||
|
#### mscript.last\_loop()
|
||||||
|
Return the last loop
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+parent_loop"></a>
|
||||||
|
|
||||||
|
#### mscript.parent\_loop()
|
||||||
|
Return the second-last loop
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+loop_count"></a>
|
||||||
|
|
||||||
|
#### mscript.loop\_count()
|
||||||
|
Extract the loop count integer from a LOOP cmd
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+fade"></a>
|
||||||
|
|
||||||
|
#### mscript.fade()
|
||||||
|
Execute a fade of frame length, from color to another color
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+fade_count"></a>
|
||||||
|
|
||||||
|
#### mscript.fade\_count()
|
||||||
|
Extract the fade length integer from a FADE cmd
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+fade_start"></a>
|
||||||
|
|
||||||
|
#### mscript.fade\_start()
|
||||||
|
Extract the start color from a string
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+fade_end"></a>
|
||||||
|
|
||||||
|
#### mscript.fade\_end()
|
||||||
|
Extract the end color from a string
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+update"></a>
|
||||||
|
|
||||||
|
#### mscript.update()
|
||||||
|
Increase the state of a specific object, such as the camera/projector,
|
||||||
|
by the value defined in val
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+str_to_arr"></a>
|
||||||
|
|
||||||
|
#### mscript.str\_to\_arr()
|
||||||
|
Split string on command, extract any integers from string
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+light_to_arr"></a>
|
||||||
|
|
||||||
|
#### mscript.light\_to\_arr()
|
||||||
|
Split a string on a command to extract data for light array
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+light_state"></a>
|
||||||
|
|
||||||
|
#### mscript.light\_state()
|
||||||
|
Split a string to extract an rgb color value
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..Mscript+fail"></a>
|
||||||
|
|
||||||
|
#### mscript.fail()
|
||||||
|
Throw an error with specific message
|
||||||
|
|
||||||
|
**Kind**: instance method of [<code>Mscript</code>](#module_lib/mscript..Mscript)
|
||||||
|
<a name="module_lib/mscript..startsWith"></a>
|
||||||
|
|
||||||
|
### lib/mscript~startsWith()
|
||||||
|
startswith function from lodash, do not want the entire lib for this
|
||||||
|
|
||||||
|
**Kind**: inner method of [<code>lib/mscript</code>](#module_lib/mscript)
|
|
@ -0,0 +1,13 @@
|
||||||
|
# TODO - mscript
|
||||||
|
|
||||||
|
* Add variables and simple evaluation
|
||||||
|
* Add "Light" feature
|
||||||
|
|
||||||
|
Bash-like variables?
|
||||||
|
Similar to LESS/SASS?
|
||||||
|
Makes a tokenization easier
|
||||||
|
|
||||||
|
@ is better than $
|
||||||
|
|
||||||
|
RangeError: Invalid array length
|
||||||
|
at Mscript.str_to_arr (./mcopy/app/lib/mscript/index.js:474:9)
|
|
@ -0,0 +1,545 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/** @module lib/mscript */
|
||||||
|
|
||||||
|
const BLACK = '0,0,0';
|
||||||
|
const WHITE = '255,255,255';
|
||||||
|
const CMD = [
|
||||||
|
'CF',
|
||||||
|
'PF',
|
||||||
|
'BF',
|
||||||
|
'CB',
|
||||||
|
'PB',
|
||||||
|
'BB'
|
||||||
|
];
|
||||||
|
const ALTS = {
|
||||||
|
'CF' : ['CAMERA FORWARD', 'CAM FORWARD'],
|
||||||
|
'PF' : ['PROJECTOR FORWARD', 'PROJ FORWARD'],
|
||||||
|
'BF' : ['BLACK FORWARD', 'BLACK', 'BLANK FORWARD', 'BLANK'],
|
||||||
|
'CB' : ['CAMERA BACKWARD', 'CAM BACKWARD', 'CAMERA BACK', 'CAM BACK'],
|
||||||
|
'PB' : ['PROJECTOR FORWARD', 'PROJ FORWARD', 'PROJECTOR BACK', 'PROJ BACK'],
|
||||||
|
'BB' : ['BLACK BACKWARD', 'BLACK BACK', 'BLANK BACK'],
|
||||||
|
'L ' : ['LIGHT', 'COLOR', 'LAMP'],
|
||||||
|
'F ' : ['FADE']
|
||||||
|
};
|
||||||
|
|
||||||
|
/** helper functions */
|
||||||
|
|
||||||
|
/** startswith function from lodash, do not want the entire lib for this */
|
||||||
|
function startsWith(string, target, position) {
|
||||||
|
const { length } = string;
|
||||||
|
position = position == null ? 0 : position;
|
||||||
|
if (position < 0) {
|
||||||
|
position = 0;
|
||||||
|
} else if (position > length) {
|
||||||
|
position = length;
|
||||||
|
}
|
||||||
|
target = `${target}`;
|
||||||
|
return string.slice(position, position + target.length) == target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** class Mscript */
|
||||||
|
class Mscript {
|
||||||
|
constructor () {
|
||||||
|
this.output = {};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Clear the state of the script
|
||||||
|
*/
|
||||||
|
clear () {
|
||||||
|
this.lines = [];
|
||||||
|
|
||||||
|
this.cam = 0;
|
||||||
|
this.proj = 0;
|
||||||
|
this.color = '';
|
||||||
|
this.loops = [];
|
||||||
|
this.rec = -1;
|
||||||
|
|
||||||
|
this.two = '';
|
||||||
|
this.arr = [];
|
||||||
|
this.light = [];
|
||||||
|
this.target = 0; //move to target using CAM # or PROJ #
|
||||||
|
this.dist = 0;
|
||||||
|
|
||||||
|
this.variables = {};
|
||||||
|
|
||||||
|
this.output = {};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Main function, accepts multi-line string, parses into lines
|
||||||
|
* and interprets the instructions from the text. Returns an array
|
||||||
|
* of steps to be fed into the mcopy.
|
||||||
|
*/
|
||||||
|
interpret (text, callback) {
|
||||||
|
this.clear()
|
||||||
|
|
||||||
|
if (typeof text === 'undefined') {
|
||||||
|
return this.fail('No input');
|
||||||
|
}
|
||||||
|
|
||||||
|
//split string into lines, each containing a command
|
||||||
|
this.lines = text.split('\n');
|
||||||
|
|
||||||
|
this.lines = this.lines.map(line => {
|
||||||
|
line = line.replace(/\t+/g, ''); //strip tabs
|
||||||
|
line = line.trim(); //remove excess whitespace before and after command
|
||||||
|
line = line.toUpperCase();
|
||||||
|
return line;
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let line of this.lines) {
|
||||||
|
this.two = line.substring(0, 2);
|
||||||
|
if (CMD.indexOf(this.two) !== -1) {
|
||||||
|
this.basic_cmd(line);
|
||||||
|
} else if (startsWith(line, '@') || line.indexOf('@') !== -1) {
|
||||||
|
this.variable(line);
|
||||||
|
} else if (startsWith(line, 'LOOP')) {
|
||||||
|
this.new_loop(line);
|
||||||
|
} else if (startsWith(line, 'L ')) {
|
||||||
|
this.light_state(line);
|
||||||
|
} else if (startsWith(line, 'F ')) {
|
||||||
|
this.new_loop(line, true);
|
||||||
|
} else if (startsWith(line, 'END')) {
|
||||||
|
this.end_loop(line);
|
||||||
|
} else if (startsWith(line, 'CAM')) { //directly go to that frame (black?)
|
||||||
|
this.move_cam(line);
|
||||||
|
} else if (startsWith(line, 'PROJ')) { //directly go to that frame
|
||||||
|
this.move_proj(line);
|
||||||
|
} else if (startsWith(line, 'SET')) { //set that state
|
||||||
|
this.set_state(line);
|
||||||
|
} else if (startsWith(line, '#') || startsWith(line, '//')) {
|
||||||
|
//comments
|
||||||
|
//ignore while parsing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.output.success = true;
|
||||||
|
this.output.arr = this.arr; //all instructions
|
||||||
|
this.output.light = this.light; //all light instructions
|
||||||
|
this.output.cam = this.cam;
|
||||||
|
this.output.proj = this.proj;
|
||||||
|
|
||||||
|
if (typeof callback !== 'undefined') {
|
||||||
|
//should only be invoked by running mscript.tests()
|
||||||
|
callback(this.output);
|
||||||
|
} else {
|
||||||
|
return this.output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variable (line) {
|
||||||
|
let parts = line.split('=');
|
||||||
|
let key = parts[0];
|
||||||
|
let value = parts[1];
|
||||||
|
let update = false;
|
||||||
|
|
||||||
|
if (value && value.indexOf('#') !== -1) {
|
||||||
|
value = value.split('#')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && value.indexOf('//') !== -1) {
|
||||||
|
value = value.split('//')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && value.indexOf('+') !== -1) {
|
||||||
|
if (value)
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.indexOf('-') !== -1) {
|
||||||
|
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.indexOf(',') === -1) { //if not color string
|
||||||
|
try {
|
||||||
|
value = parseInt(value);
|
||||||
|
} catch (err) {
|
||||||
|
//supress parsing error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.dir(parts)
|
||||||
|
if (!this.variables[key] || update) {
|
||||||
|
this.variables[key] = value;
|
||||||
|
}
|
||||||
|
console.dir(this.variables)
|
||||||
|
}
|
||||||
|
variable_replace(line) {
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Apply a basic two character command
|
||||||
|
*/
|
||||||
|
basic_cmd (line) {
|
||||||
|
if (this.rec !== -1) {
|
||||||
|
//hold generated arr in state loop array
|
||||||
|
this.loops[this.rec].arr
|
||||||
|
.push.apply(this.loops[this.rec].arr,
|
||||||
|
this.str_to_arr(line,
|
||||||
|
this.two));
|
||||||
|
this.loops[this.rec].light
|
||||||
|
.push.apply(this.loops[this.rec].light,
|
||||||
|
this.light_to_arr(line,
|
||||||
|
this.two));
|
||||||
|
} else {
|
||||||
|
this.arr.push.apply(this.arr, this.str_to_arr(line, this.two));
|
||||||
|
this.light.push.apply(this.light, this.light_to_arr(line, this.two))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Start a new loop
|
||||||
|
*/
|
||||||
|
new_loop (line, fade) {
|
||||||
|
this.rec++;
|
||||||
|
this.loops[this.rec] = {
|
||||||
|
arr : [],
|
||||||
|
light : [],
|
||||||
|
cam : 0,
|
||||||
|
proj : 0,
|
||||||
|
cmd : line + ''
|
||||||
|
};
|
||||||
|
if (fade) {
|
||||||
|
this.fade(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Close the most recent loop
|
||||||
|
*/
|
||||||
|
end_loop (line) {
|
||||||
|
let light_arr;
|
||||||
|
let start;
|
||||||
|
let end;
|
||||||
|
let len;
|
||||||
|
|
||||||
|
for (let x = 0; x < this.loop_count(this.loops[this.rec].cmd); x++) {
|
||||||
|
light_arr = this.loops[this.rec].light;
|
||||||
|
if (this.loops[this.rec].fade) {
|
||||||
|
start = this.loops[this.rec].start;
|
||||||
|
end = this.loops[this.rec].end;
|
||||||
|
len = this.loops[this.rec].fade_len;
|
||||||
|
light_arr = light_arr.map(l => {
|
||||||
|
return this.fade_rgb(start, end, len, x);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.rec === 0) {
|
||||||
|
this.arr.push.apply(this.arr, this.loops[this.rec].arr);
|
||||||
|
this.light.push.apply(this.light, light_arr);
|
||||||
|
} else if (this.rec >= 1) {
|
||||||
|
this.loops[this.rec - 1].arr
|
||||||
|
.push.apply(this.loops[this.rec - 1].arr,
|
||||||
|
this.loops[this.rec].arr);
|
||||||
|
|
||||||
|
this.loops[this.rec - 1].light
|
||||||
|
.push.apply(this.loops[this.rec - 1].light,
|
||||||
|
light_arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.update('END', this.loop_count(this.loops[this.rec].cmd));
|
||||||
|
delete this.loops[this.rec];
|
||||||
|
this.rec--;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Move camera to explicitly-defined frame
|
||||||
|
*/
|
||||||
|
move_cam (line) {
|
||||||
|
this.target = parseInt(line.split('CAM ')[1]);
|
||||||
|
if (this.rec !== -1) {
|
||||||
|
if (this.target > this.cam) {
|
||||||
|
this.dist = this.target - this.cam;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.loops[this.rec].arr.push('BF');
|
||||||
|
this.loops[this.rec].light.push(BLACK);
|
||||||
|
this.update('BF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dist = this.cam - this.target;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.loops[this.rec].arr.push('BB');
|
||||||
|
this.loops[this.rec].light.push(BLACK);
|
||||||
|
this.update('BB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (target > this.cam) {
|
||||||
|
this.dist = this.target - this.cam;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.arr.push('BF');
|
||||||
|
this.light.push(BLACK);
|
||||||
|
this.update('BF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dist = this.cam - this.target;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.arr.push('BB');
|
||||||
|
this.light.push(BLACK);
|
||||||
|
this.update('BB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Move projector to explicitly-defined frame
|
||||||
|
*/
|
||||||
|
move_proj (line) {
|
||||||
|
this.target = parseInt(line.split('PROJ ')[1]);
|
||||||
|
if (this.rec !== -1) {
|
||||||
|
if (this.target > this.proj) {
|
||||||
|
this.dist = this.target - this.proj;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.loops[this.rec].arr.push('PF');
|
||||||
|
this.loops[this.rec].light.push('');
|
||||||
|
this.update('PF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dist = this.proj - this.target;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.loops[this.rec].arr.push('PB');
|
||||||
|
this.loops[this.rec].light.push('');
|
||||||
|
this.update('PB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.target > this.proj) {
|
||||||
|
this.dist = this.target - this.proj;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.arr.push('PF');
|
||||||
|
this.light.push('');
|
||||||
|
this.update('PF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dist = this.proj - this.target;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.arr.push('PB');
|
||||||
|
this.light.push('');
|
||||||
|
this.update('PB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the state of either the cam or projector
|
||||||
|
*/
|
||||||
|
set_state (line) {
|
||||||
|
if (startsWith(line, 'SET CAM')) {
|
||||||
|
this.cam = parseInt(line.split('SET CAM')[1]);
|
||||||
|
} else if (startsWith(line, 'SET PROJ')) {
|
||||||
|
this.proj = parseInt(line.split('SET PROJ')[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return the last loop
|
||||||
|
*/
|
||||||
|
last_loop () {
|
||||||
|
return this.loops[this.loops.length - 1];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return the second-last loop
|
||||||
|
*/
|
||||||
|
parent_loop () {
|
||||||
|
return this.loops[this.loops.length - 2];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract the loop count integer from a LOOP cmd
|
||||||
|
*/
|
||||||
|
loop_count (str) {
|
||||||
|
return parseInt(str.split(' ')[1]);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Execute a fade of frame length, from color to another color
|
||||||
|
*/
|
||||||
|
fade (line) {
|
||||||
|
let len = this.fade_count(line);
|
||||||
|
let start = this.fade_start(line);
|
||||||
|
let end = this.fade_end(line);
|
||||||
|
|
||||||
|
this.loops[this.rec].start = start;
|
||||||
|
this.loops[this.rec].end = end;
|
||||||
|
this.loops[this.rec].fade = true;
|
||||||
|
this.loops[this.rec].fade_count = 0;
|
||||||
|
this.loops[this.rec].fade_len = len;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract the fade length integer from a FADE cmd
|
||||||
|
*/
|
||||||
|
fade_count (str) {
|
||||||
|
return parseInt(str.split(' ')[1]);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract the start color from a string
|
||||||
|
*/
|
||||||
|
fade_start (str) {
|
||||||
|
let color = str.split(' ')[2];
|
||||||
|
return this.rgb(color.trim())
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract the end color from a string
|
||||||
|
*/
|
||||||
|
fade_end (str) {
|
||||||
|
let color = str.split(' ')[3];
|
||||||
|
return this.rgb(color.trim())
|
||||||
|
}
|
||||||
|
fade_rgb (start, end, len, x) {
|
||||||
|
let cur = [];
|
||||||
|
let diff;
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
if (x === len - 1) {
|
||||||
|
cur[i] = end[i];
|
||||||
|
} else if (start[i] >= end[i]) {
|
||||||
|
diff = start[i] - end[i];
|
||||||
|
cur[i] = start[i] - Math.round((diff / (len - 1)) * x);
|
||||||
|
} else {
|
||||||
|
diff = end[i] - start[i];
|
||||||
|
cur[i] = start[i] + Math.round((diff / (len - 1)) * x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.rgb_str(cur);
|
||||||
|
|
||||||
|
}
|
||||||
|
rgb (str) {
|
||||||
|
let rgb = str.split(',');
|
||||||
|
return rgb.map( char => {
|
||||||
|
return parseInt(char);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
rgb_str (arr) {
|
||||||
|
return arr.join(',');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Increase the state of a specific object, such as the camera/projector,
|
||||||
|
* by the value defined in val
|
||||||
|
*/
|
||||||
|
update (cmd, val = 1) {
|
||||||
|
if (cmd === 'END') {
|
||||||
|
//I don't understand this loop
|
||||||
|
for (let i = 0; i < val; i++) {
|
||||||
|
if (this.rec === 0) {
|
||||||
|
this.cam += this.loops[this.rec].cam;
|
||||||
|
this.proj += this.loops[this.rec].proj;
|
||||||
|
} else if (this.rec >= 1) {
|
||||||
|
this.loops[this.rec - 1].cam += this.loops[this.rec].cam;
|
||||||
|
this.loops[this.rec - 1].proj += this.loops[this.rec].proj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (cmd === 'CF') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.cam += val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].cam += val;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'CB') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.cam -= val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].cam--;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'PF') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.proj += val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].proj += val;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'PB') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.proj -= val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].proj--;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'BF') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.cam += val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].cam += val;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'BB') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.cam -= val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].cam -= val;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'L ') {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Split string on command, extract any integers from string
|
||||||
|
*/
|
||||||
|
str_to_arr (str, cmd) {
|
||||||
|
const cnt = str.split(cmd);
|
||||||
|
let c = parseInt(cnt[1]);
|
||||||
|
let arr = [];
|
||||||
|
if (cnt[1] === '') {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = parseInt(cnt[1]);
|
||||||
|
}
|
||||||
|
arr = new Array(c).fill(cmd);
|
||||||
|
this.update(cmd, c);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Split a string on a command to extract data for light array
|
||||||
|
*/
|
||||||
|
light_to_arr (str, cmd) {
|
||||||
|
const cnt = str.split(cmd);
|
||||||
|
let c = parseInt(cnt[1]);
|
||||||
|
let arr = [];
|
||||||
|
if (cnt[1] === '') {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = parseInt(cnt[1]);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < c; i++) {
|
||||||
|
if (cmd === 'CF'
|
||||||
|
|| cmd === 'CB') {
|
||||||
|
arr.push(this.color);
|
||||||
|
} else if (cmd === 'BF'
|
||||||
|
|| cmd === 'BB') {
|
||||||
|
arr.push(BLACK);
|
||||||
|
} else {
|
||||||
|
arr.push('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Split a string to extract an rgb color value
|
||||||
|
*/
|
||||||
|
light_state (str) {
|
||||||
|
//add parsers for other color spaces
|
||||||
|
const color = str.replace('L ', '').trim();
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw an error with specific message
|
||||||
|
*/
|
||||||
|
fail (msg) {
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Mscript;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
CAM # - go to camera frame #
|
||||||
|
PROJ # - go to projector frame #
|
||||||
|
|
||||||
|
SET CAM # - sets camera count to #
|
||||||
|
SET PROJ # - sets projector count to #
|
||||||
|
|
||||||
|
LOOP # - begin loop, can nest recursively, # times
|
||||||
|
END LOOP - (or END) closes loop
|
||||||
|
|
||||||
|
L #RGB - sets light to rgb value
|
||||||
|
|
||||||
|
FADE 24 0,0,0 255,255,255
|
||||||
|
|
||||||
|
CF - Camera forwards
|
||||||
|
PF - Projector forwards
|
||||||
|
BF - Black forwards
|
||||||
|
CB - Camera backwards
|
||||||
|
PB - Projector backwards
|
||||||
|
BB - Black backwards
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,476 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/** @module lib/mscript */
|
||||||
|
|
||||||
|
let fs;
|
||||||
|
let input;
|
||||||
|
|
||||||
|
/** object mscript */
|
||||||
|
const mscript = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for the presence of specific arguments in process
|
||||||
|
* argv
|
||||||
|
*
|
||||||
|
* @param {string} shrt Short version of argument or flag
|
||||||
|
* @param {string} lng Long version of argument or flag
|
||||||
|
*
|
||||||
|
* @return {boolean} Is flag present
|
||||||
|
*/
|
||||||
|
mscript.arg = function arg (shrt, lng) {
|
||||||
|
if (process.argv.indexOf(shrt) !== -1 ||
|
||||||
|
process.argv.indexOf(lng) !== -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for the position of specific arguments in process
|
||||||
|
* argv
|
||||||
|
*
|
||||||
|
* @param {string} shrt Short version of argument or flag
|
||||||
|
* @param {string} lng Long version of argument or flag
|
||||||
|
*
|
||||||
|
* @return {boolean} Position of arg or flag, for locating input
|
||||||
|
*/
|
||||||
|
mscript.arg_pos = function arg_pos (shrt, lng) {
|
||||||
|
var pos = -1;
|
||||||
|
pos = process.argv.indexOf(shrt);
|
||||||
|
if (pos === -1) {
|
||||||
|
pos = process.argv.indexOf(lng);
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
mscript.black = '0,0,0';
|
||||||
|
mscript.cmd = [
|
||||||
|
'CF',
|
||||||
|
'PF',
|
||||||
|
'BF',
|
||||||
|
'CB',
|
||||||
|
'PB',
|
||||||
|
'BB'
|
||||||
|
];
|
||||||
|
mscript.alts = {
|
||||||
|
'CF' : ['CAMERA FORWARD', 'CAM FORWARD'],
|
||||||
|
'PF' : ['PROJECTOR FORWARD', 'PROJ FORWARD'],
|
||||||
|
'BF' : ['BLACK FORWARD', 'BLACK', 'BLANK FORWARD', 'BLANK'],
|
||||||
|
'CB' : ['CAMERA BACKWARD', 'CAM BACKWARD', 'CAMERA BACK', 'CAM BACK'],
|
||||||
|
'PB' : ['PROJECTOR FORWARD', 'PROJ FORWARD', 'PROJECTOR BACK', 'PROJ BACK'],
|
||||||
|
'BB' : ['BLACK BACKWARD', 'BLACK BACK', 'BLANK BACK'],
|
||||||
|
'L ' : ['LIGHT', 'COLOR', 'LAMP'],
|
||||||
|
'F ' : ['FADE']
|
||||||
|
};
|
||||||
|
|
||||||
|
mscript.state = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the state object
|
||||||
|
*/
|
||||||
|
mscript.state_clear = function state_clear () {
|
||||||
|
mscript.state = {
|
||||||
|
cam : 0,
|
||||||
|
proj : 0,
|
||||||
|
color : '',
|
||||||
|
loops : [],
|
||||||
|
rec : -1
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* This is never used and doesn't do anything?
|
||||||
|
*/
|
||||||
|
mscript.alts_unique = function alts_unique () {
|
||||||
|
var ids = Object.keys(mscript.alts),
|
||||||
|
all = [];
|
||||||
|
for (var i = 0; i < ids.length; i++) {
|
||||||
|
if (all.indexOf(ids[i]) === -1) {
|
||||||
|
all.push(ids[i]);
|
||||||
|
} else {
|
||||||
|
mscript.fail("Can't compile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.interpret = function interpret (text, callback) {
|
||||||
|
mscript.state_clear();
|
||||||
|
if (typeof text === 'undefined') {
|
||||||
|
mscript.fail('No input');
|
||||||
|
}
|
||||||
|
var lines = text.split('\n'),
|
||||||
|
two = '',
|
||||||
|
arr = [],
|
||||||
|
light = [],
|
||||||
|
target = 0,
|
||||||
|
dist = 0, //?
|
||||||
|
output = {};
|
||||||
|
for (var i = 0; i < lines.length; i++) {
|
||||||
|
lines[i] = lines[i].replace(/\t+/g, ""); //strip tabs
|
||||||
|
lines[i] = lines[i].trim(); //remove excess whitespace before and after command
|
||||||
|
two = lines[i].substring(0, 2);
|
||||||
|
if (mscript.cmd.indexOf(two) !== -1) {
|
||||||
|
|
||||||
|
if (mscript.state.loops.length > 0) {
|
||||||
|
//hold generated arr in state loop array
|
||||||
|
mscript.state.loops[mscript.state.rec].arr
|
||||||
|
.push.apply(mscript.state.loops[mscript.state.rec].arr,
|
||||||
|
mscript.str_to_arr(lines[i],
|
||||||
|
two));
|
||||||
|
mscript.state.loops[mscript.state.rec].light
|
||||||
|
.push.apply(mscript.state.loops[mscript.state.rec].light,
|
||||||
|
mscript.light_to_arr(lines[i],
|
||||||
|
two));
|
||||||
|
} else {
|
||||||
|
arr.push.apply(arr, mscript.str_to_arr(lines[i], two));
|
||||||
|
light.push.apply(light, mscript.light_to_arr(lines[i], two))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (lines[i].substring(0, 4) === 'LOOP') {
|
||||||
|
mscript.state.rec++;
|
||||||
|
mscript.state.loops[mscript.state.rec] = {
|
||||||
|
arr : [],
|
||||||
|
light : [],
|
||||||
|
cam : 0,
|
||||||
|
proj : 0,
|
||||||
|
cmd : lines[i] + ''
|
||||||
|
};
|
||||||
|
} else if (lines[i].substring(0, 2) === 'L ') {
|
||||||
|
mscript.light_state(lines[i]);
|
||||||
|
} else if (lines[i].substring(0, 3) === 'END') {
|
||||||
|
for (var x = 0; x < mscript.loop_count(mscript.state.loops[mscript.state.rec].cmd); x++) {
|
||||||
|
if (mscript.state.rec === 0) {
|
||||||
|
arr.push.apply(arr, mscript.state.loops[mscript.state.rec].arr);
|
||||||
|
light.push.apply(light, mscript.state.loops[mscript.state.rec].light);
|
||||||
|
} else if (mscript.state.rec >= 1) {
|
||||||
|
mscript.state.loops[mscript.state.rec - 1].arr
|
||||||
|
.push.apply(mscript.state.loops[mscript.state.rec - 1].arr,
|
||||||
|
mscript.state.loops[mscript.state.rec].arr);
|
||||||
|
mscript.state.loops[mscript.state.rec - 1].light
|
||||||
|
.push.apply(mscript.state.loops[mscript.state.rec - 1].light,
|
||||||
|
mscript.state.loops[mscript.state.rec].light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mscript.state_update('END', mscript.loop_count(mscript.state.loops[mscript.state.rec].cmd));
|
||||||
|
delete mscript.state.loops[mscript.state.rec];
|
||||||
|
mscript.state.rec--;
|
||||||
|
} else if (lines[i].substring(0, 3) === 'CAM') { //directly go to that frame (black?)
|
||||||
|
target = parseInt(lines[i].split('CAM ')[1]);
|
||||||
|
if (mscript.state.loops.length > 0) {
|
||||||
|
if (target > mscript.state.cam) {
|
||||||
|
dist = target - mscript.state.cam;
|
||||||
|
for (var x = 0; x < dist; x++) {
|
||||||
|
mscript.state.loops[mscript.state.rec].arr.push('BF');
|
||||||
|
mscript.state.loops[mscript.state.rec].light.push(mscript.black);
|
||||||
|
mscript.state_update('BF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dist = mscript.state.cam - target;
|
||||||
|
for (var x = 0; x < dist; x++) {
|
||||||
|
mscript.state.loops[mscript.state.rec].arr.push('BB');
|
||||||
|
mscript.state.loops[mscript.state.rec].light.push(mscript.black);
|
||||||
|
mscript.state_update('BB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (target > mscript.state.cam) {
|
||||||
|
dist = target - mscript.state.cam;
|
||||||
|
for (var x = 0; x < dist; x++) {
|
||||||
|
arr.push('BF');
|
||||||
|
light.push(mscript.black);
|
||||||
|
mscript.state_update('BF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dist = mscript.state.cam - target;
|
||||||
|
for (var x = 0; x < dist; x++) {
|
||||||
|
arr.push('BB');
|
||||||
|
light.push(mscript.black);
|
||||||
|
mscript.state_update('BB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (lines[i].substring(0, 4) === 'PROJ') { //directly go to that frame
|
||||||
|
target = parseInt(lines[i].split('PROJ ')[1]);
|
||||||
|
if (mscript.state.loops.length > 0) {
|
||||||
|
if (target > mscript.state.proj) {
|
||||||
|
dist = target - mscript.state.proj;
|
||||||
|
for (var x = 0; x < dist; x++) {
|
||||||
|
mscript.state.loops[mscript.state.rec].arr.push('PF');
|
||||||
|
mscript.state.loops[mscript.state.rec].light.push('');
|
||||||
|
mscript.state_update('PF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dist = mscript.state.proj - target;
|
||||||
|
for (var x = 0; x < dist; x++) {
|
||||||
|
mscript.state.loops[mscript.state.rec].arr.push('PB');
|
||||||
|
mscript.state.loops[mscript.state.rec].light.push('');
|
||||||
|
mscript.state_update('PB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (target > mscript.state.proj) {
|
||||||
|
dist = target - mscript.state.proj;
|
||||||
|
for (var x = 0; x < dist; x++) {
|
||||||
|
arr.push('PF');
|
||||||
|
light.push('');
|
||||||
|
mscript.state_update('PF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dist = mscript.state.proj - target;
|
||||||
|
for (var x = 0; x < dist; x++) {
|
||||||
|
arr.push('PB');
|
||||||
|
light.push('');
|
||||||
|
mscript.state_update('PB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (lines[i].substring(0, 3) === 'SET') { //set that state
|
||||||
|
if (lines[i].substring(0, 7) === 'SET CAM') {
|
||||||
|
mscript.state.cam = parseInt(lines[i].split('SET CAM')[1]);
|
||||||
|
} else if (lines[i].substring(0, 8) === 'SET PROJ') {
|
||||||
|
mscript.state.proj = parseInt(lines[i].split('SET PROJ')[1]);
|
||||||
|
}
|
||||||
|
} else if (lines[i].substring(0, 1) === '#' || lines[i].substring(0, 2) === '//') {
|
||||||
|
//comments
|
||||||
|
//ignore while parsing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.success = true;
|
||||||
|
output.arr = arr;
|
||||||
|
output.light = light;
|
||||||
|
output.cam = mscript.state.cam;
|
||||||
|
output.proj = mscript.state.proj;
|
||||||
|
if (typeof callback !== 'undefined') {
|
||||||
|
//should only be invoked by running mscript.tests()
|
||||||
|
callback(output);
|
||||||
|
} else {
|
||||||
|
return mscript.output(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.last_loop = function last_loop () {
|
||||||
|
return mscript.state.loops[mscript.state.loops.length - 1];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.parent_loop = function parent_loop () {
|
||||||
|
return mscript.state.loops[mscript.state.loops.length - 2];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.state_update = function state_update (cmd, val) {
|
||||||
|
if (cmd === 'END') {
|
||||||
|
for (var i = 0; i < val; i++) {
|
||||||
|
if (mscript.state.rec === 0) {
|
||||||
|
mscript.state.cam += mscript.state.loops[mscript.state.rec].cam;
|
||||||
|
mscript.state.proj += mscript.state.loops[mscript.state.rec].proj;
|
||||||
|
} else if (mscript.state.rec >= 1) {
|
||||||
|
mscript.state.loops[mscript.state.rec - 1].cam += mscript.state.loops[mscript.state.rec].cam;
|
||||||
|
mscript.state.loops[mscript.state.rec - 1].proj += mscript.state.loops[mscript.state.rec].proj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (cmd === 'CF') {
|
||||||
|
if (mscript.state.loops.length < 1) {
|
||||||
|
mscript.state.cam++;
|
||||||
|
} else {
|
||||||
|
mscript.state.loops[mscript.state.rec].cam++;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'CB') {
|
||||||
|
if (mscript.state.loops.length < 1) {
|
||||||
|
mscript.state.cam--;
|
||||||
|
} else {
|
||||||
|
mscript.state.loops[mscript.state.rec].cam--;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'PF') {
|
||||||
|
if (mscript.state.loops.length < 1) {
|
||||||
|
mscript.state.proj++;
|
||||||
|
} else {
|
||||||
|
mscript.state.loops[mscript.state.rec].proj++;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'PB') {
|
||||||
|
if (mscript.state.loops.length < 1) {
|
||||||
|
mscript.state.proj--;
|
||||||
|
} else {
|
||||||
|
mscript.state.loops[mscript.state.rec].proj--;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'BF') {
|
||||||
|
if (mscript.state.loops.length < 1) {
|
||||||
|
mscript.state.cam++;
|
||||||
|
} else {
|
||||||
|
mscript.state.loops[mscript.state.rec].cam++;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'BB') {
|
||||||
|
if (mscript.state.loops.length < 1) {
|
||||||
|
mscript.state.cam--;
|
||||||
|
} else {
|
||||||
|
mscript.state.loops[mscript.state.rec].cam++;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'L ') {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.str_to_arr = function str_to_arr (str, cmd) {
|
||||||
|
var cnt = str.split(cmd),
|
||||||
|
c = parseInt(cnt[1]),
|
||||||
|
arr = [];
|
||||||
|
if (cnt[1] === '') {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = parseInt(cnt[1]);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < c; i++) {
|
||||||
|
arr.push(cmd);
|
||||||
|
mscript.state_update(cmd);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.light_state = function light_state (str) {
|
||||||
|
//add parsers for other color spaces
|
||||||
|
var color = str.replace('L ', '').trim();
|
||||||
|
mscript.state.color = color;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.light_to_arr = function light_to_arr (str, cmd) {
|
||||||
|
var cnt = str.split(cmd),
|
||||||
|
c = parseInt(cnt[1]),
|
||||||
|
arr = [];
|
||||||
|
if (cnt[1] === '') {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = parseInt(cnt[1]);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < c; i++) {
|
||||||
|
if (cmd === 'CF'
|
||||||
|
|| cmd === 'CB') {
|
||||||
|
arr.push(mscript.state.color);
|
||||||
|
} else if (cmd === 'BF'
|
||||||
|
|| cmd === 'BB') {
|
||||||
|
arr.push(mscript.black);
|
||||||
|
} else {
|
||||||
|
arr.push('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.loop_count = function loop_count (str) {
|
||||||
|
return parseInt(str.split(' ')[1]);
|
||||||
|
};
|
||||||
|
mscript.fade_count = function fade_count (str) {
|
||||||
|
return parseInt(str.split(' ')[1]);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.fail = function fail (reason) {
|
||||||
|
console.error(JSON.stringify({success: false, error: true, msg : reason}));
|
||||||
|
if (process) process.exit();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.output = function output (data) {
|
||||||
|
var json = true; //default
|
||||||
|
if (mscript.arg('-j', '--json')) {
|
||||||
|
json = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mscript.arg('-t', '--text')) {
|
||||||
|
json = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json) {
|
||||||
|
console.log(JSON.stringify(data));
|
||||||
|
} else {
|
||||||
|
var ids = Object.keys(data);
|
||||||
|
for (var i = 0; i < ids.length; i++) {
|
||||||
|
console.log(ids[i] + ': ' + data[ids[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mscript.init = function init () {
|
||||||
|
if (mscript.arg('-t', '--tests')) {
|
||||||
|
return mscript.tests();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mscript.arg('-v', '--verbose')) {
|
||||||
|
console.time('mscript');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mscript.arg('-c', '--cam')) {
|
||||||
|
mscript.state.cam = parseInt(process.argv[mscript.arg_pos('-c', '--cam') + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mscript.arg('-p', '--proj')) {
|
||||||
|
mscript.state.proj = parseInt(process.argv[mscript.arg_pos('-p', '--proj') + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mscript.arg('-f', '--file')) {
|
||||||
|
input = process.argv[mscript.arg_pos('-f', '--file') + 1];
|
||||||
|
mscript.interpret(fs.readFileSync(input, 'utf8'));
|
||||||
|
} else {
|
||||||
|
mscript.interpret(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mscript.arg('-v', '--verbose')) {
|
||||||
|
console.timeEnd('mscript');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof document === 'undefined'
|
||||||
|
&& typeof module !== 'undefined'
|
||||||
|
&& !module.parent) {
|
||||||
|
//node script
|
||||||
|
fs = require('fs');
|
||||||
|
input = process.argv[2];
|
||||||
|
mscript.init();
|
||||||
|
} else if (typeof module !== 'undefined' && module.parent) {
|
||||||
|
//module
|
||||||
|
fs = require('fs');
|
||||||
|
module.exports = mscript;
|
||||||
|
} else {
|
||||||
|
//web
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
CAM # - go to camera frame #
|
||||||
|
PROJ # - go to projector frame #
|
||||||
|
|
||||||
|
SET CAM # - sets camera count to #
|
||||||
|
SET PROJ # - sets projector count to #
|
||||||
|
|
||||||
|
LOOP # - begin loop, can nest recursively, # times
|
||||||
|
END LOOP - (or END) closes loop
|
||||||
|
|
||||||
|
L #RGB - sets light to rgb value
|
||||||
|
|
||||||
|
FADE
|
||||||
|
|
||||||
|
CF - Camera forwards
|
||||||
|
PF - Projector forwards
|
||||||
|
BF - Black forwards
|
||||||
|
CB - Camera backwards
|
||||||
|
PB - Projector backwards
|
||||||
|
BB - Black backwards
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "mscript",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "<a name=\"module_lib/mscript\"></a>",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"name": "mcopy",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": {
|
||||||
|
"version": "11.10.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.10.4.tgz",
|
||||||
|
"integrity": "sha512-wa09itaLE8L705aXd8F80jnFpxz3Y1/KRHfKsYL2bPc0XF+wEWu8sR9n5bmeu8Ba1N9z2GRNzm/YdHcghLkLKg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"typescript": {
|
||||||
|
"version": "3.3.3333",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz",
|
||||||
|
"integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "mcopy",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Small gauge film optical printer platform",
|
||||||
|
"main": "build.js",
|
||||||
|
"directories": {
|
||||||
|
"doc": "docs",
|
||||||
|
"lib": "lib"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"build": "sh ./scripts/build.sh"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/sixteenmillimeter/mcopy.git"
|
||||||
|
},
|
||||||
|
"author": "mmcwilliams",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/sixteenmillimeter/mcopy/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/sixteenmillimeter/mcopy#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^11.10.4",
|
||||||
|
"typescript": "^3.3.3333"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
./node_modules/.bin/tsc -p tsconfig.json
|
||||||
|
|
||||||
|
#electron-build fails when local modules are in parent directory
|
||||||
|
#copy them into lib directory
|
||||||
|
cp -r ./lib/ ./app/lib
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
libs="./lib/*"
|
||||||
|
for l in $libs
|
||||||
|
do
|
||||||
|
echo "Generating documentation for $l"
|
||||||
|
./node_modules/.bin/jsdoc2md $l/index.js > $l/Readme.md
|
||||||
|
done
|
|
@ -0,0 +1,375 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const SerialPort = require('serialport')
|
||||||
|
const Readline = SerialPort.parsers.Readline
|
||||||
|
const exec = require('child_process').exec
|
||||||
|
|
||||||
|
const parser = new Readline('')
|
||||||
|
const newlineRe : RegExp = new RegExp('\n', 'g')
|
||||||
|
const returnRe : RegExp = new RegExp('\r', 'g')
|
||||||
|
|
||||||
|
let eventEmitter : any
|
||||||
|
let cfg : object
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause the process for X milliseconds in async/await functions
|
||||||
|
*
|
||||||
|
* @param {integer} ms milliseconds
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after wait
|
||||||
|
**/
|
||||||
|
async function delay (ms : number) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
return setTimeout(resolve, ms)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a command to an Arduino using async/await
|
||||||
|
*
|
||||||
|
* @param {string} device Arduino identifier
|
||||||
|
* @param {string} cmd Single character command to send
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after sending
|
||||||
|
**/
|
||||||
|
async function send (device : string, cmd : string) {
|
||||||
|
return new Promise ((resolve, reject) => {
|
||||||
|
arduino.queue[cmd] = (ms : number) => {
|
||||||
|
return resolve(ms)
|
||||||
|
}
|
||||||
|
return arduino.serial[device].write(cmd, (err : any, results : any) => {
|
||||||
|
if (err) {
|
||||||
|
//console.error(err)
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
//
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a string to an Arduino using async/await
|
||||||
|
*
|
||||||
|
* @param {string} device Arduino identifier
|
||||||
|
* @param {string} str String to send
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after sending
|
||||||
|
**/
|
||||||
|
async function write (device : string, str : string) {
|
||||||
|
return new Promise ((resolve, reject) => {
|
||||||
|
arduino.serial[device].write(str, function (err, results) {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
//console.log('sent: ' + str)
|
||||||
|
return resolve(results)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to an Arduino using async/await
|
||||||
|
*
|
||||||
|
* @param {string} device Arduino identifier
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after opening
|
||||||
|
**/
|
||||||
|
async function openArduino (device : string) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
return arduino.serial[device].open(error => {
|
||||||
|
if (error) {
|
||||||
|
return reject(error)
|
||||||
|
}
|
||||||
|
return resolve(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a connection to an Arduino using async/await
|
||||||
|
*
|
||||||
|
* @param {string} device Arduino identifier
|
||||||
|
*
|
||||||
|
* @returns {Promise} Resolves after closing
|
||||||
|
**/
|
||||||
|
async function closeArduino (device : string) {
|
||||||
|
return new Promise((resolve : any, reject : any) => {
|
||||||
|
return arduino.serial[device].close((err) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
return resolve(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/******
|
||||||
|
Arduino handlers
|
||||||
|
*******/
|
||||||
|
const arduino = {
|
||||||
|
path : {},
|
||||||
|
known: [
|
||||||
|
'/dev/tty.usbmodem1a161',
|
||||||
|
'/dev/tty.usbserial-A800f8dk',
|
||||||
|
'/dev/tty.usbserial-A900cebm',
|
||||||
|
'/dev/tty.usbmodem1a131',
|
||||||
|
'/dev/tty.usbserial-a900f6de',
|
||||||
|
'/dev/tty.usbmodem1a141',
|
||||||
|
'/dev/ttyACM0',
|
||||||
|
'COM3'
|
||||||
|
],
|
||||||
|
alias : {
|
||||||
|
|
||||||
|
},
|
||||||
|
serial : {
|
||||||
|
connect : {},
|
||||||
|
projector : {},
|
||||||
|
camera : {},
|
||||||
|
light : {}
|
||||||
|
},
|
||||||
|
baud : 57600,
|
||||||
|
queue : {},
|
||||||
|
timer : 0,
|
||||||
|
lock : false,
|
||||||
|
locks : {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arduino.enumerate = async function () {
|
||||||
|
return new Promise( (resolve, reject) => {
|
||||||
|
return SerialPort.list((err, ports) => {
|
||||||
|
let matches = []
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
ports.forEach(port => {
|
||||||
|
if (arduino.known.indexOf(port.comName) !== -1) {
|
||||||
|
matches.push(port.comName)
|
||||||
|
} else if ((port.manufacturer + '').toLowerCase().indexOf('arduino') !== -1) {
|
||||||
|
matches.push(port.comName)
|
||||||
|
} else if ((port.comName + '').toLowerCase().indexOf('usbserial') !== -1) {
|
||||||
|
matches.push(port.comName)
|
||||||
|
} else if ((port.comName + '').toLowerCase().indexOf('usbmodem') !== -1) {
|
||||||
|
matches.push(port.comName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (matches.length === 0) {
|
||||||
|
return reject('No USB devices found');
|
||||||
|
} else if (matches.length > 0) {
|
||||||
|
return resolve(matches)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//commands which respond to a sent char
|
||||||
|
arduino.send = async function (serial, cmd, res) {
|
||||||
|
const device = arduino.alias[serial]
|
||||||
|
let results
|
||||||
|
if (arduino.locks[serial]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
arduino.locks[serial] = true
|
||||||
|
await delay(cfg.arduino.serialDelay)
|
||||||
|
try {
|
||||||
|
results = await send(device, cmd)
|
||||||
|
} catch (e) {
|
||||||
|
return console.error(e)
|
||||||
|
}
|
||||||
|
arduino.locks[serial] = false
|
||||||
|
arduino.timer = new Date().getTime()
|
||||||
|
return await eventEmitter.emit('arduino_send', cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
//send strings, after char triggers firmware to accept
|
||||||
|
arduino.string = async function (serial, str) {
|
||||||
|
const device = arduino.alias[serial]
|
||||||
|
let writeSuccess
|
||||||
|
await delay(cfg.arduino.serialDelay)
|
||||||
|
if (typeof arduino.serial[device].fake !== 'undefined'
|
||||||
|
&& arduino.serial[device].fake) {
|
||||||
|
return arduino.serial[device].string(str)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
writeSuccess = await write(device, str)
|
||||||
|
} catch (e) {
|
||||||
|
return console.error(e)
|
||||||
|
}
|
||||||
|
return writeSuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//respond with same char over serial when done
|
||||||
|
arduino.end = async function (serial, data) {
|
||||||
|
const end = new Date().getTime()
|
||||||
|
const ms = end - arduino.timer
|
||||||
|
let complete
|
||||||
|
if (arduino.queue[data] !== undefined) {
|
||||||
|
arduino.locks[serial] = false;
|
||||||
|
//console.log('Command ' + data + ' took ' + ms + 'ms');
|
||||||
|
complete = arduino.queue[data](ms) //execute callback
|
||||||
|
eventEmitter.emit('arduino_end', data)
|
||||||
|
delete arduino.queue[data]
|
||||||
|
} else {
|
||||||
|
//console.log('Received stray "' + data + '"'); //silent to user
|
||||||
|
}
|
||||||
|
return complete
|
||||||
|
};
|
||||||
|
arduino.alias = function (serial, device) {
|
||||||
|
console.log(`Making "${serial}" an alias of ${device}`)
|
||||||
|
arduino.alias[serial] = device
|
||||||
|
}
|
||||||
|
arduino.connect = async function (serial, device, confirm) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let connectSuccess
|
||||||
|
arduino.path[serial] = device;
|
||||||
|
arduino.alias[serial] = device;
|
||||||
|
arduino.serial[device] = new SerialPort(arduino.path[serial], {
|
||||||
|
autoOpen : false,
|
||||||
|
baudRate: cfg.arduino.baud,
|
||||||
|
parser: parser
|
||||||
|
})
|
||||||
|
arduino.locks[device] = false
|
||||||
|
try {
|
||||||
|
connectSuccess = await openArduino(device)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('failed to open: ' + e)
|
||||||
|
return reject(e)
|
||||||
|
}
|
||||||
|
console.log(`Opened connection with ${arduino.path[serial]} as ${serial}`);
|
||||||
|
if (!confirm) {
|
||||||
|
arduino.serial[device].on('data', async (data) => {
|
||||||
|
let d = data.toString('utf8')
|
||||||
|
d = d.replace(newlineRe, '').replace(returnRe, '')
|
||||||
|
return await arduino.end(serial, d)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
arduino.serial[device].on('data', async (data) => {
|
||||||
|
let d = data.toString('utf8')
|
||||||
|
d = d.replace(newlineRe, '').replace(returnRe, '')
|
||||||
|
return await arduino.confirmEnd(d)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return resolve(arduino.path[serial])
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
arduino.confirmExec = {};
|
||||||
|
arduino.confirmEnd = function (data) {
|
||||||
|
//console.dir(data)
|
||||||
|
if (data === cfg.arduino.cmd.connect
|
||||||
|
|| data === cfg.arduino.cmd.proj_identifier
|
||||||
|
|| data === cfg.arduino.cmd.cam_identifier
|
||||||
|
|| data === cfg.arduino.cmd.light_identifier
|
||||||
|
|| data === cfg.arduino.cmd.proj_light_identifier
|
||||||
|
|| data === cfg.arduino.cmd.proj_cam_light_identifier
|
||||||
|
|| data === cfg.arduino.cmd.proj_cam_identifier ) {
|
||||||
|
arduino.confirmExec(null, data);
|
||||||
|
arduino.confirmExec = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arduino.verify = async function () {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const device = arduino.alias['connect']
|
||||||
|
let writeSuccess
|
||||||
|
arduino.confirmExec = function (err, data) {
|
||||||
|
if (data === cfg.arduino.cmd.connect) {
|
||||||
|
return resolve(true)
|
||||||
|
} else {
|
||||||
|
return reject('Wrong data returned')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await delay(cfg.arduino.serialDelay)
|
||||||
|
try {
|
||||||
|
writeSuccess = await send(device, cfg.arduino.cmd.connect)
|
||||||
|
} catch (e) {
|
||||||
|
return reject(e)
|
||||||
|
}
|
||||||
|
return resolve(writeSuccess)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
arduino.distinguish = async function () {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const device = arduino.alias['connect']
|
||||||
|
let writeSuccess
|
||||||
|
let type
|
||||||
|
arduino.confirmExec = function (err, data) {
|
||||||
|
if (data === cfg.arduino.cmd.proj_identifier) {
|
||||||
|
type = 'projector'
|
||||||
|
} else if (data === cfg.arduino.cmd.cam_identifier) {
|
||||||
|
type = 'camera'
|
||||||
|
} else if (data === cfg.arduino.cmd.light_identifier) {
|
||||||
|
type = 'light'
|
||||||
|
} else if (data === cfg.arduino.cmd.proj_light_identifier) {
|
||||||
|
type = 'projector,light'
|
||||||
|
} else if (data === cfg.arduino.cmd.proj_cam_light_identifier) {
|
||||||
|
type = 'projector,camera,light'
|
||||||
|
} else if (data === cfg.arduino.cmd.proj_cam_identifier) {
|
||||||
|
type = 'projector,camera'
|
||||||
|
} else if (data === cfg.ardino.cmd.proj_second_identifier) {
|
||||||
|
type = 'projector_second'
|
||||||
|
}
|
||||||
|
return resolve(type)
|
||||||
|
}
|
||||||
|
await delay(cfg.arduino.serialDelay)
|
||||||
|
try {
|
||||||
|
writeSuccess = await send(device, cfg.arduino.cmd.mcopy_identifier)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
return reject(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
arduino.close = async function (callback) {
|
||||||
|
const device = arduino.alias['connect']
|
||||||
|
let closeSuccess
|
||||||
|
try {
|
||||||
|
closeSuccess = await closeArduino(device)
|
||||||
|
} catch (e) {
|
||||||
|
return console.error(e)
|
||||||
|
}
|
||||||
|
return closeSuccess
|
||||||
|
};
|
||||||
|
|
||||||
|
arduino.fakeConnect = async function (serial) {
|
||||||
|
//console.log('Connecting to fake arduino...');
|
||||||
|
const device = '/dev/fake'
|
||||||
|
arduino.alias[serial] = device
|
||||||
|
arduino.serial[device] = {
|
||||||
|
write : function (cmd, cb) {
|
||||||
|
const t = {
|
||||||
|
c : cfg.arduino.cam.time + cfg.arduino.cam.delay,
|
||||||
|
p : cfg.arduino.proj.time + cfg.arduino.proj.delay
|
||||||
|
}
|
||||||
|
let timeout = t[cmd]
|
||||||
|
let end
|
||||||
|
if (typeof timeout === 'undefined') timeout = 10
|
||||||
|
arduino.timer = +new Date()
|
||||||
|
setTimeout(() => {
|
||||||
|
arduino.end(serial, cmd)
|
||||||
|
return cb()
|
||||||
|
}, timeout)
|
||||||
|
|
||||||
|
},
|
||||||
|
string : async function (str) {
|
||||||
|
//do nothing
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
fake : true
|
||||||
|
};
|
||||||
|
//console.log('Connected to fake arduino! Not real! Doesn\'t exist!');
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof module !== 'undefined' && module.parent) {
|
||||||
|
module.exports = function (c, ee) {
|
||||||
|
eventEmitter = ee
|
||||||
|
cfg = c
|
||||||
|
return arduino
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,545 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/** @module lib/mscript */
|
||||||
|
|
||||||
|
const BLACK = '0,0,0';
|
||||||
|
const WHITE = '255,255,255';
|
||||||
|
const CMD = [
|
||||||
|
'CF',
|
||||||
|
'PF',
|
||||||
|
'BF',
|
||||||
|
'CB',
|
||||||
|
'PB',
|
||||||
|
'BB'
|
||||||
|
];
|
||||||
|
const ALTS = {
|
||||||
|
'CF' : ['CAMERA FORWARD', 'CAM FORWARD'],
|
||||||
|
'PF' : ['PROJECTOR FORWARD', 'PROJ FORWARD'],
|
||||||
|
'BF' : ['BLACK FORWARD', 'BLACK', 'BLANK FORWARD', 'BLANK'],
|
||||||
|
'CB' : ['CAMERA BACKWARD', 'CAM BACKWARD', 'CAMERA BACK', 'CAM BACK'],
|
||||||
|
'PB' : ['PROJECTOR FORWARD', 'PROJ FORWARD', 'PROJECTOR BACK', 'PROJ BACK'],
|
||||||
|
'BB' : ['BLACK BACKWARD', 'BLACK BACK', 'BLANK BACK'],
|
||||||
|
'L ' : ['LIGHT', 'COLOR', 'LAMP'],
|
||||||
|
'F ' : ['FADE']
|
||||||
|
};
|
||||||
|
|
||||||
|
/** helper functions */
|
||||||
|
|
||||||
|
/** startswith function from lodash, do not want the entire lib for this */
|
||||||
|
function startsWith(string, target, position) {
|
||||||
|
const { length } = string;
|
||||||
|
position = position == null ? 0 : position;
|
||||||
|
if (position < 0) {
|
||||||
|
position = 0;
|
||||||
|
} else if (position > length) {
|
||||||
|
position = length;
|
||||||
|
}
|
||||||
|
target = `${target}`;
|
||||||
|
return string.slice(position, position + target.length) == target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** class Mscript */
|
||||||
|
class Mscript {
|
||||||
|
constructor () {
|
||||||
|
this.output = {};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Clear the state of the script
|
||||||
|
*/
|
||||||
|
clear () {
|
||||||
|
this.lines = [];
|
||||||
|
|
||||||
|
this.cam = 0;
|
||||||
|
this.proj = 0;
|
||||||
|
this.color = '';
|
||||||
|
this.loops = [];
|
||||||
|
this.rec = -1;
|
||||||
|
|
||||||
|
this.two = '';
|
||||||
|
this.arr = [];
|
||||||
|
this.light = [];
|
||||||
|
this.target = 0; //move to target using CAM # or PROJ #
|
||||||
|
this.dist = 0;
|
||||||
|
|
||||||
|
this.variables = {};
|
||||||
|
|
||||||
|
this.output = {};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Main function, accepts multi-line string, parses into lines
|
||||||
|
* and interprets the instructions from the text. Returns an array
|
||||||
|
* of steps to be fed into the mcopy.
|
||||||
|
*/
|
||||||
|
interpret (text, callback) {
|
||||||
|
this.clear()
|
||||||
|
|
||||||
|
if (typeof text === 'undefined') {
|
||||||
|
return this.fail('No input');
|
||||||
|
}
|
||||||
|
|
||||||
|
//split string into lines, each containing a command
|
||||||
|
this.lines = text.split('\n');
|
||||||
|
|
||||||
|
this.lines = this.lines.map(line => {
|
||||||
|
line = line.replace(/\t+/g, ''); //strip tabs
|
||||||
|
line = line.trim(); //remove excess whitespace before and after command
|
||||||
|
line = line.toUpperCase();
|
||||||
|
return line;
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let line of this.lines) {
|
||||||
|
this.two = line.substring(0, 2);
|
||||||
|
if (CMD.indexOf(this.two) !== -1) {
|
||||||
|
this.basic_cmd(line);
|
||||||
|
} else if (startsWith(line, '@') || line.indexOf('@') !== -1) {
|
||||||
|
this.variable(line);
|
||||||
|
} else if (startsWith(line, 'LOOP')) {
|
||||||
|
this.new_loop(line);
|
||||||
|
} else if (startsWith(line, 'L ')) {
|
||||||
|
this.light_state(line);
|
||||||
|
} else if (startsWith(line, 'F ')) {
|
||||||
|
this.new_loop(line, true);
|
||||||
|
} else if (startsWith(line, 'END')) {
|
||||||
|
this.end_loop(line);
|
||||||
|
} else if (startsWith(line, 'CAM')) { //directly go to that frame (black?)
|
||||||
|
this.move_cam(line);
|
||||||
|
} else if (startsWith(line, 'PROJ')) { //directly go to that frame
|
||||||
|
this.move_proj(line);
|
||||||
|
} else if (startsWith(line, 'SET')) { //set that state
|
||||||
|
this.set_state(line);
|
||||||
|
} else if (startsWith(line, '#') || startsWith(line, '//')) {
|
||||||
|
//comments
|
||||||
|
//ignore while parsing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.output.success = true;
|
||||||
|
this.output.arr = this.arr; //all instructions
|
||||||
|
this.output.light = this.light; //all light instructions
|
||||||
|
this.output.cam = this.cam;
|
||||||
|
this.output.proj = this.proj;
|
||||||
|
|
||||||
|
if (typeof callback !== 'undefined') {
|
||||||
|
//should only be invoked by running mscript.tests()
|
||||||
|
callback(this.output);
|
||||||
|
} else {
|
||||||
|
return this.output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variable (line) {
|
||||||
|
let parts = line.split('=');
|
||||||
|
let key = parts[0];
|
||||||
|
let value = parts[1];
|
||||||
|
let update = false;
|
||||||
|
|
||||||
|
if (value && value.indexOf('#') !== -1) {
|
||||||
|
value = value.split('#')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && value.indexOf('//') !== -1) {
|
||||||
|
value = value.split('//')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && value.indexOf('+') !== -1) {
|
||||||
|
if (value)
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.indexOf('-') !== -1) {
|
||||||
|
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.indexOf(',') === -1) { //if not color string
|
||||||
|
try {
|
||||||
|
value = parseInt(value);
|
||||||
|
} catch (err) {
|
||||||
|
//supress parsing error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.dir(parts)
|
||||||
|
if (!this.variables[key] || update) {
|
||||||
|
this.variables[key] = value;
|
||||||
|
}
|
||||||
|
console.dir(this.variables)
|
||||||
|
}
|
||||||
|
variable_replace(line) {
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Apply a basic two character command
|
||||||
|
*/
|
||||||
|
basic_cmd (line) {
|
||||||
|
if (this.rec !== -1) {
|
||||||
|
//hold generated arr in state loop array
|
||||||
|
this.loops[this.rec].arr
|
||||||
|
.push.apply(this.loops[this.rec].arr,
|
||||||
|
this.str_to_arr(line,
|
||||||
|
this.two));
|
||||||
|
this.loops[this.rec].light
|
||||||
|
.push.apply(this.loops[this.rec].light,
|
||||||
|
this.light_to_arr(line,
|
||||||
|
this.two));
|
||||||
|
} else {
|
||||||
|
this.arr.push.apply(this.arr, this.str_to_arr(line, this.two));
|
||||||
|
this.light.push.apply(this.light, this.light_to_arr(line, this.two))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Start a new loop
|
||||||
|
*/
|
||||||
|
new_loop (line, fade) {
|
||||||
|
this.rec++;
|
||||||
|
this.loops[this.rec] = {
|
||||||
|
arr : [],
|
||||||
|
light : [],
|
||||||
|
cam : 0,
|
||||||
|
proj : 0,
|
||||||
|
cmd : line + ''
|
||||||
|
};
|
||||||
|
if (fade) {
|
||||||
|
this.fade(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Close the most recent loop
|
||||||
|
*/
|
||||||
|
end_loop (line) {
|
||||||
|
let light_arr;
|
||||||
|
let start;
|
||||||
|
let end;
|
||||||
|
let len;
|
||||||
|
|
||||||
|
for (let x = 0; x < this.loop_count(this.loops[this.rec].cmd); x++) {
|
||||||
|
light_arr = this.loops[this.rec].light;
|
||||||
|
if (this.loops[this.rec].fade) {
|
||||||
|
start = this.loops[this.rec].start;
|
||||||
|
end = this.loops[this.rec].end;
|
||||||
|
len = this.loops[this.rec].fade_len;
|
||||||
|
light_arr = light_arr.map(l => {
|
||||||
|
return this.fade_rgb(start, end, len, x);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.rec === 0) {
|
||||||
|
this.arr.push.apply(this.arr, this.loops[this.rec].arr);
|
||||||
|
this.light.push.apply(this.light, light_arr);
|
||||||
|
} else if (this.rec >= 1) {
|
||||||
|
this.loops[this.rec - 1].arr
|
||||||
|
.push.apply(this.loops[this.rec - 1].arr,
|
||||||
|
this.loops[this.rec].arr);
|
||||||
|
|
||||||
|
this.loops[this.rec - 1].light
|
||||||
|
.push.apply(this.loops[this.rec - 1].light,
|
||||||
|
light_arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.update('END', this.loop_count(this.loops[this.rec].cmd));
|
||||||
|
delete this.loops[this.rec];
|
||||||
|
this.rec--;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Move camera to explicitly-defined frame
|
||||||
|
*/
|
||||||
|
move_cam (line) {
|
||||||
|
this.target = parseInt(line.split('CAM ')[1]);
|
||||||
|
if (this.rec !== -1) {
|
||||||
|
if (this.target > this.cam) {
|
||||||
|
this.dist = this.target - this.cam;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.loops[this.rec].arr.push('BF');
|
||||||
|
this.loops[this.rec].light.push(BLACK);
|
||||||
|
this.update('BF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dist = this.cam - this.target;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.loops[this.rec].arr.push('BB');
|
||||||
|
this.loops[this.rec].light.push(BLACK);
|
||||||
|
this.update('BB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (target > this.cam) {
|
||||||
|
this.dist = this.target - this.cam;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.arr.push('BF');
|
||||||
|
this.light.push(BLACK);
|
||||||
|
this.update('BF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dist = this.cam - this.target;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.arr.push('BB');
|
||||||
|
this.light.push(BLACK);
|
||||||
|
this.update('BB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Move projector to explicitly-defined frame
|
||||||
|
*/
|
||||||
|
move_proj (line) {
|
||||||
|
this.target = parseInt(line.split('PROJ ')[1]);
|
||||||
|
if (this.rec !== -1) {
|
||||||
|
if (this.target > this.proj) {
|
||||||
|
this.dist = this.target - this.proj;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.loops[this.rec].arr.push('PF');
|
||||||
|
this.loops[this.rec].light.push('');
|
||||||
|
this.update('PF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dist = this.proj - this.target;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.loops[this.rec].arr.push('PB');
|
||||||
|
this.loops[this.rec].light.push('');
|
||||||
|
this.update('PB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.target > this.proj) {
|
||||||
|
this.dist = this.target - this.proj;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.arr.push('PF');
|
||||||
|
this.light.push('');
|
||||||
|
this.update('PF');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dist = this.proj - this.target;
|
||||||
|
for (let x = 0; x < this.dist; x++) {
|
||||||
|
this.arr.push('PB');
|
||||||
|
this.light.push('');
|
||||||
|
this.update('PB');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the state of either the cam or projector
|
||||||
|
*/
|
||||||
|
set_state (line) {
|
||||||
|
if (startsWith(line, 'SET CAM')) {
|
||||||
|
this.cam = parseInt(line.split('SET CAM')[1]);
|
||||||
|
} else if (startsWith(line, 'SET PROJ')) {
|
||||||
|
this.proj = parseInt(line.split('SET PROJ')[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return the last loop
|
||||||
|
*/
|
||||||
|
last_loop () {
|
||||||
|
return this.loops[this.loops.length - 1];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return the second-last loop
|
||||||
|
*/
|
||||||
|
parent_loop () {
|
||||||
|
return this.loops[this.loops.length - 2];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract the loop count integer from a LOOP cmd
|
||||||
|
*/
|
||||||
|
loop_count (str) {
|
||||||
|
return parseInt(str.split(' ')[1]);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Execute a fade of frame length, from color to another color
|
||||||
|
*/
|
||||||
|
fade (line) {
|
||||||
|
let len = this.fade_count(line);
|
||||||
|
let start = this.fade_start(line);
|
||||||
|
let end = this.fade_end(line);
|
||||||
|
|
||||||
|
this.loops[this.rec].start = start;
|
||||||
|
this.loops[this.rec].end = end;
|
||||||
|
this.loops[this.rec].fade = true;
|
||||||
|
this.loops[this.rec].fade_count = 0;
|
||||||
|
this.loops[this.rec].fade_len = len;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract the fade length integer from a FADE cmd
|
||||||
|
*/
|
||||||
|
fade_count (str) {
|
||||||
|
return parseInt(str.split(' ')[1]);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract the start color from a string
|
||||||
|
*/
|
||||||
|
fade_start (str) {
|
||||||
|
let color = str.split(' ')[2];
|
||||||
|
return this.rgb(color.trim())
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract the end color from a string
|
||||||
|
*/
|
||||||
|
fade_end (str) {
|
||||||
|
let color = str.split(' ')[3];
|
||||||
|
return this.rgb(color.trim())
|
||||||
|
}
|
||||||
|
fade_rgb (start, end, len, x) {
|
||||||
|
let cur = [];
|
||||||
|
let diff;
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
if (x === len - 1) {
|
||||||
|
cur[i] = end[i];
|
||||||
|
} else if (start[i] >= end[i]) {
|
||||||
|
diff = start[i] - end[i];
|
||||||
|
cur[i] = start[i] - Math.round((diff / (len - 1)) * x);
|
||||||
|
} else {
|
||||||
|
diff = end[i] - start[i];
|
||||||
|
cur[i] = start[i] + Math.round((diff / (len - 1)) * x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.rgb_str(cur);
|
||||||
|
|
||||||
|
}
|
||||||
|
rgb (str) {
|
||||||
|
let rgb = str.split(',');
|
||||||
|
return rgb.map( char => {
|
||||||
|
return parseInt(char);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
rgb_str (arr) {
|
||||||
|
return arr.join(',');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Increase the state of a specific object, such as the camera/projector,
|
||||||
|
* by the value defined in val
|
||||||
|
*/
|
||||||
|
update (cmd, val = 1) {
|
||||||
|
if (cmd === 'END') {
|
||||||
|
//I don't understand this loop
|
||||||
|
for (let i = 0; i < val; i++) {
|
||||||
|
if (this.rec === 0) {
|
||||||
|
this.cam += this.loops[this.rec].cam;
|
||||||
|
this.proj += this.loops[this.rec].proj;
|
||||||
|
} else if (this.rec >= 1) {
|
||||||
|
this.loops[this.rec - 1].cam += this.loops[this.rec].cam;
|
||||||
|
this.loops[this.rec - 1].proj += this.loops[this.rec].proj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (cmd === 'CF') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.cam += val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].cam += val;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'CB') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.cam -= val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].cam--;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'PF') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.proj += val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].proj += val;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'PB') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.proj -= val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].proj--;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'BF') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.cam += val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].cam += val;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'BB') {
|
||||||
|
if (this.rec === -1) {
|
||||||
|
this.cam -= val;
|
||||||
|
} else {
|
||||||
|
this.loops[this.rec].cam -= val;
|
||||||
|
}
|
||||||
|
} else if (cmd === 'L ') {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Split string on command, extract any integers from string
|
||||||
|
*/
|
||||||
|
str_to_arr (str, cmd) {
|
||||||
|
const cnt = str.split(cmd);
|
||||||
|
let c = parseInt(cnt[1]);
|
||||||
|
let arr = [];
|
||||||
|
if (cnt[1] === '') {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = parseInt(cnt[1]);
|
||||||
|
}
|
||||||
|
arr = new Array(c).fill(cmd);
|
||||||
|
this.update(cmd, c);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Split a string on a command to extract data for light array
|
||||||
|
*/
|
||||||
|
light_to_arr (str, cmd) {
|
||||||
|
const cnt = str.split(cmd);
|
||||||
|
let c = parseInt(cnt[1]);
|
||||||
|
let arr = [];
|
||||||
|
if (cnt[1] === '') {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = parseInt(cnt[1]);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < c; i++) {
|
||||||
|
if (cmd === 'CF'
|
||||||
|
|| cmd === 'CB') {
|
||||||
|
arr.push(this.color);
|
||||||
|
} else if (cmd === 'BF'
|
||||||
|
|| cmd === 'BB') {
|
||||||
|
arr.push(BLACK);
|
||||||
|
} else {
|
||||||
|
arr.push('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Split a string to extract an rgb color value
|
||||||
|
*/
|
||||||
|
light_state (str) {
|
||||||
|
//add parsers for other color spaces
|
||||||
|
const color = str.replace('L ', '').trim();
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw an error with specific message
|
||||||
|
*/
|
||||||
|
fail (msg) {
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Mscript;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
CAM # - go to camera frame #
|
||||||
|
PROJ # - go to projector frame #
|
||||||
|
|
||||||
|
SET CAM # - sets camera count to #
|
||||||
|
SET PROJ # - sets projector count to #
|
||||||
|
|
||||||
|
LOOP # - begin loop, can nest recursively, # times
|
||||||
|
END LOOP - (or END) closes loop
|
||||||
|
|
||||||
|
L #RGB - sets light to rgb value
|
||||||
|
|
||||||
|
FADE 24 0,0,0 255,255,255
|
||||||
|
|
||||||
|
CF - Camera forwards
|
||||||
|
PF - Projector forwards
|
||||||
|
BF - Black forwards
|
||||||
|
CB - Camera backwards
|
||||||
|
PB - Projector backwards
|
||||||
|
BB - Black backwards
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"target": "ES2017",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"sourceMap": true,
|
||||||
|
"removeComments" : false,
|
||||||
|
"outDir": "./lib/",
|
||||||
|
"rootDir" : "./src/"
|
||||||
|
},
|
||||||
|
"exclude" : []
|
||||||
|
}
|
Loading…
Reference in New Issue