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