Skip to content
Snippets Groups Projects
atkseriallink.js 7.34 KiB
Newer Older
  • Learn to ignore specific revisions
  • // 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 SerialPort = require('serialport')
    
    
    Jake Read's avatar
    Jake Read committed
    function ATKSerialLink() {
        var atkSerialLink = {
    
            description: {
                isHardware: true,
    
    Jake Read's avatar
    Jake Read committed
                isLink: true,
    
                name: 'Serialport ATK Link',
                alt: 'window into hardware world'
            },
    
    Jake Read's avatar
    Jake Read committed
            routes: new Array()
    
        }
    
        var state = State()
    
    Jake Read's avatar
    Jake Read committed
        atkSerialLink.state = state
    
    Jake Read's avatar
    Jake Read committed
        state.portName = '---'
        state.connect = Button('click to find and connect', findSerialPort)
        state.portStatus = 'closed' // or we hope it will be 
    
    
        /*
        ------------------------------------------------------
        HOOKING UP 
        ------------------------------------------------------
        */
    
    
    Jake Read's avatar
    Jake Read committed
        atkSerialLink.attach = function(route) {
            console.log('PORT->LINK HOOKUP', route.route)
            this.routes.push(route)
            route.link = this
    
        }
    
        /*
        ------------------------------------------------------
        SERIALPORT MANAGEMENT 
        ------------------------------------------------------
        */
    
        // instance of SerialPort 
        serialport = null
    
        function findSerialPort() {
    
            state.portStatus = 'searching for CP2102 device'
            var found = false 
    
            SerialPort.list(function(err, ports) {
                ports.forEach(function(serialport) {
                    if (serialport.manufacturer == 'Silicon Labs') {
                        console.log('found cp2102 serialport')
    
                        found = true 
    
    Jake Read's avatar
    Jake Read committed
                        state.portName = serialport.comName
    
                        openSerialPort()
                    }
                })
            })
    
            if(!found){
                console.log('no CP2102 device found, try serialport-list to make sure it is available to the system')
                state.portStatus = 'no CP2102 device found'
            }
    
        }
    
        function openSerialPort() {
    
    Jake Read's avatar
    Jake Read committed
            if (state.portName == '---') {
    
                findSerialPort()
            } else {
                if (serialport == null) {
    
    Jake Read's avatar
    Jake Read committed
                    serialport = new SerialPort(state.portName, {
    
                        baudRate: 250000
                    })
                    serialport.on('open', function() {
    
    Jake Read's avatar
    Jake Read committed
                        state.portStatus = 'open'
    
                    })
                    serialport.on('error', function(err) {
    
    Jake Read's avatar
    Jake Read committed
                        state.portStatus = err.message
    
                    })
                    serialport.on('data', onSerialPortData)
                }
            }
        }
    
        /*
        ------------------------------------------------------
        PACKETS TO HARDWARE
        ------------------------------------------------------
        */
    
    
    Jake Read's avatar
    Jake Read committed
        atkSerialLink.send = function(msg, route) {
    
            // it would be responsible to check this over now, but hey
    
    Jake Read's avatar
    Jake Read committed
            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 
    
    Jake Read's avatar
    Jake Read committed
                var literalRoute = route.route.split(',')
                pckt = literalRoute.concat(pckt) // add route 
    
                pckt.unshift(pckt.length + 1) // add length byte 
                if (writeToSerialPort(pckt)) {
    
    Jake Read's avatar
    Jake Read committed
                    console.log('PCKT OUT >>', pckt.toString(), '---------------')
    
    Jake Read's avatar
    Jake Read committed
                    // 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')
                    }
    
    Jake Read's avatar
    Jake Read committed
                console.log('non-array on atkSerialLink input')
    
            }
        }
    
        // HERE this module is a hot mess 
    
        function writeToSerialPort(pckt) {
            if (serialport != null && serialport.writable) {
                if (serialport.write(pckt)) {
                    return true
                } else {
                    console.log('------------------ !ACHTUNG! -------------------')
                    console.log('------------------ !ACHTUNG! -------------------')
                    console.log('---------- serialport.write(pckt) false --------------')
                    // https://nodejs.org/api/stream.html#stream_event_drain
                    // https://serialport.io/docs/api-stream
                    return false
                }
            } else {
                return false
            }
        }
    
        /*
        ------------------------------------------------------
        PACKETS FROM HARDWARE 
        ------------------------------------------------------
        */
    
        var thisPacket = new Array()
    
    
    Jake Read's avatar
    Jake Read committed
        function onSerialPortData(data) {
    
            // we'll make sure it's what we think it will be
            // console.log("PORT DATA")
            var dtArray = new Array()
            if (Buffer.isBuffer(data)) {
                for (var i = 0; i < data.length; i++) {
                    dtArray[i] = data[i]
                }
            } else {
                console.log("ERR: port data non-buffer")
            }
    
            //console.log('DATA IN', dtArray.toString())
    
            thisPacket = thisPacket.concat(dtArray)
            if (thisPacket[0] <= 0) {
                thisPacket = []
                console.log('throwing packet with leading zero')
            }
    
            while (thisPacket.length >= thisPacket[0]) {
                if (thisPacket.length == thisPacket[0]) {
                    var packetCopy = thisPacket.slice(0) // copy, deref
                    thisPacket = []
                    onPacket(packetCopy)
                } else { // rare case of two packets saddling break 
                    var fullPacket = thisPacket.slice(0, thisPacket[0])
                    onPacket(fullPacket)
                    thisPacket = thisPacket.slice(thisPacket[0])
                }
    
            }
        }
    
        function onPacket(pckt) {
            var debug = false
            // we're the last link, shift that pointer
            shiftPacketPointer(pckt)
            // log it
            console.log('PCKT IN <<', pckt.toString(), '-----------------------')
            // grab the routing header
            var incomingRoute = pckt.slice(2, pckt.indexOf(255))
            // flip to match outgoing 
            var returnRoute = new Array()
            for (i in incomingRoute) {
                returnRoute[i] = incomingRoute[incomingRoute.length - 1 - i]
            }
            // now we'll look for a reciprocal port from our list 
    
    Jake Read's avatar
    Jake Read committed
            var match = false
            for (key in atkSerialLink.routes) {
                if (returnRoute.toString() === atkSerialLink.routes[key].route.toString()) {
    
                    // strip header and return message 
    
    Jake Read's avatar
    Jake Read committed
                    var msg = pckt.slice(pckt.indexOf(255) + 1)
    
    Jake Read's avatar
    Jake Read committed
                    // this slices down to the keys ... doesn't take the keys away 
    
    Jake Read's avatar
    Jake Read committed
                    match = true 
                    atkSerialLink.routes[key].onMessage(msg)
    
    Jake Read's avatar
    Jake Read committed
            if (!match) {
    
                console.log("PACKET RETURN AND NO KEY FOUND")
                console.log(pckt)
            }
        }
    
        function shiftPacketPointer(pckt) {
            var end = 0
            var i = 0
            while (end == 0) {
                if (pckt[i] === 255) {
                    end = i
                } else if (i >= pckt.length) {
                    break
                }
                i++
            }
            //array[1] = 254
            for (var j = 1; j < end - 1; j++) {
                pckt[j] = pckt[j + 1]
            }
            pckt[end - 1] = 0
            // console.log('shifted', pckt)
        }
    
    
    Jake Read's avatar
    Jake Read committed
        return atkSerialLink
    
    Jake Read's avatar
    Jake Read committed
    module.exports = ATKSerialLink