re-write progress, changing platforms
This commit is contained in:
parent
af5e493980
commit
26655ea0a7
|
@ -173,7 +173,7 @@ class BLE {
|
||||||
bleno.on('stateChange', state => {
|
bleno.on('stateChange', state => {
|
||||||
log.info('stateChange', { state : state })
|
log.info('stateChange', { state : state })
|
||||||
if (state === 'poweredOn') {
|
if (state === 'poweredOn') {
|
||||||
log.info('Starting advertising', { DEVICE_NAME: DEVICE_NAME, DEVICE_ID : process.env.BLENO_DEVICE_NAME })
|
log.info('Starting advertising', { DEVICE_NAME, DEVICE_ID : process.env.BLENO_DEVICE_NAME })
|
||||||
bleno.startAdvertising(DEVICE_NAME, [CHAR_ID])
|
bleno.startAdvertising(DEVICE_NAME, [CHAR_ID])
|
||||||
} else {
|
} else {
|
||||||
bleno.stopAdvertising()
|
bleno.stopAdvertising()
|
||||||
|
|
|
@ -1,423 +1,461 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
const db = require('../db')
|
if (mod && mod.__esModule) return mod;
|
||||||
const log = require('../log')('intval')
|
var result = {};
|
||||||
const storage = require('node-persist')
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
const fs = require('fs')
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
let Gpio
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const db = require('../db');
|
||||||
|
const log = require('../log')('intval');
|
||||||
|
const storage = __importStar(require("node-persist"));
|
||||||
|
const fs_extra_1 = require("fs-extra");
|
||||||
|
require("../delay");
|
||||||
|
let Gpio;
|
||||||
try {
|
try {
|
||||||
Gpio = require('onoff').Gpio
|
Gpio = require('onoff').Gpio;
|
||||||
} catch (e) {
|
}
|
||||||
log.warn('Failed including Gpio, using sim')
|
catch (e) {
|
||||||
Gpio = require('../../lib/onoffsim').Gpio
|
log.warn('Failed including Gpio, using sim');
|
||||||
|
Gpio = require('../../lib/onoffsim').Gpio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const PINS = {
|
const PINS = {
|
||||||
fwd : {
|
fwd: {
|
||||||
pin : 13,
|
pin: 13,
|
||||||
dir : 'out'
|
dir: 'out'
|
||||||
},
|
},
|
||||||
bwd : {
|
bwd: {
|
||||||
pin : 19,
|
pin: 19,
|
||||||
dir : 'out'
|
dir: 'out'
|
||||||
},
|
},
|
||||||
micro : {
|
micro: {
|
||||||
pin : 5,
|
pin: 5,
|
||||||
dir : 'in',
|
dir: 'in',
|
||||||
edge : 'both'
|
edge: 'both'
|
||||||
},
|
},
|
||||||
release : {
|
release: {
|
||||||
pin : 6,
|
pin: 6,
|
||||||
dir : 'in',
|
dir: 'in',
|
||||||
edge : 'both'
|
edge: 'both'
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
/** class representing the intval3 features */
|
||||||
|
class Intval {
|
||||||
|
constructor() {
|
||||||
|
this.STATE_DIR = '~/state';
|
||||||
|
this._frame = {
|
||||||
|
open: 250,
|
||||||
|
openBwd: 400,
|
||||||
|
closed: 100,
|
||||||
|
expected: 530 //expected length of frame, in ms
|
||||||
|
};
|
||||||
|
this._release = {
|
||||||
|
min: 20,
|
||||||
|
seq: 1000
|
||||||
|
};
|
||||||
|
this._microDelay = 10; // delay after stop signal before stopping motors
|
||||||
|
this._pin = {};
|
||||||
|
this._state = {};
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Initialize the storage object and bind functions to process events.
|
||||||
|
*/
|
||||||
|
async _init() {
|
||||||
|
let dirExists;
|
||||||
|
try {
|
||||||
|
dirExists = await fs_extra_1.exists(this.STATE_DIR);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
log.error('init', `Error locating state directory ${this.STATE_DIR}`);
|
||||||
|
}
|
||||||
|
if (!dirExists) {
|
||||||
|
try {
|
||||||
|
await fs_extra_1.mkdir(this.STATE_DIR);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
log.error('init', `Error creating state directory ${this.STATE_DIR}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storage.init({
|
||||||
|
dir: this.STATE_DIR,
|
||||||
|
stringify: JSON.stringify,
|
||||||
|
parse: JSON.parse,
|
||||||
|
encoding: 'utf8',
|
||||||
|
logging: false,
|
||||||
|
continuous: true,
|
||||||
|
interval: false,
|
||||||
|
ttl: false,
|
||||||
|
}).then(this._restoreState).catch((err) => {
|
||||||
|
log.warn('init', err);
|
||||||
|
this.reset();
|
||||||
|
this._declarePins();
|
||||||
|
});
|
||||||
|
process.on('SIGINT', this._undeclarePins);
|
||||||
|
process.on('uncaughtException', this._undeclarePins);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Restore the state from the storage object
|
||||||
|
*/
|
||||||
|
_restoreState() {
|
||||||
|
storage.getItem('_state', 'test').then(this._setState).catch((err) => {
|
||||||
|
this._setState();
|
||||||
|
log.error('_restoreState', err);
|
||||||
|
});
|
||||||
|
this._declarePins();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creating the state object.
|
||||||
|
*/
|
||||||
|
_setState(data = undefined) {
|
||||||
|
if (typeof data !== 'undefined') {
|
||||||
|
this._state = data;
|
||||||
|
this._state.frame.cb = () => { };
|
||||||
|
log.info('_setState', 'Restored intval state from disk');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
log.info('_setState', 'Setting state from defaults');
|
||||||
|
this._state = {
|
||||||
|
frame: {
|
||||||
|
dir: true,
|
||||||
|
start: 0,
|
||||||
|
active: false,
|
||||||
|
paused: false,
|
||||||
|
exposure: 0,
|
||||||
|
delay: 0,
|
||||||
|
current: {},
|
||||||
|
cb: () => { }
|
||||||
|
},
|
||||||
|
release: {
|
||||||
|
time: 0,
|
||||||
|
active: false //is pressed
|
||||||
|
},
|
||||||
|
micro: {
|
||||||
|
time: 0,
|
||||||
|
primed: false //is ready to stop frame
|
||||||
|
},
|
||||||
|
counter: 0,
|
||||||
|
sequence: false
|
||||||
|
};
|
||||||
|
this._storeState();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Store the state object.
|
||||||
|
*/
|
||||||
|
_storeState() {
|
||||||
|
storage.setItem('_state', this._state)
|
||||||
|
.then(() => { })
|
||||||
|
.catch((err) => {
|
||||||
|
log.error('_storeState', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* (internal function) Declares all Gpio pins that will be used.
|
||||||
|
*/
|
||||||
|
_declarePins() {
|
||||||
|
let pin;
|
||||||
|
for (let p in PINS) {
|
||||||
|
pin = PINS[p];
|
||||||
|
if (pin.edge)
|
||||||
|
this._pin[p] = new Gpio(pin.pin, pin.dir, pin.edge);
|
||||||
|
if (!pin.edge)
|
||||||
|
this._pin[p] = new Gpio(pin.pin, pin.dir);
|
||||||
|
log.info('_declarePins', { pin: pin.pin, dir: pin.dir, edge: pin.edge });
|
||||||
|
}
|
||||||
|
this._pin.release.watch(this._watchRelease);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* (internal function) Undeclares all Gpio in event of uncaught error
|
||||||
|
* that interupts the node process.
|
||||||
|
*/
|
||||||
|
_undeclarePins(e) {
|
||||||
|
log.error('_undeclarePins', e);
|
||||||
|
if (!this._pin) {
|
||||||
|
log.warn('_undeclarePins', { reason: 'No pins' });
|
||||||
|
return process.exit();
|
||||||
|
}
|
||||||
|
log.warn('_undeclarePins', { pin: PINS.fwd.pin, val: 0, reason: 'exiting' });
|
||||||
|
this._pin.fwd.writeSync(0);
|
||||||
|
log.warn('_undeclarePins', { pin: PINS.bwd.pin, val: 0, reason: 'exiting' });
|
||||||
|
this._pin.bwd.writeSync(0);
|
||||||
|
this._pin.fwd.unexport();
|
||||||
|
this._pin.bwd.unexport();
|
||||||
|
this._pin.micro.unexport();
|
||||||
|
this._pin.release.unexport();
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Start motor in forward direction by setting correct pins in h-bridge
|
||||||
|
*/
|
||||||
|
_startFwd() {
|
||||||
|
this._pin.fwd.writeSync(1);
|
||||||
|
this._pin.bwd.writeSync(0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Start motor in backward direction by setting correct pins in h-bridge
|
||||||
|
*/
|
||||||
|
_startBwd() {
|
||||||
|
this._pin.fwd.writeSync(0);
|
||||||
|
this._pin.bwd.writeSync(1);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Turn off all directions
|
||||||
|
*/
|
||||||
|
_pause() {
|
||||||
|
this._pin.fwd.writeSync(0);
|
||||||
|
this._pin.bwd.writeSync(0);
|
||||||
|
//log.info('_pause', 'frame paused')
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Stop motor by setting both motor pins to 0 (LOW)
|
||||||
|
*/
|
||||||
|
_stop() {
|
||||||
|
const entry = {};
|
||||||
|
const now = +new Date();
|
||||||
|
const len = now - this._state.frame.start;
|
||||||
|
this._pin.fwd.writeSync(0);
|
||||||
|
this._pin.bwd.writeSync(0);
|
||||||
|
log.info(`_stop`, { frame: len });
|
||||||
|
this._pin.micro.unwatch();
|
||||||
|
this._state.frame.active = false;
|
||||||
|
if (this._state.frame.cb)
|
||||||
|
this._state.frame.cb(len);
|
||||||
|
entry.start = this._state.frame.start;
|
||||||
|
entry.stop = now;
|
||||||
|
entry.len = len;
|
||||||
|
entry.dir = this._state.frame.current.dir ? 1 : 0;
|
||||||
|
entry.exposure = this._state.frame.current.exposure;
|
||||||
|
entry.counter = this._state.counter;
|
||||||
|
entry.sequence = this._state.sequence ? 1 : 0;
|
||||||
|
db.insert(entry);
|
||||||
|
this._state.frame.current = {};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Callback for watching relese switch state changes.
|
||||||
|
* Using GPIO 06 on Raspberry Pi Zero W.
|
||||||
|
*
|
||||||
|
* 1) If closed AND frame active, start timer, set state primed to `true`.
|
||||||
|
* 1) If opened AND frame active, stop frame
|
||||||
|
*
|
||||||
|
* Microswitch + 10K ohm resistor
|
||||||
|
* * 1 === open
|
||||||
|
* * 0 === closed
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} err Error object present if problem reading pin
|
||||||
|
* @param {integer} val Current value of the pin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
_watchMicro(err, val) {
|
||||||
|
const now = +new Date();
|
||||||
|
if (err) {
|
||||||
|
log.error('_watchMicro', err);
|
||||||
|
}
|
||||||
|
//log.info(`Microswitch val: ${val}`)
|
||||||
|
//determine when to stop
|
||||||
|
if (val === 0 && this._state.frame.active) {
|
||||||
|
if (!this._state.micro.primed) {
|
||||||
|
this._state.micro.primed = true;
|
||||||
|
this._state.micro.time = now;
|
||||||
|
log.info('Microswitch primed to stop motor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (val === 1 && this._state.frame.active) {
|
||||||
|
if (this._state.micro.primed && !this._state.micro.paused && (now - this._state.frame.start) > this._frame.open) {
|
||||||
|
this._state.micro.primed = false;
|
||||||
|
this._state.micro.time = 0;
|
||||||
|
setTimeout(() => {
|
||||||
|
this._stop();
|
||||||
|
}, this._microDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Callback for watching relese switch state changes.
|
||||||
|
* Using GPIO 05 on Raspberry Pi Zero W.
|
||||||
|
*
|
||||||
|
* 1) If closed, start timer.
|
||||||
|
* 2) If opened, check timer AND
|
||||||
|
* 3) If `press` (`now - this._state.release.time`) greater than minimum and less than `this._release.seq`, start frame
|
||||||
|
* 4) If `press` greater than `this._release.seq`, start sequence
|
||||||
|
*
|
||||||
|
* Button + 10K ohm resistor
|
||||||
|
* * 1 === open
|
||||||
|
* * 0 === closed
|
||||||
|
*
|
||||||
|
* @param {object} err Error object present if problem reading pin
|
||||||
|
* @param {integer} val Current value of the pin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
_watchRelease(err, val) {
|
||||||
|
const now = +new Date();
|
||||||
|
let press = 0;
|
||||||
|
if (err) {
|
||||||
|
return log.error(err);
|
||||||
|
}
|
||||||
|
//log.info(`Release switch val: ${val}`)
|
||||||
|
if (val === 0) {
|
||||||
|
//closed
|
||||||
|
if (this._releaseClosedState(now)) {
|
||||||
|
this._state.release.time = now;
|
||||||
|
this._state.release.active = true; //maybe unncecessary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (val === 1) {
|
||||||
|
//opened
|
||||||
|
if (this._state.release.active) {
|
||||||
|
press = now - this._state.release.time;
|
||||||
|
if (press > this._release.min && press < this._release.seq) {
|
||||||
|
this.frame();
|
||||||
|
}
|
||||||
|
else if (press >= this._release.seq) {
|
||||||
|
this.sequence();
|
||||||
|
}
|
||||||
|
//log.info(`Release closed for ${press}ms`)
|
||||||
|
this._state.release.time = 0;
|
||||||
|
this._state.release.active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
_releaseClosedState(now) {
|
||||||
|
if (!this._state.release.active && this._state.release.time === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this._state.release.active && (now - this._state.release.time) > (this._release.seq * 10)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Reset the state and store it.
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
this._setState();
|
||||||
|
this._storeState();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the default direction of the camera.
|
||||||
|
* * forward = true
|
||||||
|
* * backward = false
|
||||||
|
*
|
||||||
|
* @param {boolean} [dir=true] Direction of the camera
|
||||||
|
*/
|
||||||
|
setDir(val = true) {
|
||||||
|
if (typeof val !== 'boolean') {
|
||||||
|
return log.warn('Direction must be represented as either true or false');
|
||||||
|
}
|
||||||
|
this._state.frame.dir = val;
|
||||||
|
this._storeState();
|
||||||
|
log.info('setDir', { direction: val ? 'forward' : 'backward' });
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the exposure value for a single frame.
|
||||||
|
*
|
||||||
|
* @param {integer} val Length in milliseconds
|
||||||
|
*/
|
||||||
|
setExposure(val = 0) {
|
||||||
|
this._state.frame.exposure = val;
|
||||||
|
this._storeState();
|
||||||
|
log.info('setExposure', { exposure: val });
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the delay time between each frame.
|
||||||
|
*
|
||||||
|
* @param {integer} val Length in milliseconds
|
||||||
|
*/
|
||||||
|
setDelay(val = 0) {
|
||||||
|
this._state.frame.delay = val;
|
||||||
|
this._storeState();
|
||||||
|
log.info('setDelay', { delay: val });
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the counter to the value.
|
||||||
|
*
|
||||||
|
* @param {integer} val Frame number
|
||||||
|
*/
|
||||||
|
setCounter(val = 0) {
|
||||||
|
this._state.counter = val;
|
||||||
|
this._storeState();
|
||||||
|
log.info('setCounter', { counter: val });
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Begin a single frame with set variables or defaults
|
||||||
|
*
|
||||||
|
* @param {?boolean} [dir="null"] (optional) Direction of the frame
|
||||||
|
* @param {?integer} [exposure="null"] (optional) Exposure time, 0 = minimum
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
frame(dir = null, exposure = null, cb = () => { }) {
|
||||||
|
if (dir === true || (dir === null && this._state.frame.dir === true)) {
|
||||||
|
dir = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dir = false;
|
||||||
|
}
|
||||||
|
if (exposure === null && this._state.frame.exposure !== 0) {
|
||||||
|
exposure = this._state.frame.exposure;
|
||||||
|
}
|
||||||
|
else if (exposure === null) {
|
||||||
|
exposure = 0; //default speed
|
||||||
|
}
|
||||||
|
this._state.frame.start = +new Date();
|
||||||
|
this._state.frame.active = true;
|
||||||
|
this._pin.micro.watch(this._watchMicro);
|
||||||
|
log.info('frame', { dir: dir ? 'forward' : 'backward', exposure: exposure });
|
||||||
|
if (dir) {
|
||||||
|
this._startFwd();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._startBwd();
|
||||||
|
}
|
||||||
|
if (exposure !== 0) {
|
||||||
|
this._state.frame.paused = true;
|
||||||
|
if (dir) {
|
||||||
|
setTimeout(this._pause, this._frame.open);
|
||||||
|
//log.info('frame', { pausing : time + this._frame.open })
|
||||||
|
setTimeout(() => {
|
||||||
|
this._state.frame.paused = false;
|
||||||
|
this._startFwd();
|
||||||
|
}, exposure + this._frame.closed);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setTimeout(this._pause, this._frame.openBwd);
|
||||||
|
setTimeout(() => {
|
||||||
|
//log.info('frame', 'restarting')
|
||||||
|
this._state.frame.paused = false;
|
||||||
|
this._startBwd();
|
||||||
|
}, exposure + this._frame.closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dir) {
|
||||||
|
this._state.frame.cb = (len) => {
|
||||||
|
this._state.counter++;
|
||||||
|
this._storeState();
|
||||||
|
cb(len);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._state.frame.cb = (len) => {
|
||||||
|
this._state.counter--;
|
||||||
|
this._storeState();
|
||||||
|
cb(len);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this._state.frame.current = {
|
||||||
|
dir: dir,
|
||||||
|
exposure: exposure
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
status() {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
module.exports = new Intval();
|
||||||
/** Object representing the intval3 features */
|
//# sourceMappingURL=index.js.map
|
||||||
const intval = {}
|
|
||||||
|
|
||||||
intval._frame = {
|
|
||||||
open : 250, //delay before pausing frame in open state
|
|
||||||
openBwd : 400,
|
|
||||||
closed : 100, //time that frame actually remains closed for
|
|
||||||
expected : 530 //expected length of frame, in ms
|
|
||||||
}
|
|
||||||
intval._release = {
|
|
||||||
min : 20,
|
|
||||||
seq : 1000
|
|
||||||
}
|
|
||||||
intval._microDelay = 10 // delay after stop signal before stopping motors
|
|
||||||
intval._pin = {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
intval.init = function () {
|
|
||||||
if (!fs.existsSync('./state')) fs.mkdirSync('./state')
|
|
||||||
storage.init({
|
|
||||||
dir: './state',
|
|
||||||
stringify: JSON.stringify,
|
|
||||||
parse: JSON.parse,
|
|
||||||
encoding: 'utf8',
|
|
||||||
logging: false, // can also be custom logging function
|
|
||||||
continuous: true, // continously persist to disk
|
|
||||||
interval: false, // milliseconds, persist to disk on an interval
|
|
||||||
ttl: false, // ttl* [NEW], can be true for 24h default or a number in MILLISECONDS
|
|
||||||
expiredInterval: 2 * 60 * 1000, // [NEW] every 2 minutes the process will clean-up the expired cache
|
|
||||||
forgiveParseErrors: false // [NEW]
|
|
||||||
}).then(intval._restoreState).catch((err) => {
|
|
||||||
log.warn('init', err)
|
|
||||||
intval.reset()
|
|
||||||
intval._declarePins()
|
|
||||||
})
|
|
||||||
|
|
||||||
process.on('SIGINT', intval._undeclarePins)
|
|
||||||
process.on('uncaughtException', intval._undeclarePins)
|
|
||||||
}
|
|
||||||
|
|
||||||
intval._restoreState = function (res) {
|
|
||||||
storage.getItem('_state', 'test').then(intval._setState).catch((err) => {
|
|
||||||
intval._setState(undefined)
|
|
||||||
log.error('_restoreState', err)
|
|
||||||
})
|
|
||||||
intval._declarePins()
|
|
||||||
}
|
|
||||||
|
|
||||||
intval._setState = function (data) {
|
|
||||||
if (typeof data !== 'undefined') {
|
|
||||||
intval._state = data
|
|
||||||
intval._state.frame.cb = () => {}
|
|
||||||
log.info('_setState', 'Restored intval state from disk')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
log.info('_setState', 'Setting state from defaults')
|
|
||||||
intval._state = {
|
|
||||||
frame : {
|
|
||||||
dir : true, //forward
|
|
||||||
start : 0, //time frame started, timestamp
|
|
||||||
active : false, //should frame be running
|
|
||||||
paused : false,
|
|
||||||
exposure : 0, //length of frame exposure, in ms
|
|
||||||
delay : 0, //delay before start of frame, in ms
|
|
||||||
current : {}, //current settings
|
|
||||||
cb : () => {}
|
|
||||||
},
|
|
||||||
release : {
|
|
||||||
time: 0,
|
|
||||||
active : false //is pressed
|
|
||||||
},
|
|
||||||
micro : {
|
|
||||||
time : 0,
|
|
||||||
primed : false //is ready to stop frame
|
|
||||||
},
|
|
||||||
counter : 0,
|
|
||||||
sequence : false
|
|
||||||
}
|
|
||||||
intval._storeState()
|
|
||||||
}
|
|
||||||
|
|
||||||
intval._storeState = function () {
|
|
||||||
storage.setItem('_state', intval._state)
|
|
||||||
.then(() => {})
|
|
||||||
.catch((err) => {
|
|
||||||
log.error('_storeState', err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* (internal function) Declares all Gpio pins that will be used
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval._declarePins = function () {
|
|
||||||
let pin
|
|
||||||
for (let p in PINS) {
|
|
||||||
pin = PINS[p]
|
|
||||||
if (pin.edge) intval._pin[p] = new Gpio(pin.pin, pin.dir, pin.edge)
|
|
||||||
if (!pin.edge) intval._pin[p] = new Gpio(pin.pin, pin.dir)
|
|
||||||
log.info('_declarePins', { pin : pin.pin, dir : pin.dir, edge : pin.edge })
|
|
||||||
}
|
|
||||||
intval._pin.release.watch(intval._watchRelease)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* (internal function) Undeclares all Gpio in event of uncaught error
|
|
||||||
* that interupts the node process
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval._undeclarePins = function (e) {
|
|
||||||
log.error(e)
|
|
||||||
if (!intval._pin) {
|
|
||||||
log.warn('_undeclarePins', { reason : 'No pins'})
|
|
||||||
return process.exit()
|
|
||||||
}
|
|
||||||
log.warn('_undeclarePins', { pin : PINS.fwd.pin, val : 0, reason : 'exiting'})
|
|
||||||
intval._pin.fwd.writeSync(0)
|
|
||||||
log.warn('_undeclarePins', { pin : PINS.bwd.pin, val : 0, reason : 'exiting'})
|
|
||||||
intval._pin.bwd.writeSync(0)
|
|
||||||
intval._pin.fwd.unexport()
|
|
||||||
intval._pin.bwd.unexport()
|
|
||||||
intval._pin.micro.unexport()
|
|
||||||
intval._pin.release.unexport()
|
|
||||||
process.exit()
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Start motor in forward direction by setting correct pins in h-bridge
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval._startFwd = function () {
|
|
||||||
intval._pin.fwd.writeSync(1)
|
|
||||||
intval._pin.bwd.writeSync(0)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Start motor in backward direction by setting correct pins in h-bridge
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval._startBwd = function () {
|
|
||||||
intval._pin.fwd.writeSync(0)
|
|
||||||
intval._pin.bwd.writeSync(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
intval._pause = function () {
|
|
||||||
intval._pin.fwd.writeSync(0)
|
|
||||||
intval._pin.bwd.writeSync(0)
|
|
||||||
//log.info('_pause', 'frame paused')
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Stop motor by setting both motor pins to 0 (LOW)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval._stop = function () {
|
|
||||||
const entry = {}
|
|
||||||
const now = +new Date()
|
|
||||||
const len = now - intval._state.frame.start
|
|
||||||
|
|
||||||
intval._pin.fwd.writeSync(0)
|
|
||||||
intval._pin.bwd.writeSync(0)
|
|
||||||
|
|
||||||
log.info(`_stop`, { frame : len })
|
|
||||||
|
|
||||||
intval._pin.micro.unwatch()
|
|
||||||
intval._state.frame.active = false
|
|
||||||
|
|
||||||
if (intval._state.frame.cb) intval._state.frame.cb(len)
|
|
||||||
|
|
||||||
entry.start = intval._state.frame.start
|
|
||||||
entry.stop = now
|
|
||||||
entry.len = len
|
|
||||||
entry.dir = intval._state.frame.current.dir ? 1 : 0
|
|
||||||
entry.exposure = intval._state.frame.current.exposure
|
|
||||||
entry.counter = intval._state.counter
|
|
||||||
entry.sequence = intval._state.sequence ? 1 : 0
|
|
||||||
|
|
||||||
db.insert(entry)
|
|
||||||
|
|
||||||
intval._state.frame.current = {}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Callback for watching relese switch state changes.
|
|
||||||
* Using GPIO 06 on Raspberry Pi Zero W.
|
|
||||||
*
|
|
||||||
* 1) If closed AND frame active, start timer, set state primed to `true`.
|
|
||||||
* 1) If opened AND frame active, stop frame
|
|
||||||
*
|
|
||||||
* Microswitch + 10K ohm resistor
|
|
||||||
* * 1 === open
|
|
||||||
* * 0 === closed
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param {object} err Error object present if problem reading pin
|
|
||||||
* @param {integer} val Current value of the pin
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval._watchMicro = function (err, val) {
|
|
||||||
const now = +new Date()
|
|
||||||
if (err) {
|
|
||||||
log.error('_watchMicro', err)
|
|
||||||
}
|
|
||||||
//log.info(`Microswitch val: ${val}`)
|
|
||||||
//determine when to stop
|
|
||||||
if (val === 0 && intval._state.frame.active) {
|
|
||||||
if (!intval._state.micro.primed) {
|
|
||||||
intval._state.micro.primed = true
|
|
||||||
intval._state.micro.time = now
|
|
||||||
log.info('Microswitch primed to stop motor')
|
|
||||||
}
|
|
||||||
} else if (val === 1 && intval._state.frame.active) {
|
|
||||||
if (intval._state.micro.primed && !intval._state.micro.paused && (now - intval._state.frame.start) > intval._frame.open) {
|
|
||||||
intval._state.micro.primed = false
|
|
||||||
intval._state.micro.time = 0
|
|
||||||
setTimeout( () => {
|
|
||||||
intval._stop()
|
|
||||||
}, intval._microDelay)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Callback for watching relese switch state changes.
|
|
||||||
* Using GPIO 05 on Raspberry Pi Zero W.
|
|
||||||
*
|
|
||||||
* 1) If closed, start timer.
|
|
||||||
* 2) If opened, check timer AND
|
|
||||||
* 3) If `press` (`now - intval._state.release.time`) greater than minimum and less than `intval._release.seq`, start frame
|
|
||||||
* 4) If `press` greater than `intval._release.seq`, start sequence
|
|
||||||
*
|
|
||||||
* Button + 10K ohm resistor
|
|
||||||
* * 1 === open
|
|
||||||
* * 0 === closed
|
|
||||||
*
|
|
||||||
* @param {object} err Error object present if problem reading pin
|
|
||||||
* @param {integer} val Current value of the pin
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval._watchRelease = function (err, val) {
|
|
||||||
const now = +new Date()
|
|
||||||
let press = 0
|
|
||||||
if (err) {
|
|
||||||
return log.error(err)
|
|
||||||
}
|
|
||||||
//log.info(`Release switch val: ${val}`)
|
|
||||||
if (val === 0) {
|
|
||||||
//closed
|
|
||||||
if (intval._releaseClosedState(now)) {
|
|
||||||
intval._state.release.time = now
|
|
||||||
intval._state.release.active = true //maybe unncecessary
|
|
||||||
}
|
|
||||||
} else if (val === 1) {
|
|
||||||
//opened
|
|
||||||
if (intval._state.release.active) {
|
|
||||||
press = now - intval._state.release.time
|
|
||||||
if (press > intval._release.min && press < intval._release.seq) {
|
|
||||||
intval.frame()
|
|
||||||
} else if (press >= intval._release.seq) {
|
|
||||||
intval.sequence()
|
|
||||||
}
|
|
||||||
//log.info(`Release closed for ${press}ms`)
|
|
||||||
intval._state.release.time = 0
|
|
||||||
intval._state.release.active = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
intval._releaseClosedState = function (now) {
|
|
||||||
if (!intval._state.release.active && intval._state.release.time === 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (intval._state.release.active && (now - intval._state.release.time) > (intval._release.seq * 10)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
intval.reset = function () {
|
|
||||||
intval._setState()
|
|
||||||
intval._storeState()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the default direction of the camera.
|
|
||||||
* * forward = true
|
|
||||||
* * backward = false
|
|
||||||
*
|
|
||||||
* @param {boolean} [dir=true] Direction of the camera
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval.setDir = function (val = true) {
|
|
||||||
if (typeof val !== 'boolean') {
|
|
||||||
return log.warn('Direction must be represented as either true or false')
|
|
||||||
}
|
|
||||||
intval._state.frame.dir = val
|
|
||||||
intval._storeState()
|
|
||||||
log.info('setDir', { direction : val ? 'forward' : 'backward' })
|
|
||||||
}
|
|
||||||
|
|
||||||
intval.setExposure = function (val = 0) {
|
|
||||||
intval._state.frame.exposure = val
|
|
||||||
intval._storeState()
|
|
||||||
log.info('setExposure', { exposure : val })
|
|
||||||
}
|
|
||||||
|
|
||||||
intval.setDelay = function (val = 0) {
|
|
||||||
intval._state.frame.delay = val
|
|
||||||
intval._storeState()
|
|
||||||
log.info('setDelay', { delay : val })
|
|
||||||
}
|
|
||||||
intval.setCounter = function (val = 0) {
|
|
||||||
intval._state.counter = val
|
|
||||||
intval._storeState()
|
|
||||||
log.info('setCounter', { counter : val })
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Begin a single frame with set variables or defaults
|
|
||||||
*
|
|
||||||
* @param {?boolean} [dir="null"] (optional) Direction of the frame
|
|
||||||
* @param {?integer} [exposure="null"] (optional) Exposure time, 0 = minimum
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
intval.frame = function (dir = null, exposure = null, cb = () => {}) {
|
|
||||||
if (dir === true || (dir === null && intval._state.frame.dir === true) ) {
|
|
||||||
dir = true
|
|
||||||
} else {
|
|
||||||
dir = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exposure === null && intval._state.frame.exposure !== 0) {
|
|
||||||
exposure = intval._state.frame.exposure
|
|
||||||
} else if (exposure === null) {
|
|
||||||
exposure = 0 //default speed
|
|
||||||
}
|
|
||||||
|
|
||||||
intval._state.frame.start = +new Date()
|
|
||||||
intval._state.frame.active = true
|
|
||||||
intval._pin.micro.watch(intval._watchMicro)
|
|
||||||
|
|
||||||
log.info('frame', {dir : dir ? 'forward' : 'backward', exposure : exposure})
|
|
||||||
|
|
||||||
if (dir) {
|
|
||||||
intval._startFwd()
|
|
||||||
} else {
|
|
||||||
intval._startBwd()
|
|
||||||
}
|
|
||||||
if (exposure !== 0) {
|
|
||||||
intval._state.frame.paused = true
|
|
||||||
if (dir) {
|
|
||||||
setTimeout(intval._pause, intval._frame.open)
|
|
||||||
//log.info('frame', { pausing : time + intval._frame.open })
|
|
||||||
setTimeout( () => {
|
|
||||||
intval._state.frame.paused = false
|
|
||||||
intval._startFwd()
|
|
||||||
}, exposure + intval._frame.closed)
|
|
||||||
} else {
|
|
||||||
setTimeout(intval._pause, intval._frame.openBwd)
|
|
||||||
setTimeout( () => {
|
|
||||||
//log.info('frame', 'restarting')
|
|
||||||
intval._state.frame.paused = false
|
|
||||||
intval._startBwd()
|
|
||||||
}, exposure + intval._frame.closed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dir) {
|
|
||||||
intval._state.frame.cb = (len) => {
|
|
||||||
intval._state.counter++
|
|
||||||
intval._storeState()
|
|
||||||
cb(len)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
intval._state.frame.cb = (len) => {
|
|
||||||
intval._state.counter--
|
|
||||||
intval._storeState()
|
|
||||||
cb(len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
intval._state.frame.current = {
|
|
||||||
dir: dir,
|
|
||||||
exposure: exposure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
intval.status = function () {
|
|
||||||
return intval._state
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = intval
|
|
File diff suppressed because one or more lines are too long
|
@ -1,43 +1,50 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const uuid = require('uuid').v4;
|
const v4_1 = __importDefault(require("uuid/v4"));
|
||||||
const log = require('../log')('seq');
|
const log = require('../log')('seq');
|
||||||
require("../delay");
|
require("../delay");
|
||||||
/** Object sequence features */
|
/** Object sequence features */
|
||||||
class Sequence {
|
class Sequence {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._state = {
|
this._state = {
|
||||||
arr: [],
|
arr: []
|
||||||
active: false,
|
|
||||||
paused: false,
|
|
||||||
frame: false,
|
|
||||||
delay: false,
|
|
||||||
count: 0,
|
|
||||||
stop: null
|
|
||||||
};
|
};
|
||||||
|
this.active = false;
|
||||||
|
this.paused = false;
|
||||||
|
this.frame = false;
|
||||||
|
this.delay = false;
|
||||||
|
this.count = 0;
|
||||||
|
this._stop = null;
|
||||||
this._loop = {
|
this._loop = {
|
||||||
arr: [],
|
arr: [],
|
||||||
count: 0,
|
count: 0,
|
||||||
max: 0
|
max: 0
|
||||||
};
|
};
|
||||||
this.stop = function () {
|
this.stop = function () {
|
||||||
this._state.active = false;
|
this.active = false;
|
||||||
this._state.count = 0;
|
this.count = 0;
|
||||||
this._state.arr = [];
|
this._state.arr = [];
|
||||||
this._loop.count = 0;
|
this._loop.count = 0;
|
||||||
this._loop.max = 0;
|
this._loop.max = 0;
|
||||||
this._loop.arr = [];
|
this._loop.arr = [];
|
||||||
if (this._state.stop)
|
if (this._stop)
|
||||||
this._state.stop();
|
this._stop();
|
||||||
this._state.stop = null;
|
this._stop = null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Start running a "sequence" of frames. Shoots a continuous sequence
|
||||||
|
* of single frames with a delay in between each one.
|
||||||
|
**/
|
||||||
start(options, cb) {
|
start(options, cb) {
|
||||||
if (this._state.active) {
|
if (this._state.active) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this._state.active = true;
|
this.active = true;
|
||||||
this._state.count = 0;
|
this.count = 0;
|
||||||
if (options.arr) {
|
if (options.arr) {
|
||||||
this._state.arr = options.arr;
|
this._state.arr = options.arr;
|
||||||
}
|
}
|
||||||
|
@ -51,44 +58,44 @@ class Sequence {
|
||||||
else {
|
else {
|
||||||
this._loop.max = 0;
|
this._loop.max = 0;
|
||||||
}
|
}
|
||||||
this._state.stop = cb;
|
this._stop = cb;
|
||||||
this.step();
|
this.step();
|
||||||
this._state.id = uuid();
|
this.id = v4_1.default();
|
||||||
return this._state.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
setStop() {
|
setStop() {
|
||||||
this._state.active = false;
|
this.active = false;
|
||||||
}
|
}
|
||||||
pause() {
|
pause() {
|
||||||
this._state.paused = true;
|
this.paused = true;
|
||||||
}
|
}
|
||||||
resume() {
|
resume() {
|
||||||
this._state.paused = false;
|
this.paused = false;
|
||||||
this.step();
|
this.step();
|
||||||
}
|
}
|
||||||
step() {
|
step() {
|
||||||
if (this._state.active && !this._state.paused) {
|
if (this.active && !this.paused) {
|
||||||
if (this._state.arr.length > 0) {
|
if (this._state.arr.length > 0) {
|
||||||
if (this._state.count > this._state.arr.length - 1) {
|
if (this.count > this._state.arr.length - 1) {
|
||||||
return this.stop();
|
return this.stop();
|
||||||
}
|
}
|
||||||
log.info('step', { count: this._state.count, id: this._state.id });
|
log.info('step', { count: this.count, id: this._state.id });
|
||||||
return this._state.arr[this._state.count](() => {
|
return this._state.arr[this.count](() => {
|
||||||
this._state.count++;
|
this.count++;
|
||||||
this.step();
|
this.step();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (this._loop.arr.length > 0) {
|
else if (this._loop.arr.length > 0) {
|
||||||
if (this._state.count > this._loop.arr.length - 1) {
|
if (this.count > this._loop.arr.length - 1) {
|
||||||
this._state.count = 0;
|
this.count = 0;
|
||||||
this._loop.count++;
|
this._loop.count++;
|
||||||
}
|
}
|
||||||
if (this._loop.max > 0 && this._loop.count > this._loop.max) {
|
if (this._loop.max > 0 && this._loop.count > this._loop.max) {
|
||||||
return this.stop();
|
return this.stop();
|
||||||
}
|
}
|
||||||
log.info('step', { count: this._state.count, id: this._state.id });
|
log.info('step', { count: this.count, id: this.id });
|
||||||
return this._loop.arr[this._state.count](() => {
|
return this._loop.arr[this.count](() => {
|
||||||
this._state.count++;
|
this.count++;
|
||||||
this.step();
|
this.step();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -96,11 +103,11 @@ class Sequence {
|
||||||
return this.stop();
|
return this.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (this._state.paused) {
|
else if (this.paused) {
|
||||||
log.info('step', 'Sequence paused', { loop: this._loop.count, count: this._state.count });
|
log.info('step', 'Sequence paused', { loop: this._loop.count, count: this.count });
|
||||||
}
|
}
|
||||||
else if (!this._state.active) {
|
else if (!this.active) {
|
||||||
log.info('step', 'Sequence stopped', { loop: this._loop.count, count: this._state.count });
|
log.info('step', 'Sequence stopped', { loop: this._loop.count, count: this.count });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sequence/index.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sequence/index.ts"],"names":[],"mappings":"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"}
|
File diff suppressed because it is too large
Load Diff
|
@ -27,6 +27,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bleno": "^0.5.0",
|
"bleno": "^0.5.0",
|
||||||
"cron": "^1.7.2",
|
"cron": "^1.7.2",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
"node-ipc": "^9.1.1",
|
"node-ipc": "^9.1.1",
|
||||||
"node-persist": "^3.0.5",
|
"node-persist": "^3.0.5",
|
||||||
"onoff": "^5.0.0",
|
"onoff": "^5.0.0",
|
||||||
|
@ -37,7 +38,10 @@
|
||||||
"winston": "^3.2.1"
|
"winston": "^3.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/fs-extra": "^8.0.0",
|
||||||
"@types/node": "^12.7.12",
|
"@types/node": "^12.7.12",
|
||||||
|
"@types/node-persist": "0.0.33",
|
||||||
|
"@types/uuid": "^3.4.5",
|
||||||
"jsdoc-to-markdown": "^5.0.2",
|
"jsdoc-to-markdown": "^5.0.2",
|
||||||
"qunit": "^2.9.3",
|
"qunit": "^2.9.3",
|
||||||
"typescript": "^3.6.4"
|
"typescript": "^3.6.4"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
sudo -u pi -i<< EOF
|
sudo -u pi -i<< EOF
|
||||||
cd /home/pi/intval3 && git pull
|
cd /home/pi/intval3 && git reset --hard && git pull && npm i
|
||||||
EOF
|
EOF
|
|
@ -0,0 +1,519 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const db = require('../db');
|
||||||
|
const log = require('../log')('intval');
|
||||||
|
import * as storage from 'node-persist';
|
||||||
|
import { exists, mkdir } from 'fs-extra';
|
||||||
|
import '../delay';
|
||||||
|
|
||||||
|
let Gpio : any
|
||||||
|
try {
|
||||||
|
Gpio = require('onoff').Gpio
|
||||||
|
} catch (e) {
|
||||||
|
log.warn('Failed including Gpio, using sim')
|
||||||
|
Gpio = require('../../lib/onoffsim').Gpio
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const PINS = {
|
||||||
|
fwd : {
|
||||||
|
pin : 13,
|
||||||
|
dir : 'out'
|
||||||
|
},
|
||||||
|
bwd : {
|
||||||
|
pin : 19,
|
||||||
|
dir : 'out'
|
||||||
|
},
|
||||||
|
micro : {
|
||||||
|
pin : 5,
|
||||||
|
dir : 'in',
|
||||||
|
edge : 'both'
|
||||||
|
},
|
||||||
|
release : {
|
||||||
|
pin : 6,
|
||||||
|
dir : 'in',
|
||||||
|
edge : 'both'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Entry {
|
||||||
|
start : number;
|
||||||
|
stop : number;
|
||||||
|
len : number;
|
||||||
|
dir : number;
|
||||||
|
exposure : number;
|
||||||
|
counter : number;
|
||||||
|
sequence : number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** class representing the intval3 features */
|
||||||
|
class Intval {
|
||||||
|
private STATE_DIR : string = '~/state';
|
||||||
|
|
||||||
|
private _frame : any = {
|
||||||
|
open : 250, //delay before pausing frame in open state
|
||||||
|
openBwd : 400,
|
||||||
|
closed : 100, //time that frame actually remains closed for
|
||||||
|
expected : 530 //expected length of frame, in ms
|
||||||
|
}
|
||||||
|
private _release : any = {
|
||||||
|
min : 20,
|
||||||
|
seq : 1000
|
||||||
|
}
|
||||||
|
private _microDelay : number = 10; // delay after stop signal before stopping motors
|
||||||
|
private _pin : any = {};
|
||||||
|
private _state : any = {};
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the storage object and bind functions to process events.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private async _init () {
|
||||||
|
let dirExists : boolean;
|
||||||
|
|
||||||
|
try {
|
||||||
|
dirExists = await exists(this.STATE_DIR);
|
||||||
|
} catch (err) {
|
||||||
|
log.error('init', `Error locating state directory ${this.STATE_DIR}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dirExists) {
|
||||||
|
try {
|
||||||
|
await mkdir(this.STATE_DIR);
|
||||||
|
} catch (err) {
|
||||||
|
log.error('init', `Error creating state directory ${this.STATE_DIR}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
storage.init({
|
||||||
|
dir: this.STATE_DIR,
|
||||||
|
stringify: JSON.stringify,
|
||||||
|
parse: JSON.parse,
|
||||||
|
encoding: 'utf8',
|
||||||
|
logging: false, // can also be custom logging function
|
||||||
|
continuous: true, // continously persist to disk
|
||||||
|
interval: false, // milliseconds, persist to disk on an interval
|
||||||
|
ttl: false, // ttl* [NEW], can be true for 24h default or a number in MILLISECONDS
|
||||||
|
//expiredInterval: 2 * 60 * 1000, // [NEW] every 2 minutes the process will clean-up the expired cache
|
||||||
|
//forgiveParseErrors: false // [NEW]
|
||||||
|
}).then(this._restoreState).catch((err) => {
|
||||||
|
log.warn('init', err)
|
||||||
|
this.reset();
|
||||||
|
this._declarePins();
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on('SIGINT', this._undeclarePins);
|
||||||
|
process.on('uncaughtException', this._undeclarePins);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the state from the storage object
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _restoreState () {
|
||||||
|
storage.getItem('_state', 'test').then(this._setState).catch((err) => {
|
||||||
|
this._setState();
|
||||||
|
log.error('_restoreState', err);
|
||||||
|
})
|
||||||
|
this._declarePins();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creating the state object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _setState (data : any = undefined) {
|
||||||
|
if (typeof data !== 'undefined') {
|
||||||
|
this._state = data;
|
||||||
|
this._state.frame.cb = () => {};
|
||||||
|
log.info('_setState', 'Restored intval state from disk');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
log.info('_setState', 'Setting state from defaults');
|
||||||
|
this._state = {
|
||||||
|
frame : {
|
||||||
|
dir : true, //forward
|
||||||
|
start : 0, //time frame started, timestamp
|
||||||
|
active : false, //should frame be running
|
||||||
|
paused : false,
|
||||||
|
exposure : 0, //length of frame exposure, in ms
|
||||||
|
delay : 0, //delay before start of frame, in ms
|
||||||
|
current : {}, //current settings
|
||||||
|
cb : () => {}
|
||||||
|
},
|
||||||
|
release : {
|
||||||
|
time: 0,
|
||||||
|
active : false //is pressed
|
||||||
|
},
|
||||||
|
micro : {
|
||||||
|
time : 0,
|
||||||
|
primed : false //is ready to stop frame
|
||||||
|
},
|
||||||
|
counter : 0,
|
||||||
|
sequence : false
|
||||||
|
}
|
||||||
|
this._storeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the state object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _storeState () {
|
||||||
|
storage.setItem('_state', this._state)
|
||||||
|
.then(() => {})
|
||||||
|
.catch((err) => {
|
||||||
|
log.error('_storeState', err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (internal function) Declares all Gpio pins that will be used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _declarePins () {
|
||||||
|
let pin;
|
||||||
|
for (let p in PINS) {
|
||||||
|
pin = PINS[p];
|
||||||
|
if (pin.edge) this._pin[p] = new Gpio(pin.pin, pin.dir, pin.edge);
|
||||||
|
if (!pin.edge) this._pin[p] = new Gpio(pin.pin, pin.dir);
|
||||||
|
log.info('_declarePins', { pin : pin.pin, dir : pin.dir, edge : pin.edge });
|
||||||
|
}
|
||||||
|
this._pin.release.watch(this._watchRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (internal function) Undeclares all Gpio in event of uncaught error
|
||||||
|
* that interupts the node process.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _undeclarePins (e : Error) {
|
||||||
|
log.error('_undeclarePins', e);
|
||||||
|
if (!this._pin) {
|
||||||
|
log.warn('_undeclarePins', { reason : 'No pins'});
|
||||||
|
return process.exit();
|
||||||
|
}
|
||||||
|
log.warn('_undeclarePins', { pin : PINS.fwd.pin, val : 0, reason : 'exiting'});
|
||||||
|
this._pin.fwd.writeSync(0);
|
||||||
|
log.warn('_undeclarePins', { pin : PINS.bwd.pin, val : 0, reason : 'exiting'});
|
||||||
|
this._pin.bwd.writeSync(0);
|
||||||
|
this._pin.fwd.unexport();
|
||||||
|
this._pin.bwd.unexport();
|
||||||
|
this._pin.micro.unexport();
|
||||||
|
this._pin.release.unexport();
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start motor in forward direction by setting correct pins in h-bridge
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _startFwd () {
|
||||||
|
this._pin.fwd.writeSync(1);
|
||||||
|
this._pin.bwd.writeSync(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start motor in backward direction by setting correct pins in h-bridge
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _startBwd () {
|
||||||
|
this._pin.fwd.writeSync(0);
|
||||||
|
this._pin.bwd.writeSync(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn off all directions
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _pause () {
|
||||||
|
this._pin.fwd.writeSync(0);
|
||||||
|
this._pin.bwd.writeSync(0);
|
||||||
|
//log.info('_pause', 'frame paused')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop motor by setting both motor pins to 0 (LOW)
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _stop () {
|
||||||
|
const entry : any = {};
|
||||||
|
const now : number = +new Date();
|
||||||
|
const len : number = now - this._state.frame.start;
|
||||||
|
|
||||||
|
this._pin.fwd.writeSync(0);
|
||||||
|
this._pin.bwd.writeSync(0);
|
||||||
|
|
||||||
|
log.info(`_stop`, { frame : len });
|
||||||
|
|
||||||
|
this._pin.micro.unwatch();
|
||||||
|
this._state.frame.active = false;
|
||||||
|
|
||||||
|
if (this._state.frame.cb) this._state.frame.cb(len);
|
||||||
|
|
||||||
|
entry.start = this._state.frame.start;
|
||||||
|
entry.stop = now;
|
||||||
|
entry.len = len;
|
||||||
|
entry.dir = this._state.frame.current.dir ? 1 : 0;
|
||||||
|
entry.exposure = this._state.frame.current.exposure;
|
||||||
|
entry.counter = this._state.counter;
|
||||||
|
entry.sequence = this._state.sequence ? 1 : 0;
|
||||||
|
|
||||||
|
db.insert(entry);
|
||||||
|
|
||||||
|
this._state.frame.current = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for watching relese switch state changes.
|
||||||
|
* Using GPIO 06 on Raspberry Pi Zero W.
|
||||||
|
*
|
||||||
|
* 1) If closed AND frame active, start timer, set state primed to `true`.
|
||||||
|
* 1) If opened AND frame active, stop frame
|
||||||
|
*
|
||||||
|
* Microswitch + 10K ohm resistor
|
||||||
|
* * 1 === open
|
||||||
|
* * 0 === closed
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {object} err Error object present if problem reading pin
|
||||||
|
* @param {integer} val Current value of the pin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _watchMicro (err : Error, val : number) {
|
||||||
|
const now : number = +new Date();
|
||||||
|
if (err) {
|
||||||
|
log.error('_watchMicro', err);
|
||||||
|
}
|
||||||
|
//log.info(`Microswitch val: ${val}`)
|
||||||
|
//determine when to stop
|
||||||
|
if (val === 0 && this._state.frame.active) {
|
||||||
|
if (!this._state.micro.primed) {
|
||||||
|
this._state.micro.primed = true;
|
||||||
|
this._state.micro.time = now;
|
||||||
|
log.info('Microswitch primed to stop motor');
|
||||||
|
}
|
||||||
|
} else if (val === 1 && this._state.frame.active) {
|
||||||
|
if (this._state.micro.primed && !this._state.micro.paused && (now - this._state.frame.start) > this._frame.open) {
|
||||||
|
this._state.micro.primed = false;
|
||||||
|
this._state.micro.time = 0;
|
||||||
|
setTimeout( () => {
|
||||||
|
this._stop();
|
||||||
|
}, this._microDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for watching relese switch state changes.
|
||||||
|
* Using GPIO 05 on Raspberry Pi Zero W.
|
||||||
|
*
|
||||||
|
* 1) If closed, start timer.
|
||||||
|
* 2) If opened, check timer AND
|
||||||
|
* 3) If `press` (`now - this._state.release.time`) greater than minimum and less than `this._release.seq`, start frame
|
||||||
|
* 4) If `press` greater than `this._release.seq`, start sequence
|
||||||
|
*
|
||||||
|
* Button + 10K ohm resistor
|
||||||
|
* * 1 === open
|
||||||
|
* * 0 === closed
|
||||||
|
*
|
||||||
|
* @param {object} err Error object present if problem reading pin
|
||||||
|
* @param {integer} val Current value of the pin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _watchRelease (err : Error, val : number) {
|
||||||
|
const now : number = +new Date();
|
||||||
|
let press : number = 0;
|
||||||
|
if (err) {
|
||||||
|
return log.error(err);
|
||||||
|
}
|
||||||
|
//log.info(`Release switch val: ${val}`)
|
||||||
|
if (val === 0) {
|
||||||
|
//closed
|
||||||
|
if (this._releaseClosedState(now)) {
|
||||||
|
this._state.release.time = now;
|
||||||
|
this._state.release.active = true; //maybe unncecessary
|
||||||
|
}
|
||||||
|
} else if (val === 1) {
|
||||||
|
//opened
|
||||||
|
if (this._state.release.active) {
|
||||||
|
press = now - this._state.release.time;
|
||||||
|
if (press > this._release.min && press < this._release.seq) {
|
||||||
|
this.frame();
|
||||||
|
} else if (press >= this._release.seq) {
|
||||||
|
this.sequence();
|
||||||
|
}
|
||||||
|
//log.info(`Release closed for ${press}ms`)
|
||||||
|
this._state.release.time = 0;
|
||||||
|
this._state.release.active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _releaseClosedState (now : number) {
|
||||||
|
if (!this._state.release.active && this._state.release.time === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this._state.release.active && (now - this._state.release.time) > (this._release.seq * 10)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the state and store it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public reset () {
|
||||||
|
this._setState();
|
||||||
|
this._storeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default direction of the camera.
|
||||||
|
* * forward = true
|
||||||
|
* * backward = false
|
||||||
|
*
|
||||||
|
* @param {boolean} [dir=true] Direction of the camera
|
||||||
|
*/
|
||||||
|
|
||||||
|
public setDir (val : boolean = true) {
|
||||||
|
if (typeof val !== 'boolean') {
|
||||||
|
return log.warn('Direction must be represented as either true or false');
|
||||||
|
}
|
||||||
|
this._state.frame.dir = val;
|
||||||
|
this._storeState();
|
||||||
|
log.info('setDir', { direction : val ? 'forward' : 'backward' });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the exposure value for a single frame.
|
||||||
|
*
|
||||||
|
* @param {integer} val Length in milliseconds
|
||||||
|
*/
|
||||||
|
|
||||||
|
public setExposure (val : number = 0) {
|
||||||
|
this._state.frame.exposure = val;
|
||||||
|
this._storeState();
|
||||||
|
log.info('setExposure', { exposure : val });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the delay time between each frame.
|
||||||
|
*
|
||||||
|
* @param {integer} val Length in milliseconds
|
||||||
|
*/
|
||||||
|
|
||||||
|
public setDelay (val : number = 0) {
|
||||||
|
this._state.frame.delay = val;
|
||||||
|
this._storeState();
|
||||||
|
log.info('setDelay', { delay : val });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the counter to the value.
|
||||||
|
*
|
||||||
|
* @param {integer} val Frame number
|
||||||
|
*/
|
||||||
|
|
||||||
|
public setCounter (val : number = 0) {
|
||||||
|
this._state.counter = val;
|
||||||
|
this._storeState();
|
||||||
|
log.info('setCounter', { counter : val });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin a single frame with set variables or defaults
|
||||||
|
*
|
||||||
|
* @param {?boolean} [dir="null"] (optional) Direction of the frame
|
||||||
|
* @param {?integer} [exposure="null"] (optional) Exposure time, 0 = minimum
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public frame (dir : boolean = null, exposure : number = null, cb : Function = () => {}) {
|
||||||
|
if (dir === true || (dir === null && this._state.frame.dir === true) ) {
|
||||||
|
dir = true;
|
||||||
|
} else {
|
||||||
|
dir = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exposure === null && this._state.frame.exposure !== 0) {
|
||||||
|
exposure = this._state.frame.exposure;
|
||||||
|
} else if (exposure === null) {
|
||||||
|
exposure = 0; //default speed
|
||||||
|
}
|
||||||
|
|
||||||
|
this._state.frame.current.exposure = exposure;
|
||||||
|
this._state.frame.current.dir = dir;
|
||||||
|
|
||||||
|
this._state.frame.start = +new Date();
|
||||||
|
this._state.frame.active = true;
|
||||||
|
this._pin.micro.watch(this._watchMicro);
|
||||||
|
|
||||||
|
log.info('frame', {dir : dir ? 'forward' : 'backward', exposure : exposure});
|
||||||
|
|
||||||
|
if (dir) {
|
||||||
|
this._startFwd();
|
||||||
|
} else {
|
||||||
|
this._startBwd();
|
||||||
|
}
|
||||||
|
if (exposure !== 0) {
|
||||||
|
this._state.frame.paused = true;
|
||||||
|
if (dir) {
|
||||||
|
setTimeout(this._pause, this._frame.open);
|
||||||
|
//log.info('frame', { pausing : time + this._frame.open })
|
||||||
|
setTimeout( () => {
|
||||||
|
this._state.frame.paused = false;
|
||||||
|
this._startFwd();
|
||||||
|
}, exposure + this._frame.closed);
|
||||||
|
} else {
|
||||||
|
setTimeout(this._pause, this._frame.openBwd);
|
||||||
|
setTimeout( () => {
|
||||||
|
//log.info('frame', 'restarting')
|
||||||
|
this._state.frame.paused = false;
|
||||||
|
this._startBwd();
|
||||||
|
}, exposure + this._frame.closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dir) {
|
||||||
|
this._state.frame.cb = (len : number) => {
|
||||||
|
this._state.counter++;
|
||||||
|
this._storeState();
|
||||||
|
cb(len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._state.frame.cb = (len : number) => {
|
||||||
|
this._state.counter--;
|
||||||
|
this._storeState();
|
||||||
|
cb(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the state of the
|
||||||
|
*/
|
||||||
|
|
||||||
|
public status () {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Intval();
|
||||||
|
|
||||||
|
export default Intval;
|
|
@ -1,20 +1,30 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const uuid = require('uuid').v4
|
import uuid from 'uuid/v4';
|
||||||
const log = require('../log')('seq')
|
const log = require('../log')('seq');
|
||||||
import '../delay'
|
import '../delay';
|
||||||
|
|
||||||
|
const MAX_INTEGER = 2147483647;
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
len? : number;
|
||||||
|
}
|
||||||
|
|
||||||
/** Object sequence features */
|
/** Object sequence features */
|
||||||
class Sequence {
|
class Sequence {
|
||||||
public _state : any = {
|
public _state : any = {
|
||||||
arr : [],
|
arr : []
|
||||||
active : false,
|
|
||||||
paused : false,
|
|
||||||
frame: false,
|
|
||||||
delay : false,
|
|
||||||
count : 0,
|
|
||||||
stop : null
|
|
||||||
}
|
}
|
||||||
|
private id : string;
|
||||||
|
|
||||||
|
private active : boolean = false;
|
||||||
|
private paused : boolean = false;
|
||||||
|
|
||||||
|
private frame : boolean = false;
|
||||||
|
private delay : boolean = false;
|
||||||
|
private count : number = 0;
|
||||||
|
|
||||||
|
private _stop : Function = null;
|
||||||
|
|
||||||
public _loop : any = {
|
public _loop : any = {
|
||||||
arr : [],
|
arr : [],
|
||||||
|
@ -22,17 +32,20 @@ class Sequence {
|
||||||
max : 0
|
max : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor () {
|
constructor (intval : Intval) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
public start (options : any, cb : Function) {
|
* Start running a "sequence" of frames. Shoots a continuous sequence
|
||||||
|
* of single frames with a delay in between each one.
|
||||||
|
**/
|
||||||
|
public startOld (options : any, cb : Function) {
|
||||||
if (this._state.active) {
|
if (this._state.active) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
this._state.active = true
|
this.active = true
|
||||||
this._state.count = 0
|
this.count = 0
|
||||||
|
|
||||||
if (options.arr) {
|
if (options.arr) {
|
||||||
this._state.arr = options.arr
|
this._state.arr = options.arr
|
||||||
|
@ -48,70 +61,74 @@ class Sequence {
|
||||||
} else {
|
} else {
|
||||||
this._loop.max = 0
|
this._loop.max = 0
|
||||||
}
|
}
|
||||||
this._state.stop = cb
|
this._stop = cb
|
||||||
this.step()
|
this.step()
|
||||||
this._state.id = uuid()
|
this.id = uuid()
|
||||||
return this._state.id
|
return this.id
|
||||||
|
}
|
||||||
|
|
||||||
|
public async start (options : Options) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setStop () {
|
public setStop () {
|
||||||
this._state.active = false
|
this.active = false
|
||||||
}
|
}
|
||||||
|
|
||||||
public stop = function () {
|
public stop = function () {
|
||||||
this._state.active = false
|
this.active = false
|
||||||
this._state.count = 0
|
this.count = 0
|
||||||
this._state.arr = []
|
this._state.arr = []
|
||||||
|
|
||||||
this._loop.count = 0
|
this._loop.count = 0
|
||||||
this._loop.max = 0
|
this._loop.max = 0
|
||||||
this._loop.arr = []
|
this._loop.arr = []
|
||||||
|
|
||||||
if (this._state.stop) this._state.stop()
|
if (this._stop) this._stop()
|
||||||
|
|
||||||
this._state.stop = null
|
this._stop = null
|
||||||
}
|
}
|
||||||
|
|
||||||
public pause () {
|
public pause () {
|
||||||
this._state.paused = true
|
this.paused = true
|
||||||
}
|
}
|
||||||
|
|
||||||
public resume () {
|
public resume () {
|
||||||
this._state.paused = false
|
this.paused = false
|
||||||
this.step()
|
this.step()
|
||||||
}
|
}
|
||||||
|
|
||||||
public step () {
|
public step () {
|
||||||
if (this._state.active && !this._state.paused) {
|
if (this.active && !this.paused) {
|
||||||
if (this._state.arr.length > 0) {
|
if (this._state.arr.length > 0) {
|
||||||
if (this._state.count > this._state.arr.length - 1) {
|
if (this.count > this._state.arr.length - 1) {
|
||||||
return this.stop()
|
return this.stop()
|
||||||
}
|
}
|
||||||
log.info('step', { count : this._state.count, id : this._state.id })
|
log.info('step', { count : this.count, id : this._state.id })
|
||||||
return this._state.arr[this._state.count](() => {
|
return this._state.arr[this.count](() => {
|
||||||
this._state.count++
|
this.count++
|
||||||
this.step()
|
this.step()
|
||||||
})
|
})
|
||||||
} else if (this._loop.arr.length > 0) {
|
} else if (this._loop.arr.length > 0) {
|
||||||
if (this._state.count > this._loop.arr.length - 1) {
|
if (this.count > this._loop.arr.length - 1) {
|
||||||
this._state.count = 0
|
this.count = 0
|
||||||
this._loop.count++
|
this._loop.count++
|
||||||
}
|
}
|
||||||
if (this._loop.max > 0 && this._loop.count > this._loop.max) {
|
if (this._loop.max > 0 && this._loop.count > this._loop.max) {
|
||||||
return this.stop()
|
return this.stop()
|
||||||
}
|
}
|
||||||
log.info('step', { count : this._state.count, id : this._state.id })
|
log.info('step', { count : this.count, id : this.id })
|
||||||
return this._loop.arr[this._state.count](() => {
|
return this._loop.arr[this.count](() => {
|
||||||
this._state.count++
|
this.count++
|
||||||
this.step()
|
this.step()
|
||||||
})
|
})
|
||||||
} else{
|
} else{
|
||||||
return this.stop()
|
return this.stop()
|
||||||
}
|
}
|
||||||
} else if (this._state.paused) {
|
} else if (this.paused) {
|
||||||
log.info('step', 'Sequence paused', { loop : this._loop.count, count : this._state.count })
|
log.info('step', 'Sequence paused', { loop : this._loop.count, count : this.count })
|
||||||
} else if (!this._state.active) {
|
} else if (!this.active) {
|
||||||
log.info('step', 'Sequence stopped', { loop : this._loop.count, count : this._state.count })
|
log.info('step', 'Sequence stopped', { loop : this._loop.count, count : this.count })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"target": "ES2017",
|
"target": "ES2017",
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
|
"allowSyntheticDefaultImports" : true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments" : false,
|
"removeComments" : false,
|
||||||
|
|
Loading…
Reference in New Issue