Newer
Older
// HEADER
import {
Hunkify,
Input,
Output,
State
} from './hunks.js'
// END HEADER
let dtin = new Input('byteArray', 'data', this)
this.inputs.push(dtin)
let dtout = new Output('byteArray', 'data', this)
this.outputs.push(dtout)
// needs 2 trak status
let isActive = new State('boolean', 'isActive', false)
let otherLink = new State('uint16', 'otherLink', 0)
this.states.push(isActive, otherLink)
// default messages -> manager, besides also data link
let inputList = new State('string', 'inputList', "mgrMsgs (byteArray)")
let outputList = new State('string', 'outputList', "mgrMsgs (byteArray)")
this.states.push(inputList, outputList)
/* --------------------------- ---------------------------- */
/* ------------------ OP ON KEYS FROM STATE ------------------ */
/* --------------------------- ---------------------------- */
let getTypeAndNameKeys = (str) => {
let keys = str.split(',')
let ks = new Array()
let tk = keys[i].substring(keys[i].indexOf('(') + 1, keys[i].indexOf(')'))
let nk = keys[i].substring(0, keys[i].indexOf(' ('))
if (nk[0] == ' ') nk = nk.substring(1)
if (tk.length < 2 || nk.length < 2) {
this.log('bad key pair on inputs / outputs at link')
} else {
}
}
return ks
}
let swapLists = (newList, input) => {
// list,
let nks = getTypeAndNameKeys(newList)
// old list,
let oks
oks = this.inputs
} else {
oks = this.outputs
}
// one by one, down the list we go
// we'l walk the inputs array in step,
// if the input we want already exists in oks, we'll place that
let ioe = -1 // 'index of existing placement'
for (let io in oks) {
if (oks[io].name === nks[kp].nameKey && oks[io].type === nks[kp].typeKey) {
this.inputs[kp + 1] = oks[ioe]
} else {
this.outputs[kp + 1] = oks[ioe]
}
// we can only make types we have serialization routines for:
let phy = findPhy(nks[kp].typeKey)
if(phy.key && phy.read){
this.inputs[kp + 1] = new Input(nks[kp].typeKey, nks[kp].nameKey, this, true)
}
if(phy.key && phy.write){
this.outputs[kp + 1] = new Output(nks[kp].typeKey, nks[kp].nameKey, this, true)
}
if (input) {
while (this.inputs.length - 1 > nks.length) {
// OK: back up to this ...
swapLists(value, true)
// we have to report this ...
this.mgr.evaluateHunk(this)
// if OK
inputList.set(value)
this.mgr.evaluateHunk(this)
// this has to follow on, to complete the promise ?
// this necessitates that we write a manager-message-buffer on embedded,
outputList.set(value)
}
/* --------------------------- ---------------------------- */
/* -------------------------- INIT --------------------------- */
/* --------------------------- ---------------------------- */
this.init = () => {
// since we know this needs to default to nc, and many programs
// will save with these states set 'true', we reset them now.
//otherLink.set(0)
//isActive.set(false)
otherLink.value = 0
isActive.value = false
// just add in order
let ipKeys = getTypeAndNameKeys(inputList.value)
this.inputs.push(new Input(kp.typeKey, kp.nameKey, this, true))
}
}
let opKeys = getTypeAndNameKeys(outputList.value)
this.outputs.push(new Output(kp.typeKey, kp.nameKey, this, true))
}
}
}
/* --------------------------- ---------------------------- */
/* ---------------------- LINK STATE ------------------------- */
/* --------------------------- ---------------------------- */
// a wait-state
let isOpening = false
let openup = (reqResponse) => {
// exit when already opening, this is called
// whenever an input port is occupied (wanting to send)
// ??
let msg = [LK.HELLO]
MSGS.writeTo(msg, this.ind, 'uint16')
// if we're already open, we gucc
MSGS.writeTo(msg, true, 'boolean')
//console.log('link trying to open up', msg)
isOpening = true
} else {
// otherwise we need to ask for a hello in return
MSGS.writeTo(msg, false, 'boolean')
// console.log('link replying to open up', msg)
}
dtout.put(msg)
}
let dataout = (data) => {
if (!isActive.value) {
console.error('attempt to put on not-active link')
} else {
if (!Array.isArray(data)) console.error('non-array put at link')
/* --------------------------- ---------------------------- */
/* ----------------------- SERIALIZE ------------------------- */
/* --------------------------- ---------------------------- */
// deserialize msgs: data is an array of bytes
let demsg = (data) => {
console.log(data)
throw new Error(`link demsg receives non-array, logged above`)
}
// WRITE IT
let msg = {}
//console.log('demsg for hello', data)
msg.isHello = true
msg.otherLink = MSGS.readFrom(data, 1, 'uint16').item
msg.reqReturn = MSGS.readFrom(data, 4, 'boolean').item
return msg
}
// data[0] is the route, the link we need to bump on
msg.port = data[0]
// check for ack,
msg.isAck = true
return msg
// otherwise, get phy and write out
let phy = TSET.find((item) => {
return item.key === data[1]
})
if (phy === undefined) throw new Error(`type not found at deserialization for expected key ${data[1]}`)
return msg
}
// this ...
let ack = (port) => {
outbuffer.push(msg)
}
// serialize messages:
let sermsg = (port, data, type) => {
if (typeof port !== 'number' || port > 254) throw new Error('port is no good at serialize')
// we r ready,
let msg = [port]
MSGS.writeTo(msg, data, type)
if (debug) console.log('LINK sermsg to outbuffer', msg)
this.loop = () => {
// (1) check for data
// if there's data on the line, we might be opening or operating ...
// pulls every time, this is ok because we trust the other link
// to be flow-controlling: this should either be for an open port or
// an ack,
// pull it and deserialize it,
let msg = demsg(dtin.get())
// ack,
if (msg.isAck) {
if (debug) console.log('link ack conf on ', msg.port)
throw new Error('received ack on unexpected port')
}
// is clear upstream
this.inputs[msg.port].icus = true;
// HELLO OTHERLINK
// if we're not open, now we are
}
isOpening = false
otherLink.set(msg.otherLink)
if (msg.reqReturn) {
openup(false)
// check port existence
// new approach: blind ackit
ack(msg.port)
console.warn('blind ack')
//throw new Error(`link receives message for port not listed: ${msg.port}`)
}
// not an ack, for port, if open, put data
// clear ahead, typecheck and put
if (debug) console.log('link putting', msg.data, 'on', msg.port)
this.outputs[msg.port].put(msg.data)
this.outputs[msg.port].needsAck = true
// and ack when it is pulled off,
} else {
// oboy: we pulled it off of the link, so
console.log(`WARN: link receives message for occupied port: ${msg.port}, ${this.outputs[msg.port].name}`)
console.log('the msg', msg)
}
}
// this is an array, we have to deserialize it
// (2) check if we can put
if (!(dtout.io()) && outbuffer.length > 0) { // if we can send things to the world, do so
if (!isActive.value) {
// clear-to-send upstream, we don't have sync state, so
// want to open, want a reply
openup(true)
return
}
// because of looping sys, we can only do this once per turn
if (debug) console.log('LINK OUT ->>', turn)
dataout(turn)
}
// (3) check if we can ack, if data has been consumed
// if now clear, ack back
if (this.outputs[o].needsAck && !this.outputs[o].io()) {
// CLEANUP: .needsAck to false -> ack fn ?
this.outputs[o].needsAck = false
ack(o)
}
}
// (4) look at inputs and see if we can put anything on the line
// only pull off of inputs if we are known to be clear downstream
if (this.inputs[i].icus && this.inputs[i].io()) {
if (!isActive.value) {
// nc, but wants to send, so ... and don't pull offline yet
// so ping to open up,
openup(true)
return
}
if (debug) console.log(`link pulling message from input ${i}, data is ${data}`)
// FOOTER
export default Link
// END FOOTER