From 45dc48cfc57ef2dcd653221b8ee48307729e322c Mon Sep 17 00:00:00 2001
From: Jake Read <jake.read@cba.mit.edu>
Date: Thu, 15 Nov 2018 13:04:37 -0500
Subject: [PATCH] rm bug for routes not attaching on program load

---
 README.md                         |  12 +-
 client/client.js                  |   2 +-
 client/divtools.js                |   5 +-
 client/index.html                 |   2 +-
 lib/atkunit.js                    |   2 +-
 main.js                           |   2 +-
 modules/hardware/atkseriallink.js |   8 +-
 modules/parsing/gcode.js          |   4 +-
 modules/ui/button.js              |   5 +-
 modules/ui/number.js              |   2 +-
 package.json                      |   2 +-
 programs.js                       |  49 ++-
 programs/hwtest-2.json            | 573 +++++++++++++++++++++++++++++
 programs/hwtest.json              | 308 ++++++++++++++++
 programs/hwtst-3.json             | 590 ++++++++++++++++++++++++++++++
 views.js                          |   2 +-
 16 files changed, 1530 insertions(+), 38 deletions(-)
 create mode 100644 programs/hwtest-2.json
 create mode 100644 programs/hwtest.json
 create mode 100644 programs/hwtst-3.json

diff --git a/README.md b/README.md
index 6f8389e..98ce70b 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@ It's in the early stages, so bear with us. Everything is going to be great.
 
 To Run DMC, you'll need to install node.js, and then the packages serialport and ws (websocket).
 
+
+
 ### Install Node.js
 
 Node.js is a runtime environment for javascript, so you can write and run js locally. [Download and install it here](https://nodejs.org/en/download/). 
@@ -110,9 +112,15 @@ Herein will contain a list of known problems / common errors and their fixes.
 
 ## For MW
 
+ - bug hunting
+  - dereferenced events / stepper axis vector 
+  - multiple button calls ... 
+  - stepper / planner bug 
+  - is load / save really consistent ? what is the state answer ? 
+
 - title is still 'xperiment'
-- do hw if you can, and gifs / demo at the same time?
-- some example program 
+- stepper move.vector is a ref issue? derefed before running calcTrap() ? runs ? in planner ? 
+
 - example modules 
 
 - add reset button to hardware
diff --git a/client/client.js b/client/client.js
index e5e3416..7932d80 100644
--- a/client/client.js
+++ b/client/client.js
@@ -342,7 +342,7 @@ function redrawLinks() {
         if (mdlRep.description.isHardware && !mdlRep.description.isLink) {
             nLnk++
             var hwPt = getRightWall(mdlRep.ui.domElem)
-            lnkPt.y += 10 * nLnk
+            lnkPt.y += 5 * nLnk
             var ln = newLine(hwPt.x, hwPt.y, lnkPt.x, lnkPt.y)
         }
     }
diff --git a/client/divtools.js b/client/divtools.js
index a931512..ba16c01 100644
--- a/client/divtools.js
+++ b/client/divtools.js
@@ -301,9 +301,10 @@ function getInputArrow(div) {
 function newLine(x1, y1, x2, y2) {
     var ln = {}
     ln.elem = document.createElementNS(svgns, 'line')
-    ln.elem.style.stroke = '#fcd17b'
+    ln.elem.style.stroke = '#1a1a1a'
+    ln.elem.setAttribute('stroke-dasharray', '21, 7, 7, 7')
     ln.elem.style.fill = 'none'
-    ln.elem.style.strokeWidth = '7px'
+    ln.elem.style.strokeWidth = '6px'
     ln.x1 = x1
     ln.y1 = y1
     ln.x2 = x2
diff --git a/client/index.html b/client/index.html
index 5008fd7..7ee3bec 100644
--- a/client/index.html
+++ b/client/index.html
@@ -2,7 +2,7 @@
 <html>
 
 <head>
-    <title>xperiment</title>
+    <title>RuNDMC</title>
 </head>
 
 <body>
diff --git a/lib/atkunit.js b/lib/atkunit.js
index 72c02ad..08e7f12 100644
--- a/lib/atkunit.js
+++ b/lib/atkunit.js
@@ -7,7 +7,7 @@ let Output = InOut.Output
 let State = InOut.State
 let Button = InOut.Button
 
-const ATKRoute = require('./atkroute.js')
+let ATKRoute = require('./atkroute.js')
 
 function Hardware(){
 	var hardware = {
diff --git a/main.js b/main.js
index 8570552..4bf4342 100644
--- a/main.js
+++ b/main.js
@@ -29,7 +29,7 @@ const Programs = require('./programs.js')
 
 var program = Programs.new('new program')
 
-var step = Programs.loadModuleFromSource(program, './modules/hardware/atkstepper.js')
+// var step = Programs.loadModuleFromSource(program, './modules/hardware/atkstepper.js')
 
 // UI 
 const View = require('./views.js')
diff --git a/modules/hardware/atkseriallink.js b/modules/hardware/atkseriallink.js
index 4655d35..207dc86 100644
--- a/modules/hardware/atkseriallink.js
+++ b/modules/hardware/atkseriallink.js
@@ -19,8 +19,8 @@ function ATKSerialLink() {
         routes: new Array()
     }
 
-    var state = State()
-    atkSerialLink.state = state
+    atkSerialLink.state = State()
+    var state = atkSerialLink.state 
 
     state.portName = '---'
     state.connect = Button('click to find and connect', findSerialPort)
@@ -61,7 +61,7 @@ function ATKSerialLink() {
             })
         })
         if(!found){
-            console.log('no CP2102 device found, try serialport-list to make sure it is available to the system')
+            console.log('LINK ERR: no CP2102 device found, try serialport-list to make sure it is available to the system')
             state.portStatus = 'no CP2102 device found'
         }
     }
@@ -110,7 +110,7 @@ function ATKSerialLink() {
                 if (writeToSerialPort(pckt)) {
                     console.log('PCKT OOT >>', pckt.toString())
                 } else {
-                    console.log('ERR: attempt to send to hardware, port not writable')
+                    console.log('LINK ERR: attempt to send to hardware, port not writable')
                 }
             }
         } else {
diff --git a/modules/parsing/gcode.js b/modules/parsing/gcode.js
index e848509..ae2ecb8 100644
--- a/modules/parsing/gcode.js
+++ b/modules/parsing/gcode.js
@@ -36,8 +36,8 @@ function Gcode() {
             console.log('GCODE:', instruction)
             gcode.outputs.instructionOut.emit(instruction)
         } else {
-            console.log('GCODE:', gcode.ui.mode)
-            gcode.outputs.modeChange.emit(gcode.ui.mode)
+            console.log('GCODE:', gcode.state.mode)
+            gcode.outputs.modeChange.emit(gcode.state.mode)
         }
     }
 
diff --git a/modules/ui/button.js b/modules/ui/button.js
index 48c7b6a..d8435aa 100644
--- a/modules/ui/button.js
+++ b/modules/ui/button.js
@@ -11,7 +11,7 @@ function uiButton() {
     var button = {
         // descriptions are used in UI
         description: {
-            name: 'Button!',
+            name: 'Button',
             alt: 'for clicking'
         }
     }
@@ -20,8 +20,7 @@ function uiButton() {
     // alias !
     var state = button.state 
 
-    state.button = Button('WHAM')
-    state.onChange('button', onButtonPress)
+    state.button = Button('WHAM', onButtonPress)
 
     button.inputs = {
         thru: Input('any', onButtonPress) // makes anything into '1' event
diff --git a/modules/ui/number.js b/modules/ui/number.js
index 8e827e8..467d231 100644
--- a/modules/ui/number.js
+++ b/modules/ui/number.js
@@ -11,7 +11,7 @@ function uiNum() {
     var uinum = {
         // descriptions are used in UI
         description: {
-            name: 'number output!',
+            name: 'number output',
             alt: 'for clicking'
         }
     }
diff --git a/package.json b/package.json
index 8501b57..5b90e9f 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
   "dependencies": {
     "express": "^4.16.3",
     "http": "0.0.0",
-    "mathjs": "^5.1.2",
+    "mathjs": "^5.2.3",
     "node-webcam": "^0.4.5",
     "readline": "^1.3.0",
     "serialport": "^6.2.2",
diff --git a/programs.js b/programs.js
index 35c238f..8f0f80d 100644
--- a/programs.js
+++ b/programs.js
@@ -30,7 +30,7 @@ function loadModuleFromSource(program, path, id) {
             program.description.counter++
         }
 
-        // make unique name 
+        // make unique name, or recall from program save 
         if (id) {
             mod.description.id = id
         } else {
@@ -38,22 +38,22 @@ function loadModuleFromSource(program, path, id) {
         }
         mod.description.path = path
 
+        // add to program object 
+        program.modules[mod.description.id] = mod
+
         /* ---------------------------------- */
         // WARN! Corner Case should Go Away or Improve at next spiral 
-        if(mod.description.isLink){
+        if (mod.description.isLink) {
             for (mdlName in program.modules) {
                 if (program.modules[mdlName].description.isLink) {
                     console.log("PRGMEM ONLY BIG ENOUGH FOR ONE LINK")
-                    process.exit()
+                    //process.exit()
                 }
             }
         }
         // end corner case code 
         /* ---------------------------------- */
 
-        // add to program object 
-        program.modules[mod.description.id] = mod
-
         // input need references for later hookup
         for (key in mod.inputs) {
             mod.inputs[key].parentId = mod.description.id
@@ -89,9 +89,9 @@ function loadModuleFromSource(program, path, id) {
         // here's what we'll do
         // if it's hardware, and we're not loading from some saved program (no id)
         // 
-        if (mod.description.isHardware && !mod.description.isLink && id == null) {
+        if (mod.description.isHardware && !mod.description.isLink /* && id == null */ ) {
             // make sure we haven't already done this, thx 
-            var lnk = null 
+            var lnk = null
             for (mdlName in program.modules) {
                 if (program.modules[mdlName].description.isLink) {
                     lnk = mdlName
@@ -120,7 +120,7 @@ function writeStateObject(mod, key) {
         set: function(x) {
             // update internal value 
             this['_' + key] = x
-            //console.log('SET', key, this['_' + key])
+            // console.log('SET', key, this['_' + key])
             // push to internal state change handler
             // let's call emitChange from the server-side ...
             // so that we don't get into any heavy VIR
@@ -229,7 +229,7 @@ function openProgram(path) {
         var mdl = program.modules[modName]
 
         if (mdl == null) {
-            console.log('NULL')
+            console.log('-------------------------------- NULL MDL at openProgram')
             console.log('prgRep modules', prgRep.modules)
             console.log('program modules', program.modules)
         }
@@ -249,17 +249,30 @@ function openProgram(path) {
         }
 
         // restoring state 
-        for (key in mdlRep.state) {
-            if (isStateKey(key)) {
-                // I think this is OK?
-                // would prefer to do this before we write getters and setters
-                // for now we walk-around to secret key ... 
-                mdl.state['_' + key] = mdlRep.state[key]
+        /* the first wrap, only here to prevent link not-reconnecting on program restart, should go away */
+        if (!mdlRep.description.isLink) {
+            for (key in mdlRep.state) {
+                if (isStateKey(key)) {
+                    // I think this is OK?
+                    // would prefer to do this before we write getters and setters
+                    // for now we walk-around to secret key ... 
+                    if (mdl.state[key].type == 'button' || mdl.state[key].type == 'multiline') {
+                        // defaul vals
+                    } else if (key == 'route'){
+                        // absolutely does not belong here 
+                        // TODO: states: sometimes we load, we want to run the change emitter ... sometimes we don't
+                        // what choice ? 
+                        mdl.state['_' + key] = mdlRep.state[key]
+                        mdl.state.emitChange('route')
+                    } else {
+                        mdl.state['_' + key] = mdlRep.state[key]
+                    }
+                }
             }
         }
 
-        console.log('mdlRep', mdlRep)
-        console.log('mdl', mdl)
+        //console.log('mdlRep', mdlRep)
+        //console.log('mdl', mdl)
         // restore position / UI state
         if (mdlRep.description.position != null) {
             // ??
diff --git a/programs/hwtest-2.json b/programs/hwtest-2.json
new file mode 100644
index 0000000..0886e2e
--- /dev/null
+++ b/programs/hwtest-2.json
@@ -0,0 +1,573 @@
+{
+  "description": {
+    "name": "new program",
+    "counter": 12
+  },
+  "modules": {
+    "Serialport ATK Link-1": {
+      "description": {
+        "id": "Serialport ATK Link-1",
+        "name": "Serialport ATK Link",
+        "alt": "window into hardware world",
+        "path": "./modules/hardware/atkseriallink.js",
+        "isHardware": true,
+        "isLink": true,
+        "position": {
+          "left": 968,
+          "top": 347
+        }
+      },
+      "inputs": {},
+      "outputs": {},
+      "state": {
+        "portName": "COM10",
+        "connect": {
+          "type": "button",
+          "label": "click to find and connect"
+        },
+        "portStatus": "open"
+      }
+    },
+    "ATKStepper-0": {
+      "description": {
+        "id": "ATKStepper-0",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,3",
+        "rate": 2000,
+        "axis": "X",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-2": {
+      "description": {
+        "id": "ATKStepper-2",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 456,
+          "top": 491
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,0",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": -200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-3": {
+      "description": {
+        "id": "ATKStepper-3",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 883
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,5",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-4": {
+      "description": {
+        "id": "ATKStepper-4",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 459,
+          "top": 1274
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test packet out",
+        "route": "0,1",
+        "rate": 2000,
+        "axis": "Z",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": -2000,
+        "position": 0
+      }
+    },
+    "ATKBBB-Servo-5": {
+      "description": {
+        "id": "ATKBBB-Servo-5",
+        "name": "ATKBBB-Servo",
+        "alt": "software representation of networked hardware object",
+        "path": "./modules/hardware/atkbreadboard.js",
+        "isHardware": true,
+        "position": {
+          "left": 891,
+          "top": 1354
+        }
+      },
+      "inputs": {
+        "servoVal": {
+          "accepts": "number"
+        },
+        "adcRequest": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "servoConf": {
+          "emits": "event",
+          "calls": []
+        },
+        "adcValue": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,2",
+        "servoButton": {
+          "type": "button",
+          "label": "SEND VALUE"
+        },
+        "servoVal": 0,
+        "adcButton": {
+          "type": "button",
+          "label": "REQUEST ADC CONVERSION"
+        }
+      }
+    },
+    "Button-7": {
+      "description": {
+        "id": "Button-7",
+        "name": "Button",
+        "alt": "for clicking",
+        "path": "./modules/ui/button.js",
+        "position": {
+          "left": -544,
+          "top": 337
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "whammy": {
+          "emits": "number",
+          "calls": [
+            {
+              "parentId": "delay-9",
+              "key": "thru"
+            },
+            {
+              "parentId": "number output-8",
+              "key": "evt"
+            }
+          ]
+        }
+      },
+      "state": {
+        "button": {
+          "type": "button",
+          "label": "WHAM"
+        }
+      }
+    },
+    "number output-8": {
+      "description": {
+        "id": "number output-8",
+        "name": "number output",
+        "alt": "for clicking",
+        "path": "./modules/ui/number.js",
+        "position": {
+          "left": -545,
+          "top": 605
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        },
+        "evt": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "out": {
+          "emits": "number",
+          "calls": [
+            {
+              "parentId": "Multi-line Text Input-12",
+              "key": "req"
+            }
+          ]
+        }
+      },
+      "state": {
+        "number": 10,
+        "button": {
+          "type": "button",
+          "label": "WHAM"
+        }
+      }
+    },
+    "delay-9": {
+      "description": {
+        "id": "delay-9",
+        "name": "delay",
+        "alt": "in ... out",
+        "path": "./modules/util/delay.js",
+        "position": {
+          "left": -546,
+          "top": 499
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "out": {
+          "emits": "any",
+          "calls": [
+            {
+              "parentId": "Lookahead-Motion-Planner-10",
+              "key": "run"
+            }
+          ]
+        }
+      },
+      "state": {
+        "ms": 100
+      }
+    },
+    "Lookahead-Motion-Planner-10": {
+      "description": {
+        "id": "Lookahead-Motion-Planner-10",
+        "name": "Lookahead-Motion-Planner",
+        "alt": "movements -> acceleration planned moves",
+        "path": "./modules/motion/planner.js",
+        "position": {
+          "left": -31,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "instruction": {
+          "accepts": "move instruction"
+        },
+        "acks": {
+          "accepts": "move acknowledgement"
+        },
+        "run": {
+          "accepts": "boolean"
+        }
+      },
+      "outputs": {
+        "moves": {
+          "emits": "move instruction",
+          "calls": []
+        },
+        "moveComplete": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "axisIDs": "X,Y,Z",
+        "reset": {
+          "type": "button",
+          "label": "reset planner"
+        },
+        "accel": 200,
+        "jd": 0.1,
+        "minSpeed": 1,
+        "startStop": {
+          "type": "button",
+          "label": "start / stop planner"
+        },
+        "position": [
+          0,
+          0,
+          0
+        ],
+        "isRunning": 1,
+        "netWindow": 3,
+        "netState": [
+          0,
+          0,
+          0
+        ]
+      }
+    },
+    "Gcode Parser-11": {
+      "description": {
+        "id": "Gcode Parser-11",
+        "name": "Gcode Parser",
+        "alt": "line of gcode -> planner recognized move",
+        "path": "./modules/parsing/gcode.js",
+        "position": {
+          "left": -556,
+          "top": 83
+        }
+      },
+      "inputs": {
+        "lineIn": {
+          "accepts": "string"
+        }
+      },
+      "outputs": {
+        "instructionOut": {
+          "emits": "move instruction",
+          "calls": [
+            {
+              "parentId": "Lookahead-Motion-Planner-10",
+              "key": "instruction"
+            }
+          ]
+        },
+        "modeChange": {
+          "emits": "string",
+          "calls": []
+        }
+      },
+      "state": {
+        "mode": "G0",
+        "G0": 1200,
+        "G1": 400
+      }
+    },
+    "Multi-line Text Input-12": {
+      "description": {
+        "id": "Multi-line Text Input-12",
+        "name": "Multi-line Text Input",
+        "alt": "sequential txt input",
+        "path": "./modules/ui/multiline.js",
+        "position": {
+          "left": -1117,
+          "top": 89
+        }
+      },
+      "inputs": {
+        "req": {
+          "accepts": "number"
+        },
+        "lineIn": {
+          "accepts": "string"
+        },
+        "load": {
+          "accepts": "path"
+        }
+      },
+      "outputs": {
+        "lineOut": {
+          "emits": "string",
+          "calls": [
+            {
+              "parentId": "Gcode Parser-11",
+              "key": "lineIn"
+            }
+          ]
+        }
+      },
+      "state": {
+        "load": {
+          "type": "button",
+          "label": "LOAD"
+        },
+        "thru": {
+          "type": "button",
+          "label": "WHAM"
+        },
+        "previously": {
+          "type": "multiline",
+          "label": "lines complete",
+          "rows": 11,
+          "value": ""
+        },
+        "now": {
+          "type": "multiline",
+          "label": "line just out",
+          "rows": 1,
+          "value": ""
+        },
+        "incoming": {
+          "type": "multiline",
+          "label": "future lines",
+          "rows": 36,
+          "value": "G0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\n"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/programs/hwtest.json b/programs/hwtest.json
new file mode 100644
index 0000000..7ccaf45
--- /dev/null
+++ b/programs/hwtest.json
@@ -0,0 +1,308 @@
+{
+  "description": {
+    "name": "new program",
+    "counter": 5
+  },
+  "modules": {
+    "Serialport ATK Link-1": {
+      "description": {
+        "id": "Serialport ATK Link-1",
+        "name": "Serialport ATK Link",
+        "alt": "window into hardware world",
+        "path": "./modules/hardware/atkseriallink.js",
+        "isHardware": true,
+        "isLink": true,
+        "position": {
+          "left": 968,
+          "top": 347
+        }
+      },
+      "inputs": {},
+      "outputs": {},
+      "state": {
+        "portName": "COM10",
+        "connect": {
+          "type": "button",
+          "label": "click to find and connect"
+        },
+        "portStatus": "open"
+      }
+    },
+    "ATKStepper-0": {
+      "description": {
+        "id": "ATKStepper-0",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,3",
+        "rate": 2000,
+        "axis": "X",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-2": {
+      "description": {
+        "id": "ATKStepper-2",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 456,
+          "top": 491
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,0",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": -200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-3": {
+      "description": {
+        "id": "ATKStepper-3",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 883
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,5",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-4": {
+      "description": {
+        "id": "ATKStepper-4",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 459,
+          "top": 1274
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test packet out",
+        "route": "0,1",
+        "rate": 2000,
+        "axis": "Z",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": -2000,
+        "position": 0
+      }
+    },
+    "ATKBBB-Servo-5": {
+      "description": {
+        "id": "ATKBBB-Servo-5",
+        "name": "ATKBBB-Servo",
+        "alt": "software representation of networked hardware object",
+        "path": "./modules/hardware/atkbreadboard.js",
+        "isHardware": true,
+        "position": {
+          "left": 891,
+          "top": 1354
+        }
+      },
+      "inputs": {
+        "servoVal": {
+          "accepts": "number"
+        },
+        "adcRequest": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "servoConf": {
+          "emits": "event",
+          "calls": []
+        },
+        "adcValue": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,2",
+        "servoButton": {
+          "type": "button",
+          "label": "SEND VALUE"
+        },
+        "servoVal": 0,
+        "adcButton": {
+          "type": "button",
+          "label": "REQUEST ADC CONVERSION"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/programs/hwtst-3.json b/programs/hwtst-3.json
new file mode 100644
index 0000000..d0adf2a
--- /dev/null
+++ b/programs/hwtst-3.json
@@ -0,0 +1,590 @@
+{
+  "description": {
+    "name": "new program",
+    "counter": 12
+  },
+  "modules": {
+    "Serialport ATK Link-1": {
+      "description": {
+        "id": "Serialport ATK Link-1",
+        "name": "Serialport ATK Link",
+        "alt": "window into hardware world",
+        "path": "./modules/hardware/atkseriallink.js",
+        "isHardware": true,
+        "isLink": true,
+        "position": {
+          "left": 968,
+          "top": 347
+        }
+      },
+      "inputs": {},
+      "outputs": {},
+      "state": {
+        "portName": "COM10",
+        "connect": {
+          "type": "button",
+          "label": "click to find and connect"
+        },
+        "portStatus": "open"
+      }
+    },
+    "ATKStepper-0": {
+      "description": {
+        "id": "ATKStepper-0",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,3",
+        "rate": 2000,
+        "axis": "X",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-2": {
+      "description": {
+        "id": "ATKStepper-2",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 456,
+          "top": 491
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,0",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": -200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-3": {
+      "description": {
+        "id": "ATKStepper-3",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 457,
+          "top": 883
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,5",
+        "rate": 2000,
+        "axis": "Y",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": 0,
+        "position": 0
+      }
+    },
+    "ATKStepper-4": {
+      "description": {
+        "id": "ATKStepper-4",
+        "name": "ATKStepper",
+        "alt": "software representation of stepper motor",
+        "path": "./modules/hardware/atkstepper.js",
+        "isHardware": true,
+        "position": {
+          "left": 459,
+          "top": 1274
+        }
+      },
+      "inputs": {
+        "trapezoid": {
+          "accepts": "move instruction"
+        },
+        "accel": {
+          "accepts": "number"
+        },
+        "rmtrig": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "ack": {
+          "emits": "move acknowledgement",
+          "calls": []
+        },
+        "position": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test packet out",
+        "route": "0,1",
+        "rate": 2000,
+        "axis": "Z",
+        "spu": 200,
+        "rawMove": -10,
+        "makeMove": {
+          "type": "button",
+          "label": "test move"
+        },
+        "lead": -2000,
+        "position": 0
+      }
+    },
+    "ATKBBB-Servo-5": {
+      "description": {
+        "id": "ATKBBB-Servo-5",
+        "name": "ATKBBB-Servo",
+        "alt": "software representation of networked hardware object",
+        "path": "./modules/hardware/atkbreadboard.js",
+        "isHardware": true,
+        "position": {
+          "left": 891,
+          "top": 1354
+        }
+      },
+      "inputs": {
+        "servoVal": {
+          "accepts": "number"
+        },
+        "adcRequest": {
+          "accepts": "event"
+        }
+      },
+      "outputs": {
+        "servoConf": {
+          "emits": "event",
+          "calls": []
+        },
+        "adcValue": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "reset": {
+          "type": "button",
+          "label": "reset hardware"
+        },
+        "test": {
+          "type": "button",
+          "label": "test network"
+        },
+        "message": "test OK",
+        "route": "0,2",
+        "servoButton": {
+          "type": "button",
+          "label": "SEND VALUE"
+        },
+        "servoVal": 0,
+        "adcButton": {
+          "type": "button",
+          "label": "REQUEST ADC CONVERSION"
+        }
+      }
+    },
+    "Button-7": {
+      "description": {
+        "id": "Button-7",
+        "name": "Button",
+        "alt": "for clicking",
+        "path": "./modules/ui/button.js",
+        "position": {
+          "left": -544,
+          "top": 337
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "whammy": {
+          "emits": "number",
+          "calls": [
+            {
+              "parentId": "delay-9",
+              "key": "thru"
+            },
+            {
+              "parentId": "number output-8",
+              "key": "evt"
+            }
+          ]
+        }
+      },
+      "state": {
+        "button": {
+          "type": "button",
+          "label": "WHAM"
+        }
+      }
+    },
+    "number output-8": {
+      "description": {
+        "id": "number output-8",
+        "name": "number output",
+        "alt": "for clicking",
+        "path": "./modules/ui/number.js",
+        "position": {
+          "left": -545,
+          "top": 605
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        },
+        "evt": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "out": {
+          "emits": "number",
+          "calls": [
+            {
+              "parentId": "Multi-line Text Input-12",
+              "key": "req"
+            }
+          ]
+        }
+      },
+      "state": {
+        "number": 10,
+        "button": {
+          "type": "button",
+          "label": "WHAM"
+        }
+      }
+    },
+    "delay-9": {
+      "description": {
+        "id": "delay-9",
+        "name": "delay",
+        "alt": "in ... out",
+        "path": "./modules/util/delay.js",
+        "position": {
+          "left": -546,
+          "top": 499
+        }
+      },
+      "inputs": {
+        "thru": {
+          "accepts": "any"
+        }
+      },
+      "outputs": {
+        "out": {
+          "emits": "any",
+          "calls": [
+            {
+              "parentId": "Lookahead-Motion-Planner-10",
+              "key": "run"
+            }
+          ]
+        }
+      },
+      "state": {
+        "ms": 100
+      }
+    },
+    "Lookahead-Motion-Planner-10": {
+      "description": {
+        "id": "Lookahead-Motion-Planner-10",
+        "name": "Lookahead-Motion-Planner",
+        "alt": "movements -> acceleration planned moves",
+        "path": "./modules/motion/planner.js",
+        "position": {
+          "left": -31,
+          "top": 91
+        }
+      },
+      "inputs": {
+        "instruction": {
+          "accepts": "move instruction"
+        },
+        "acks": {
+          "accepts": "move acknowledgement"
+        },
+        "run": {
+          "accepts": "boolean"
+        }
+      },
+      "outputs": {
+        "moves": {
+          "emits": "move instruction",
+          "calls": [
+            {
+              "parentId": "ATKStepper-0",
+              "key": "trapezoid"
+            },
+            {
+              "parentId": "ATKStepper-2",
+              "key": "trapezoid"
+            },
+            {
+              "parentId": "ATKStepper-3",
+              "key": "trapezoid"
+            },
+            {
+              "parentId": "ATKStepper-4",
+              "key": "trapezoid"
+            }
+          ]
+        },
+        "moveComplete": {
+          "emits": "number",
+          "calls": []
+        }
+      },
+      "state": {
+        "axisIDs": "X,Y,Z",
+        "reset": {
+          "type": "button",
+          "label": "reset planner"
+        },
+        "accel": 200,
+        "jd": 0.1,
+        "minSpeed": 1,
+        "startStop": {
+          "type": "button",
+          "label": "start / stop planner"
+        },
+        "position": [
+          0,
+          0,
+          0
+        ],
+        "isRunning": 1,
+        "netWindow": 3,
+        "netState": [
+          0,
+          0,
+          0
+        ]
+      }
+    },
+    "Gcode Parser-11": {
+      "description": {
+        "id": "Gcode Parser-11",
+        "name": "Gcode Parser",
+        "alt": "line of gcode -> planner recognized move",
+        "path": "./modules/parsing/gcode.js",
+        "position": {
+          "left": -556,
+          "top": 83
+        }
+      },
+      "inputs": {
+        "lineIn": {
+          "accepts": "string"
+        }
+      },
+      "outputs": {
+        "instructionOut": {
+          "emits": "move instruction",
+          "calls": [
+            {
+              "parentId": "Lookahead-Motion-Planner-10",
+              "key": "instruction"
+            }
+          ]
+        },
+        "modeChange": {
+          "emits": "string",
+          "calls": []
+        }
+      },
+      "state": {
+        "mode": "G0",
+        "G0": 1200,
+        "G1": 400
+      }
+    },
+    "Multi-line Text Input-12": {
+      "description": {
+        "id": "Multi-line Text Input-12",
+        "name": "Multi-line Text Input",
+        "alt": "sequential txt input",
+        "path": "./modules/ui/multiline.js",
+        "position": {
+          "left": -1117,
+          "top": 89
+        }
+      },
+      "inputs": {
+        "req": {
+          "accepts": "number"
+        },
+        "lineIn": {
+          "accepts": "string"
+        },
+        "load": {
+          "accepts": "path"
+        }
+      },
+      "outputs": {
+        "lineOut": {
+          "emits": "string",
+          "calls": [
+            {
+              "parentId": "Gcode Parser-11",
+              "key": "lineIn"
+            }
+          ]
+        }
+      },
+      "state": {
+        "load": {
+          "type": "button",
+          "label": "LOAD"
+        },
+        "thru": {
+          "type": "button",
+          "label": "WHAM"
+        },
+        "previously": {
+          "type": "multiline",
+          "label": "lines complete",
+          "rows": 11,
+          "value": ""
+        },
+        "now": {
+          "type": "multiline",
+          "label": "line just out",
+          "rows": 1,
+          "value": ""
+        },
+        "incoming": {
+          "type": "multiline",
+          "label": "future lines",
+          "rows": 36,
+          "value": "G0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\nG0 F50 X10Y10Z10\nG0 X20Y20Z0\nG0 X0\nG0 Y10\n"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/views.js b/views.js
index ff9d5af..4741979 100644
--- a/views.js
+++ b/views.js
@@ -246,7 +246,7 @@ function uiRequestStateChange(data) {
 
     if (mdlState[data.key]) {
         switch (mdlState[data.key].type) {
-            case 'button':
+            case 'button': 
                 mdlState[data.key].onClick()
                 break
             case 'multiline':
-- 
GitLab