From 7a19653c9d4f471dba8a79057338ef91d41ab3cb Mon Sep 17 00:00:00 2001 From: Jake <jake.read@cba.mit.edu> Date: Thu, 11 Oct 2018 14:51:26 -0400 Subject: [PATCH] couple of utilities --- README.md | 65 +++++++++---------------------------------- server.js | 36 ++++++++++++++++++------ src/motion/planner.js | 37 ++++++++++++++++++++++-- src/ui/button.js | 42 ++++++++++++++++++++++++++++ src/ui/multiline.js | 54 +++++++++++++++++++++++++++++++++++ src/ui/number.js | 53 +++++++++++++++++++++++++++++++++++ src/ui/panel.js | 43 ---------------------------- src/util/delay.js | 42 ++++++++++++++++++++++++++++ src/util/log.js | 38 +++++++++++++++++++++++++ 9 files changed, 304 insertions(+), 106 deletions(-) create mode 100644 src/ui/button.js create mode 100644 src/ui/multiline.js create mode 100644 src/ui/number.js delete mode 100644 src/ui/panel.js create mode 100644 src/util/delay.js create mode 100644 src/util/log.js diff --git a/README.md b/README.md index 9df449c..a660afa 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,12 @@ aka project consistent-sandbox ## oy + - num primatives, wrap to sys + - read file ? default lines ? run it + - then you have this multiline gcode / start / stop sequencing issue - and with it, scrolling around your messy program + - and this change ui / return double bounce ? - want jog keys & speed commands w/ those buttons - really want those LIGHTS - really want to watch accelerometer @@ -20,6 +24,9 @@ aka project consistent-sandbox - i.e. array access - consistent dereferencing ? +## UI bugs / + - reverse event lines ? .isLinked etc. .. + ## Features we Want - UI classes - buttons, w/ colors & reasonable std. events @@ -28,58 +35,12 @@ aka project consistent-sandbox - prettier hw/sw representation - callbacks / duplex links ? handing over an object, basically - reload-in-place - -~ for SFO, we do ~ - - machine eats gcode and runs it, and jogs, etc - - stretch to add rotary joint ... could concievably do this in the planner also - - *so* - - planner emits moves, steppers pick them out, reply with their axis ids, - - - - -- gcode -> planner -> stepper, loops back ? - - draft out event system architecture ... - - write gcode multiline inputs, would be cool to track current pos also - - try fancy txt edit library in UI, like how do we ready for three.js hooks ? -- modular / muxable axis movements - - i.e. 'back and forth button' UI elements -- gcode text block / path / file read-in - -- some styling - - state 'squishes' when module moved too far right - - state 'input' length / title length for long titles ? - -- state context menu or button - like 'fire this listener' on click, or get alt description, later edit, reload etc - -- bridge should be able to look for devices, test devices, and do terminal stuff - -- right-click on title of module, reload - -- for crashes etc, how can we re-start / kick serverside from the browser? some other daemon program ? - -- probably shouldn't send *all* of the state every time ... ? - - althought it's nice and foolproof - -- still want more diverse html inputs ... i.e. text input with some size to it ? gcode parser for this ... - -- write in logger functions - - i.e. module.log('whatever') is wrapped at load into console.log() and sends serverside log message as well, with ID and name - -- state variables good -- final steps before writing gcode consumption program - - nomenclature all over the place is spaget - - rewriting this is a good reintroduction to project - - cleaner replace ? wholistic replace ? - - classes / pretty code ? find desires by using - - any kind of save / load - - still with script-type writable file ? - - - but largely ready to write planner, serialport and packet parsing modules, do gcode stuff - -- server modules are ground truth -- to the client, we serve representations of these modules -- on the client, we keep a copy of this rep , and build a UI for it, ``rep.ui`` -- to interface, we push the rep json back and forth, mostly the rep.state object + - title context menu + - w/ proper event classes, context clicks for inputs / outputs / state elements ? + - for crashes etc, how can we re-start / kick serverside from the browser? some other daemon program ? + - write in logger functions + - i.e. module.log('whatever') is wrapped at load into console.log() and sends serverside log message as well, with ID and name + - this means writing module class that is extended ## remember diff --git a/server.js b/server.js index ba0a2fe..26b9283 100644 --- a/server.js +++ b/server.js @@ -113,18 +113,30 @@ var modules = new Array() // wrap require() up, appending path used to object, and giving ID // use the same to load from browser var term = addModule('./src/ui/terminal.js') +var multiline = addModule('./src/ui/multiline.js') +var button = addModule('./src/ui/button.js') +var numOut = addModule('./src/ui/number.js') +var delay = addModule('./src/util/delay.js') + var gcode = addModule('./src/parsing/gcode.js') var planner = addModule('./src/motion/planner.js') + var xm = addModule('./src/hardware/stepper.js') var yma = addModule('./src/hardware/stepper.js') var ymb = addModule('./src/hardware/stepper.js') var zm = addModule('./src/hardware/stepper.js') + var bridge = addModule('./src/hardware/bridge.js') // attaching an output to an input term.outputs.lineOut.attach(gcode.inputs.lineIn) gcode.outputs.instructionOut.attach(planner.inputs.instruction) +button.outputs.whammy.attach(numOut.inputs.thru) +numOut.outputs.out.attach(multiline.inputs.req) +button.outputs.whammy.attach(delay.inputs.thru) +delay.outputs.out.attach(planner.inputs.run) + // bi-directional hook planner / motor planner.outputs.moves.attach(xm.inputs.move) xm.outputs.ack.attach(planner.inputs.acks) @@ -154,16 +166,24 @@ bridge.init() // setting data w/r/t the representations they serve -setUiPos(term, 10, 10) -setUiPos(gcode, 50, 100) -setUiPos(planner, 100, 250) +setUiPos(multiline, 10, 10) + +setUiPos(gcode, 450, 10) +setUiPos(term, 450, 180) +setUiPos(button, 450, 300) +setUiPos(numOut, 450, 400) +setUiPos(delay, 450, 520) + +setUiPos(planner, 900, 10) + +var hwCol = 1350 -setUiPos(xm, 600, 20) -setUiPos(yma, 600, 260) -setUiPos(ymb, 600, 500) -setUiPos(zm, 600, 740) +setUiPos(xm, hwCol, 10) +setUiPos(yma, hwCol, 250) +setUiPos(ymb, hwCol, 490) +setUiPos(zm, hwCol, 730) -setUiPos(bridge, 600, 980) +setUiPos(bridge, hwCol, 970) // setting ui elements / state planner.state.isRunning = 0 diff --git a/src/motion/planner.js b/src/motion/planner.js index 85340b8..d02f8a6 100644 --- a/src/motion/planner.js +++ b/src/motion/planner.js @@ -30,6 +30,9 @@ function Planner() { state.jd = 1 // units to arc about state.minSpeed = 5 // units/s + state.startStop = Button('start / stop planner') + state.onChange('startStop', onStartStop) + state.position = [0, 0, 0] // should be grn / red button ... @@ -41,11 +44,13 @@ function Planner() { planner.inputs = { instruction: Input('move instruction', onNewInstruction), - acks: Input('move acknowledgement', onAck) + acks: Input('move acknowledgement', onAck), + run: Input('boolean', onRunInstruction) } planner.outputs = { - moves: Output('move instruction') + moves: Output('move instruction'), + moveComplete: Output('number') } /* @@ -72,6 +77,23 @@ function Planner() { } } + function onRunInstruction(boolean){ + if(boolean){ + if(state.isRunning){ + // already running, do nothing + } else { + state.isRunning = 1 + netStateRefresh() + } + } else { + if(state.isRunning){ + state.isRunning = 0 + } else { + // oy + } + } + } + function axisIDUpdate() { var axes = state.axisIDs.split(',') var position = new Array(axes.length) @@ -89,7 +111,16 @@ function Planner() { } function onPlannerReset() { - console.log("RESET PLANNER") + console.log("RESET PLANNER NOT YET IMPLEMENTED") + } + + function onStartStop() { + if(state.isRunning){ + state.isRunning = 0 + } else { + state.isRunning = 1 + netStateRefresh() + } } function netStateRefresh() { diff --git a/src/ui/button.js b/src/ui/button.js new file mode 100644 index 0000000..86257b4 --- /dev/null +++ b/src/ui/button.js @@ -0,0 +1,42 @@ +// boilerplate atkapi header +const InOut = require('../../lib/inout.js') +let Input = InOut.Input +let Output = InOut.Output +let State = InOut.State +let Button = InOut.Button + +// a constructor, a fn, a javascript mess +function uiButton() { + + var button = { + // descriptions are used in UI + description: { + name: 'Button!', + alt: 'for clicking' + } + } + + button.state = State() + // alias ! + var state = button.state + + state.button = Button('WHAM') + state.onChange('button', onButtonPress) + + button.inputs = { + thru: Input('any', onButtonPress) // makes anything into '1' event + } + + button.outputs = { + whammy: Output('number') + } + + function onButtonPress(evt){ + button.outputs.whammy.emit(1) + } + + return button +} + +// exports +module.exports = uiButton \ No newline at end of file diff --git a/src/ui/multiline.js b/src/ui/multiline.js new file mode 100644 index 0000000..91897b7 --- /dev/null +++ b/src/ui/multiline.js @@ -0,0 +1,54 @@ +// boilerplate atkapi header +const InOut = require('../../lib/inout.js') +let Input = InOut.Input +let Output = InOut.Output +let State = InOut.State + +// a constructor, a fn, a javascript mess +function MultiLineIn() { + + var multilinein = { + // descriptions are used in UI + description: { + name: 'Multi-line Text Input', + alt: 'sequential txt input' + } + } + + multilinein.state = State() + // alias ! + var state = multilinein.state + + state.previously = 'lines complete' // = Multiline(rows) + state.now = 'line just out' + state.incoming = 'future lines' + + multilinein.inputs = { + req: Input('number', onLineRequest), + lineIn: Input('string', onExternalLine), + load: Input('path', onLoadFile) + } + + multilinein.outputs = { + lineOut: Output('string') + } + + // internal funcs? + + function onLineRequest(num){ + // #num of lines to push out + } + + function onExternalLine(str){ + // push new str to bottom of queue + } + + function onLoadFile(path){ + // reset, git big string from file + } + + return multilinein +} + +// exports +module.exports = MultiLineIn \ No newline at end of file diff --git a/src/ui/number.js b/src/ui/number.js new file mode 100644 index 0000000..cbcd509 --- /dev/null +++ b/src/ui/number.js @@ -0,0 +1,53 @@ +// boilerplate atkapi header +const InOut = require('../../lib/inout.js') +let Input = InOut.Input +let Output = InOut.Output +let State = InOut.State +let Button = InOut.Button + +// a constructor, a fn, a javascript mess +function uiNum() { + + var uinum = { + // descriptions are used in UI + description: { + name: 'number output!', + alt: 'for clicking' + } + } + + uinum.state = State() + // alias ! + var state = uinum.state + + state.number = 16 + + state.button = Button('WHAM') + state.onChange('button', onNumberDesire) + + uinum.inputs = { + thru: Input('any', onNumberDesire) // makes anything into num event + } + + uinum.outputs = { + out: Output('number') + } + + function onNumberInput(input){ + if(typeof input == 'number'){ + state.number = input + } else { + state.number = parseFloat(input) + } + onNumberDesire() + } + + function onNumberDesire(){ + uinum.outputs.out.emit(state.number) + } + + return uinum +} + +// exports +module.exports = uiNum \ No newline at end of file diff --git a/src/ui/panel.js b/src/ui/panel.js deleted file mode 100644 index 99f080f..0000000 --- a/src/ui/panel.js +++ /dev/null @@ -1,43 +0,0 @@ -// boilerplate atkapi header -const InOut = require('../../lib/inout.js') -let Input = InOut.Input -let Output = InOut.Output - -// bonus reqs -const readline = require('readline') - -// a constructor, a fn, a javascript mess -function Panel(){ - - // object state - this.state = { - width: 64, - height: 48 - } - - // natural inputs / local functions - var rlInterface = readline.createInterface({ - input: process.stdin, - output: process.stdout - }) - - rlInterface.on('line', (data) => { - this.outputs.lineOut.emit(data) - }) - - var post = (str) => { - console.log(str) - } - - // ins and outs - this.inputs = { - lineIn: new Input('line input', 'string', post) - } - - this.outputs = { - lineOut: new Output('line output', 'string') - } -} - -// exports -module.exports = Panel \ No newline at end of file diff --git a/src/util/delay.js b/src/util/delay.js new file mode 100644 index 0000000..1d19c01 --- /dev/null +++ b/src/util/delay.js @@ -0,0 +1,42 @@ +// boilerplate atkapi header +const InOut = require('../../lib/inout.js') +let Input = InOut.Input +let Output = InOut.Output +let State = InOut.State + +// a constructor, a fn, a javascript mess +function Delay() { + + var delay = { + // descriptions are used in UI + description: { + name: 'delay!', + alt: 'in ... out' + } + } + + delay.state = State() + // alias ! + var state = delay.state + + state.ms = 100 + + delay.inputs = { + thru: Input('any', onDelayBegin) // makes anything into '1' event + } + + delay.outputs = { + out: Output('any') + } + + function onDelayBegin(input){ + setTimeout(function(){ + delay.outputs.out.emit(input) + }, state.ms) + } + + return delay +} + +// exports +module.exports = Delay \ No newline at end of file diff --git a/src/util/log.js b/src/util/log.js new file mode 100644 index 0000000..60403c4 --- /dev/null +++ b/src/util/log.js @@ -0,0 +1,38 @@ +// boilerplate atkapi header +const InOut = require('../../lib/inout.js') +let Input = InOut.Input +let Output = InOut.Output +let State = InOut.State + +// a constructor, a fn, a javascript mess +function Logger() { + + var logger = { + // descriptions are used in UI + description: { + name: 'logger!', + alt: 'in ... out to console' + } + } + + logger.state = State() + // alias ! + var state = logger.state + + state.prefix = 'LOGGER:' + state.message = '---' + + logger.inputs = { + thru: Input('any', onInput) // makes anything into '1' event + } + + function onInput(input){ + state.message = input.toString() + console.log(state.prefix, input) + } + + return logger +} + +// exports +module.exports = Logger \ No newline at end of file -- GitLab