From f953a790808ec8485c1d7c36c4065f611fb3eef6 Mon Sep 17 00:00:00 2001 From: mmcwilliams Date: Fri, 11 Oct 2019 17:57:07 -0400 Subject: [PATCH] Backup intval module, in case this whole thing goes awry. --- lib/intval/index.js.bak | 423 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 lib/intval/index.js.bak diff --git a/lib/intval/index.js.bak b/lib/intval/index.js.bak new file mode 100644 index 0000000..46718d0 --- /dev/null +++ b/lib/intval/index.js.bak @@ -0,0 +1,423 @@ +'use strict' + +const db = require('../db') +const log = require('../log')('intval') +const storage = require('node-persist') +const fs = require('fs') + +let Gpio +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' + } +} + +/** Object representing the intval3 features */ +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 \ No newline at end of file