From 121ea65f4e41daa69c1e5cac163784e88ca26c3f Mon Sep 17 00:00:00 2001 From: Scott Bender Date: Thu, 16 Jan 2020 13:50:04 -0500 Subject: [PATCH] feature: add support for Digital Yacht's NavLink2 --- lib/ikonvert.js | 156 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 131 insertions(+), 25 deletions(-) diff --git a/lib/ikonvert.js b/lib/ikonvert.js index 40d03b4..99e58b2 100644 --- a/lib/ikonvert.js +++ b/lib/ikonvert.js @@ -39,6 +39,10 @@ function iKonvertStream (options) { objectMode: true }) + this.isTcp = options.tcp === true + + this.outEvent = this.isTcp? 'navlink2-out' : 'ikonvertOut' + this.plainText = false this.reconnect = options.reconnect || true this.options = options @@ -74,7 +78,14 @@ function iKonvertStream (options) { that.sendPGN(msg) }) - this.sendString('$PDGY,N2NET_OFFLINE') + if ( this.isTcp ) { + this.isSetup = false + this.state = 0 + this.setupCommands = this.getSetupCommands() + this.expecting = false + } else { + this.sendString('$PDGY,N2NET_OFFLINE') + } debug('started') } @@ -87,7 +98,10 @@ iKonvertStream.prototype.start = function () { iKonvertStream.prototype.sendString = function (msg) { debug('sending %s', msg) - this.options.app.emit('ikonvertOut', msg) + if ( this.isTcp ) { + msg = msg + "\n\r" + } + this.options.app.emit(this.outEvent, msg) } iKonvertStream.prototype.sendPGN = function (pgn) { @@ -136,40 +150,132 @@ iKonvertStream.prototype.setup = function () { this.sendString(txPgns) } +iKonvertStream.prototype.getSetupCommands = function () { + let txPgns = '$PDGY,TX_LIST' + this.transmitPGNs.forEach(pgn => { + txPgns = txPgns + `,${pgn}` + }) + + const setupCommands = [ + '$PDGY,N2NET_OFFLINE:$PDGY,TEXT,Digital_Yacht_Navlink2', + '$PDGY,N2NET_MODE,15:$PDGY,ACK,N2NET_MODE', + `${txPgns}:$PDGY,ACK,TX_LIST`, + '$PDGY,N2NET_INIT,ALL:$PDGY,ACK,N2NET_INIT,ALL' + ] + return setupCommands +} + iKonvertStream.prototype._transform = function (chunk, encoding, done) { let line = chunk.toString().trim() line = line.substring(0, line.length) // take off the \r - if ( line.startsWith('$PDGY') ) { - if ( line === '$PDGY,000000,,,,,,' ) { - //the iKonvert is not initialized - if ( !this.didSetup ) { - this.setup() - this.setProviderStatus('Initializing...') - this.didSetup = true - } - } else if ( line === '$PDGY,ACK,TX_LIST' ) { - debug('sending net init') - this.sendString('$PDGY,N2NET_INIT,ALL') - this.setProviderStatus('Initialized...') - } else if ( line === '$PDGY,ACK,N2NET_INIT,ALL' && !this.cansend ) { - this.cansend = true; - this.options.app.emit('nmea2000OutAvailable') - //this.sendString('$PDGY,SHOW_LISTS') - } else if ( line.startsWith('$PDGY,TEXT') ) { - debug(line) - } else if ( line.startsWith('$PDGY,000000') ) { - let parts = line.split(',') - debug('ikonvert can address: %s', parts[6]) + if ( this.isTcp ) { + if ( line.startsWith('$PDGY,TEXT') ) { debug(line) } else if ( line.startsWith('$PDGY,NAK') ) { let parts = line.split(',') - let msg = `iKonvert error ${parts[2]}: ${parts[3]}` + let msg = `NavLink2 error ${parts[2]}: ${parts[3]}` console.error(msg) this.setProviderError(msg) } - } else { + + if ( !this.isSetup ) { + debug(line) + let command = this.setupCommands[this.state].split(':') + if ( !this.expecting ) { + this.sendString(command[0]) + this.expecting = true + this.sentTime = Date.now() + debug(`Waiting for ${command[1]}`) + } else { + if ( line.startsWith(command[1]) ) { + this.state = this.state + 1 + + if ( this.state == this.setupCommands.length ) { + this.isSetup = true + debug('Setup completed') + } else { + command = this.setupCommands[this.state].split(':') + this.sendString(command[0]) + this.expecting = true + this.sentTime = Date.now() + debug(`Waiting for ${command[1]}`) + } + } else if ( Date.now() - this.sentTime > 5000 ) { + debug(`Did not receive expected: ${command[1]}, retrying...`) + this.sendString(command[0]) + this.sentTime = Date.now() + } + } + } else { + this.push(line) + } + + + /* + if ( !this.didSetRaw ) { + this.setProviderStatus('Initializing...') + this.sendString('$PDGY,N2NET_OFFLINE') + this.sendString('$PDGY,N2NET_MODE,15') + this.setup() + this.didSetRaw = true + } else if ( !this.isSetup ) { + debug(line) + if ( line.startsWith('$PDGY,ACK,TX_LIST') ) { + this.sendString('$PDGY,N2NET_INIT,ALL') + } else if ( line.startsWith('$PDGY,ACK,N2NET_INIT,ALL') || line.startsWith('$PDGY,NAK,1,ALREADY_INITIALISED') ) { + this.cansend = true; + this.isSetup = true; + this.options.app.emit('nmea2000OutAvailable') + this.setProviderStatus('Connected') + } + } else { + this.push(line) + } + */ + + + /*else if ( !this.isSetup ) { + this.setup() + this.isSetup = true + } + if ( line.startsWith('$PDGY') ) { + + } else if ( this.isSetup ) { this.push(line) + }*/ + } else { + if ( line.startsWith('$PDGY') ) { + if ( line === '$PDGY,000000,,,,,,' ) { + //the iKonvert is not initialized + if ( !this.didSetup ) { + this.setup() + this.setProviderStatus('Initializing...') + this.didSetup = true + } + } else if ( line === '$PDGY,ACK,TX_LIST' ) { + debug('sending net init') + this.sendString('$PDGY,N2NET_INIT,ALL') + this.setProviderStatus('Initialized...') + } else if ( line === '$PDGY,ACK,N2NET_INIT,ALL' && !this.cansend ) { + this.cansend = true; + this.options.app.emit('nmea2000OutAvailable') + //this.sendString('$PDGY,SHOW_LISTS') + } else if ( line.startsWith('$PDGY,TEXT') ) { + debug(line) + } else if ( line.startsWith('$PDGY,000000') ) { + let parts = line.split(',') + debug('ikonvert can address: %s', parts[6]) + debug(line) + } else if ( line.startsWith('$PDGY,NAK') ) { + let parts = line.split(',') + let msg = `iKonvert error ${parts[2]}: ${parts[3]}` + console.error(msg) + this.setProviderError(msg) + } + } else { + this.push(line) + } } done()