From 250ff884d7e974a128914e6b1d547aa710e538bc Mon Sep 17 00:00:00 2001 From: Jake <jake.read@cba.mit.edu> Date: Mon, 12 Nov 2018 19:46:03 -0500 Subject: [PATCH] hardware abstraction --- README.md | 8 ++ client/client.js | 10 ++- lib/atkport.js | 27 ------- lib/atkroute.js | 36 +++++++++ lib/atkunit.js | 50 +++++++++++++ main.js | 19 ++++- modules/hardware/atkbbbs.js | 63 ---------------- modules/hardware/atkbbs.js | 69 ++++++++++++++++++ .../{serialATKLink.js => atkseriallink.js} | 73 ++++++++++--------- programs.js | 13 ++++ 10 files changed, 240 insertions(+), 128 deletions(-) delete mode 100644 lib/atkport.js create mode 100644 lib/atkroute.js create mode 100644 lib/atkunit.js delete mode 100644 modules/hardware/atkbbbs.js create mode 100644 modules/hardware/atkbbs.js rename modules/hardware/{serialATKLink.js => atkseriallink.js} (75%) diff --git a/README.md b/README.md index b32cc14..6fbf4f7 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,14 @@ This project serves the developement environment / api we use to write and repre ## For MW + - serial link OK, attach + - routes have route, test send + - thru route, append route + - thru link, to send. + - callback key subscribe fn's + - then: route change propogation? + - test with test: callback + - then draw something, and how does UI hook up, and when route changes ? - change /src to /modules or /units ? diff --git a/client/client.js b/client/client.js index 2c72cdc..62b5160 100644 --- a/client/client.js +++ b/client/client.js @@ -1,6 +1,10 @@ // // // new node controller / VIEW +// reconfigurable unviersal numeric dataflow machine controller +// 'RUN DMC' +// dataflow numeric controller +// DNC // // client.js // @@ -404,6 +408,8 @@ onwheel = function(evt) { onmousedown = function(evt) { var el = document.elementFromPoint(evt.pageX, evt.pageY) if (elementIsNotModule(el)) { + evt.preventDefault() + evt.stopPropagation() window.addEventListener('mousemove', mouseMoveDragListener) window.addEventListener('mouseup', mouseUpDragListener) } @@ -492,14 +498,14 @@ function writeModuleOptionMenu(modRep) { if (opts[i] == 'delete') { li.addEventListener('click', function(evt) { var data = { - id: modRep.description.id + id: modRep.description.id } socketSend('remove module', data) wrapper.removeChild(document.getElementById('perModuleMenu')) }) } else if (opts[i] == 'copy') { li.addEventListener('click', function(evt) { - var data = modRep.description.path + var data = modRep.description.path socketSend('put module', data) wrapper.removeChild(document.getElementById('perModuleMenu')) }) diff --git a/lib/atkport.js b/lib/atkport.js deleted file mode 100644 index 778cc4f..0000000 --- a/lib/atkport.js +++ /dev/null @@ -1,27 +0,0 @@ -// object to extend for things-that-are-hardware - -// and pass f'n to call on received messages -function ATKPort(route, calls) { - var atkport = { - isAtkPort: true, - link: null, // pls, deliver 2 me a hw outlet - route: route, - calls: calls - } - - atkport.send = function(msg) { - if (this.link != null) { - this.link.send(msg, this) - } else { - console.log("NO LINK NO SEND") - } - } - - atkport.onMessage = function(msg){ - this.calls(msg) - } - - return atkport -} - -module.exports = ATKPort \ No newline at end of file diff --git a/lib/atkroute.js b/lib/atkroute.js new file mode 100644 index 0000000..52a0f1a --- /dev/null +++ b/lib/atkroute.js @@ -0,0 +1,36 @@ +// object to extend for things-that-are-hardware + +// and pass f'n to call on received messages +function ATKRoute(route, calls) { + var atkroute = { + isAtkRoute: true, + link: null, // pls, deliver 2 me a hw outlet + route: route, + calls: {} + } + + atkroute.send = function(msg) { + if (this.link != null) { + // CHECKS and append route, then send + this.link.send(msg, this) + } else { + console.log("NO LINK NO SEND") + } + } + + atkroute.subscribe = function(key, callback){ + this.calls[key.toString()] = callback + } + + atkroute.onMessage = function(msg){ + // one key at a time, for now + var key = msg[0].toString() + if(this.calls[key] != null){ + this.calls[key](msg) + } + } + + return atkroute +} + +module.exports = ATKRoute \ No newline at end of file diff --git a/lib/atkunit.js b/lib/atkunit.js new file mode 100644 index 0000000..38fb152 --- /dev/null +++ b/lib/atkunit.js @@ -0,0 +1,50 @@ +// software object for reciprocal hardware object + +// boilerplate atkapi header +const InOut = require('./jsunit.js') +let Input = InOut.Input +let Output = InOut.Output +let State = InOut.State +let Button = InOut.Button + +const ATKRoute = require('./atkroute.js') + +function Hardware(route){ + var hardware = { + description:{ + name: 'hardwareUnit', + alt: 'software representation of networked hardware object', + isHardware: true + }, + route: ATKRoute(route) + } + + hardware.state = State() + var state = hardware.state + + state.test = Button('test network', onNetworkTest) + state.message = 'click above to test network' + state.route = route + + state.onChange('route', function(){ + console.log("route change, need to git it thru") + }) + + function onNetworkTest(){ + var tstpck = new Array() + tstpck.push(127) + state.message = 'test packet out' + hardware.route.send(tstpck) + } + + hardware.route.subscribe(127, testReturn) + + function testReturn(msg){ + state.message = 'test OK' + console.log('test returns with msg', msg) + } + + return hardware +} + +module.exports = Hardware \ No newline at end of file diff --git a/main.js b/main.js index aa864d4..864b017 100644 --- a/main.js +++ b/main.js @@ -27,9 +27,24 @@ programs are assemblies of modules const Reps = require('./reps.js') const Programs = require('./programs.js') -var program = {} +var program = Programs.new('hw unit test') -program = Programs.open('programs/default.json') +var link = Programs.loadModuleFromSource(program, './modules/hardware/atkseriallink.js') +var atkbbs = Programs.loadModuleFromSource(program, './modules/hardware/atkbbs.js') + +atkbbs.description.position = { + left: 10, + top: 200 +} + +link.description.position = { + left:475, + top: 100 +} + +link.attach(atkbbs.route) + +//program = Programs.open('programs/default.json') // UI const View = require('./views.js') diff --git a/modules/hardware/atkbbbs.js b/modules/hardware/atkbbbs.js deleted file mode 100644 index 5358147..0000000 --- a/modules/hardware/atkbbbs.js +++ /dev/null @@ -1,63 +0,0 @@ -// boilerplate atkapi header -const InOut = require('../../lib/jsunit.js') -let Input = InOut.Input -let Output = InOut.Output -let State = InOut.State -let Button = InOut.Button - -const ATKPort = require('../../lib/atkport.js') -const PCKT = require('../../lib/packets.js') - -// a constructor, a fn, a javascript mess -function ATKBreadBoardServo() { - - var atkbbs = { - description: { - name: 'Breadboard Servo Signal Generator', - alt: 'servo', - isHardware: true - }, - port: ATKPort('0', onPacket), // inputs / outputs to external hw - inputs: { - servoVal: Input('number', onServoValChange) - }, - outputs: { - conf: Output('event') - }, - } - - atkbbs.state = State() - // alias ! - var state = atkbbs.state - - state.button = Button('SEND') - state.onChange('button', onServoValChange) - state.servoVal = 0 // 0->100 does 1 -> 2ms duty on 20ms period - state.onChange('servoVal', onServoValChange) - - function onServoValChange(evt) { - var pwm = state.servoVal - if (pwm > 100) { - pwm = 100 - } else if (pwm < 0) { - pwm = 0 - } - - var microval = Math.round(7.5 * pwm) - console.log('pwm on line', microval) - - var pwmpack = PCKT.pack32(microval) - pwmpack.unshift(141) - - atkbbs.port.send(pwmpack) - } - - function onPacket(pckt) { - console.log('ATKBBBS Packet Return', pckt) - } - - return atkbbs -} - -// exports -module.exports = ATKBreadBoardServo \ No newline at end of file diff --git a/modules/hardware/atkbbs.js b/modules/hardware/atkbbs.js new file mode 100644 index 0000000..b0e3665 --- /dev/null +++ b/modules/hardware/atkbbs.js @@ -0,0 +1,69 @@ +// boilerplate atkapi header +const InOut = require('../../lib/jsunit.js') +let Input = InOut.Input +let Output = InOut.Output +let State = InOut.State +let Button = InOut.Button + +const Hardware = require('../../lib/atkunit.js') +const PCKT = require('../../lib/packets.js') + +// a constructor, a fn, a javascript mess +function ATKBreadBoardServo() { + + // we make the module, starting from this base + // '0,1' is the route to our piece of hardware + // 'onPacket' is the function that will be called + // when data arrives from that port + var atkbbs = Hardware('0,1') + + // change the name ... + atkbbs.description.name = 'ATKBBB-Servo' + + // inputs and outputs as usual + atkbbs.inputs = { + servoVal: Input('number', onServoValChange) + } + atkbbs.outputs = { + conf: Output('event') + } + + // and state as well + var state = atkbbs.state + + state.button = Button('SEND VALUE', onServoValChange) + state.servoVal = 0 // 0->100 does 1 -> 2ms duty on 20ms period + state.onChange('servoVal', onServoValChange) + + // to send things down the well, we can use + // atkbbs.route.send(packet) + // where packet is a byte array + + function onServoValChange(evt) { + var pwm = state.servoVal + if (pwm > 100) { + pwm = 100 + } else if (pwm < 0) { + pwm = 0 + } + + var microval = Math.round(7.5 * pwm) + console.log('pwm on line', microval) + + var pwmpack = PCKT.pack32(microval) + pwmpack.unshift(141) + + atkbbs.route.send(pwmpack) + } + + // to get replies to certain packets, we can + + atkbbs.route.subscribe(141, function(msg){ + console.log('logging return', msg) + }) + + return atkbbs +} + +// exports +module.exports = ATKBreadBoardServo \ No newline at end of file diff --git a/modules/hardware/serialATKLink.js b/modules/hardware/atkseriallink.js similarity index 75% rename from modules/hardware/serialATKLink.js rename to modules/hardware/atkseriallink.js index 2f54d17..281d0ee 100644 --- a/modules/hardware/serialATKLink.js +++ b/modules/hardware/atkseriallink.js @@ -8,23 +8,22 @@ let Button = InOut.Button const SerialPort = require('serialport') -function SerialATKLink() { - var serialATKLink = { +function ATKSerialLink() { + var atkSerialLink = { description: { isHardware: true, name: 'Serialport ATK Link', alt: 'window into hardware world' }, - ports: new Array() + routes: new Array() } var state = State() - serialATKLink.state = state + atkSerialLink.state = state - state.serialPortName = '---' - state.connect = Button('click to find and connect') - state.onChange('connect', findSerialPort) - state.serialPortStatus = 'closed' // or we hope it will be + state.portName = '---' + state.connect = Button('click to find and connect', findSerialPort) + state.portStatus = 'closed' // or we hope it will be /* ------------------------------------------------------ @@ -32,10 +31,10 @@ function SerialATKLink() { ------------------------------------------------------ */ - serialATKLink.attach = function(port) { - console.log('PORT->LINK HOOKUP', port.route) - this.ports.push(port) - port.link = this + atkSerialLink.attach = function(route) { + console.log('PORT->LINK HOOKUP', route.route) + this.routes.push(route) + route.link = this } /* @@ -52,7 +51,7 @@ function SerialATKLink() { ports.forEach(function(serialport) { if (serialport.manufacturer == 'Silicon Labs') { console.log('found cp2102 serialport') - state.serialPortName = serialport.comName + state.portName = serialport.comName openSerialPort() } }) @@ -60,18 +59,18 @@ function SerialATKLink() { } function openSerialPort() { - if (state.serialPortName == '---') { + if (state.portName == '---') { findSerialPort() } else { if (serialport == null) { - serialport = new SerialPort(state.serialPortName, { + serialport = new SerialPort(state.portName, { baudRate: 250000 }) serialport.on('open', function() { - state.serialPortStatus = 'open' + state.portStatus = 'open' }) serialport.on('error', function(err) { - state.serialPortStatus = err.message + state.portStatus = err.message }) serialport.on('data', onSerialPortData) } @@ -84,24 +83,30 @@ function SerialATKLink() { ------------------------------------------------------ */ - serialATKLink.send = function(msg, port) { + atkSerialLink.send = function(msg, route) { // it would be responsible to check this over now, but hey - console.log('send', msg, 'on', port) + console.log('send', msg, 'on', route.route) // dereference this var pckt = JSON.parse(JSON.stringify(msg)) if (Array.isArray(pckt)) { pckt.unshift(255) // end delimiter pckt.unshift(254) // ptr - var route = port.route.split(',') - pckt = route.concat(pckt) // add route + var literalRoute = route.route.split(',') + pckt = literalRoute.concat(pckt) // add route pckt.unshift(pckt.length + 1) // add length byte if (writeToSerialPort(pckt)) { console.log('PCKT OOT >>', pckt.toString()) } else { - console.log('ERR: attempt to send to hardware, port not writable') + // try to open ? + openSerialPort() + if (writeToSerialPort(pckt)) { + console.log('PCKT OOT >>', pckt.toString()) + } else { + console.log('ERR: attempt to send to hardware, port not writable') + } } } else { - console.log('non-array on serialATKLink input') + console.log('non-array on atkSerialLink input') } } @@ -132,7 +137,7 @@ function SerialATKLink() { var thisPacket = new Array() - function onSerialPort(data) { + function onSerialPortData(data) { // we'll make sure it's what we think it will be // console.log("PORT DATA") var dtArray = new Array() @@ -180,20 +185,20 @@ function SerialATKLink() { returnRoute[i] = incomingRoute[incomingRoute.length - 1 - i] } // now we'll look for a reciprocal port from our list - var match = null - for (key in serialATKLink.ports) { - if (returnRoute.toString() === serialATKLink.ports[key].route.toString()) { - console.log('RETURN LINK AT', serialATKLink.ports[key]) + var match = false + for (key in atkSerialLink.routes) { + if (returnRoute.toString() === atkSerialLink.routes[key].route.toString()) { + console.log('RETURN LINK AT', atkSerialLink.routes[key]) // strip header and return message - var msg = pckt.slice(pckt.indexOf(255)) + var msg = pckt.slice(pckt.indexOf(255) + 1) console.log("RETURN MSG", msg) - serialATKLink.ports[key].onMessage(msg) + match = true + atkSerialLink.routes[key].onMessage(msg) } } - if (match == null) { + if (!match) { console.log("PACKET RETURN AND NO KEY FOUND") console.log(pckt) - console.log(serialATKLink.pairs) } } @@ -216,7 +221,7 @@ function SerialATKLink() { // console.log('shifted', pckt) } - return serialATKLink + return atkSerialLink } -module.exports = SerialATKLink \ No newline at end of file +module.exports = ATKSerialLink \ No newline at end of file diff --git a/programs.js b/programs.js index 369a8f0..1c5a080 100644 --- a/programs.js +++ b/programs.js @@ -5,6 +5,18 @@ const Reps = require('./reps.js') const JSUnit = require('./lib/jsunit.js') let isStateKey = JSUnit.isStateKey +function newProgram(name){ + var program = { + description: { + name: name, + id: name + }, + modules: {} + } + + return program +} + function loadModuleFromSource(program, path, id) { // source -> heap if (fs.existsSync(path)) { @@ -224,6 +236,7 @@ function openProgram(path) { } module.exports = { + new: newProgram, open: openProgram, save: saveProgram, loadModuleFromSource: loadModuleFromSource, -- GitLab