From dceeb5f4001d6594106d85bfddd64fea3dd1738d Mon Sep 17 00:00:00 2001 From: Ian Boston Date: Tue, 5 Sep 2017 18:20:27 +0100 Subject: [PATCH] Restructured to allow sentences to be loaded from files and added some NKE sentences. Needs derived data to work --- index.js | 465 ++++++-------------------------------- nmea.js | 99 ++++++++ sentences/APB.js | 62 +++++ sentences/DBK.js | 23 ++ sentences/DBS.js | 23 ++ sentences/DBT.js | 23 ++ sentences/DPT.js | 28 +++ sentences/GLL.js | 37 +++ sentences/HDG.js | 29 +++ sentences/HDM.js | 18 ++ sentences/HDMC.js | 18 ++ sentences/HDT.js | 20 ++ sentences/MMB.js | 28 +++ sentences/MTA.js | 25 ++ sentences/MTW.js | 20 ++ sentences/MWD.js | 38 ++++ sentences/MWVR.js | 39 ++++ sentences/MWVT.js | 24 ++ sentences/PNKEP01.js | 39 ++++ sentences/PNKEP02.js | 25 ++ sentences/PNKEP03.js | 29 +++ sentences/PNKEP99.js | 29 +++ sentences/RMB.js | 39 ++++ sentences/RMC.js | 63 ++++++ sentences/ROT.js | 19 ++ sentences/TODO/PNKEP04.js | 14 ++ sentences/TODO/PNKEP05.js | 17 ++ sentences/TODO/PNKEP11.js | 8 + sentences/TODO/PNKEP12.js | 6 + sentences/TODO/TODO.js | 29 +++ sentences/TODO/XDRHeel.js | 3 + sentences/TODO/XDRMast.js | 5 + sentences/TODO/sent.js | 9 + sentences/VHW.js | 42 ++++ sentences/VLW.js | 26 +++ sentences/VTG.js | 34 +++ sentences/VWR.js | 40 ++++ sentences/VWT.js | 32 +++ sentences/XDRBaro.js | 25 ++ sentences/XDRTemp.js | 25 ++ sentences/XTE.js | 26 +++ sentences/ZDA.js | 37 +++ 42 files changed, 1242 insertions(+), 398 deletions(-) create mode 100644 nmea.js create mode 100644 sentences/APB.js create mode 100644 sentences/DBK.js create mode 100644 sentences/DBS.js create mode 100644 sentences/DBT.js create mode 100644 sentences/DPT.js create mode 100644 sentences/GLL.js create mode 100644 sentences/HDG.js create mode 100644 sentences/HDM.js create mode 100644 sentences/HDMC.js create mode 100644 sentences/HDT.js create mode 100644 sentences/MMB.js create mode 100644 sentences/MTA.js create mode 100644 sentences/MTW.js create mode 100644 sentences/MWD.js create mode 100644 sentences/MWVR.js create mode 100644 sentences/MWVT.js create mode 100644 sentences/PNKEP01.js create mode 100644 sentences/PNKEP02.js create mode 100644 sentences/PNKEP03.js create mode 100644 sentences/PNKEP99.js create mode 100644 sentences/RMB.js create mode 100644 sentences/RMC.js create mode 100644 sentences/ROT.js create mode 100644 sentences/TODO/PNKEP04.js create mode 100644 sentences/TODO/PNKEP05.js create mode 100644 sentences/TODO/PNKEP11.js create mode 100644 sentences/TODO/PNKEP12.js create mode 100644 sentences/TODO/TODO.js create mode 100644 sentences/TODO/XDRHeel.js create mode 100644 sentences/TODO/XDRMast.js create mode 100644 sentences/TODO/sent.js create mode 100644 sentences/VHW.js create mode 100644 sentences/VLW.js create mode 100644 sentences/VTG.js create mode 100644 sentences/VWR.js create mode 100644 sentences/VWT.js create mode 100644 sentences/XDRBaro.js create mode 100644 sentences/XDRTemp.js create mode 100644 sentences/XTE.js create mode 100644 sentences/ZDA.js diff --git a/index.js b/index.js index 9e8dbf3..bf5086c 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,24 @@ const Bacon = require('baconjs'); +const path = require('path') +const fs = require('fs') module.exports = function(app) { + + + function load_sentences (app, plugin, dir) { + fpath = path.join(__dirname, dir) + files = fs.readdirSync(fpath).filter(function(f) { + return f.endsWith('.js'); + }); + return files.map(fname => { + sentence = path.basename(fname, '.js') + var sobj = require(path.join(fpath, sentence))(app, plugin); + sobj.optionKey = sentence; + return sobj; + }).filter(calc => { return typeof calc !== 'undefined'; }); + } + + var plugin = { unsubscribes: [] }; @@ -20,426 +38,77 @@ module.exports = function(app) { const selfContext = 'vessels.' + app.selfId const selfMatcher = (delta) => delta.context && delta.context === selfContext - function mapToNmea(encoder) { - const selfStreams = encoder.keys.map(app.streambundle.getSelfStream, app.streambundle) - plugin.unsubscribes.push(Bacon.combineWith(encoder.f, selfStreams).changes().debounceImmediate(20).onValue(nmeaString => { - app.emit('nmea0183out', nmeaString) - })) - } - - Object.keys(plugin.sentences).forEach(name => { - if ( options[name] ) - { - mapToNmea(plugin.sentences[name]); - } - }) - } - - plugin.stop = function() { - plugin.unsubscribes.forEach(f => f()) - } - - plugin.sentences = { - /* - === MWV - Wind Speed and Angle === - - ------------------------------------------------------------------------------ - 1 2 3 4 5 - | | | | | - $--MWV,x.x,a,x.x,a*hh - ------------------------------------------------------------------------------ - - Field Number: - - 1. Wind Angle, 0 to 360 degrees - 2. Reference, R = Relative, T = True - 3. Wind Speed - 4. Wind Speed Units, K/M/N - 5. Status, A = Data Valid - 6. Checksum - */ - - MWV: { - title: "MWV - Wind heading and speed", - keys: [ - 'environment.wind.angleApparent', 'environment.wind.speedApparent' - ], - f: function mwv(angle, speed) { - return toSentence([ - '$SKMWV', - radsToDeg(angle).toFixed(1), - 'R', - speed.toFixed(1), - 'M', - 'A' - ]); - } - }, - - /* - ------------------------------------------------------------------------------ - 13 15 - 1 2 3 4 5 6 7 8 9 10 11 12| 14| - | | | | | | | | | | | | | | | - $--APB,A,A,x.x,a,N,A,A,x.x,a,c--c,x.x,a,x.x,a*hh - ------------------------------------------------------------------------------ - - Field Number: - - 1. Status - V = LORAN-C Blink or SNR warning - V = general warning flag or other navigation systems when a reliable - fix is not available - 2. Status - V = Loran-C Cycle Lock warning flag - A = OK or not used - 3. Cross Track Error Magnitude - 4. Direction to steer, L or R - 5. Cross Track Units, N = Nautical Miles - 6. Status - A = Arrival Circle Entered - 7. Status - A = Perpendicular passed at waypoint - 8. Bearing origin to destination - 9. M = Magnetic, T = True - 10. Destination Waypoint ID - 11. Bearing, present position to Destination - 12. M = Magnetic, T = True - 13. Heading to steer to destination waypoint - 14. M = Magnetic, T = True - 15. Checksum - - Example: $GPAPB,A,A,0.10,R,N,V,V,011,M,DEST,011,M,011,M*82 - */ - APB: { - title: "APB - Autopilot info", - keys: [ - 'navigation.courseGreatCircle.crossTrackError', 'navigation.courseGreatCircle.bearingTrackTrue', 'navigation.courseGreatCircle.nextPoint' - ], - f: function(xte, originToDest, nextPoint) { - return toSentence([ - '$SKAPB', 'A', 'A', Math.abs(xte), xte > 0 - ? 'L' - : 'R', - 'M', - 'V', - 'V', - (originToDest / Math.PI * 180).toFixed(0), - 'T', - '00', - (nextPoint.bearingTrue / Math.PI * 180).toFixed(0), - 'T', - (nextPoint.bearingTrue / Math.PI * 180).toFixed(0), - 'T' - ]); - } - }, - - /* - RMC - Recommended Minimum Navigation Information - This is one of the sentences commonly emitted by GPS units. - - 12 - 1 2 3 4 5 6 7 8 9 10 11| 13 - | | | | | | | | | | | | | - $--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a,m,*hh - Field Number: - 1 UTC Time - 2 Status, V=Navigation receiver warning A=Valid - 3 Latitude - 4 N or S - 5 Longitude - 6 E or W - 7 Speed over ground, knots - 8 Track made good, degrees true - 9 Date, ddmmyy - 10 Magnetic Variation, degrees - 11 E or W - 12 FAA mode indicator (NMEA 2.3 and later) - 13 Checksum - */ - - RMC: { - title: "RMC - GPS recommended minimum", - keys: [ - 'navigation.datetime', 'navigation.speedOverGround', 'navigation.courseOverGroundTrue', 'navigation.position' - ], - f: function(datetime8601, sog, cog, position) { - var datetime = new Date(datetime8601); - var hours = ('00' + datetime.getHours()).slice(-2); - var minutes = ('00' + datetime.getMinutes()).slice(-2); - var seconds = ('00' + datetime.getSeconds()).slice(-2); - return toSentence([ - '$SKRMC', hours + minutes + seconds + '.020', - 'A', - toNmeaDegrees(position.latitude), - position.latitude < 0 ? 'S' : 'N', - toNmeaDegrees(position.longitude), - position.longitude < 0 ? 'W' : 'E', - (sog * 1.94384).toFixed(1), - radsToDeg(cog).toFixed(1), - '0000', - '7.0', - 'E' - ]); - } - }, - - /* - PSILTBS - Proprietary target boat speed sentence for Silva => Nexus => Garmin displays - - - 0 1 2 - | | | - $PSILTBS,XX.xx,N,*hh - Field Number: - 0 Target Boat speed in knots - 1 N for knots - 2 Checksum - */ - - PSILTBS: { - title: "PSILTBS - Send target boat speed to Silva/Nexus/Garmin displays", - keys: [ - 'performance.targetSpeed' - ], - f: function(tbs) { - return toSentence([ - '$PSILTBS', - (tbs * 1.94384).toFixed(1), - 'N' - ]); + function mapToNmea(encoder, name) { + if ( encoder.ttl === undefined) { + encoder.ttl = 5000; // default frequency of dupliate send } - }, - - /* - PSILCD1 - Proprietary polar boat speed sentence for Silva => Nexus => Garmin displays - - - 0 1 2 - | | | - $PSILCD1,XX.xx,YY.yy,*hh - Field Number: - 0 Polar Boat speed in knots - 1 Target wind angle - 2 Checksum - */ - - PSILCD1: { - title: "PSILCD1 - Send polar speed and target wind angle to Silva/Nexus/Garmin displays", - keys: [ - 'performance.polarSpeed', 'performance.targetAngle' - ], - f: function(polarSpeed, targetAngle) { - return toSentence([ - '$PSILCD1', - (polarSpeed * 1.94384).toFixed(2), - (targetAngle / Math.PI * 180).toFixed(0) - ]); + if ( encoder.debounce === undefined) { + encoder.debounce = 2000; } - }, + encoder.nextOutput = 0; + const selfStreams = encoder.keys.map(app.streambundle.getSelfStream, app.streambundle); + // subscribe to the input streams, applying a debounce and checking for duplicates. + // debounce limits the frequency of messages. + // skiDuplicates limits repeat messages within a time period. + // encoder.ttl should be > encoder.debounce. + plugin.unsubscribes.push(Bacon.combineWith(encoder.f, selfStreams).changes(). + debounceImmediate(encoder.debounce). + skipDuplicates(function(before,after) { + var tnow = (new Date()).getTime(); + if ( before === after ) { + if ( encoder.nextOutput > tnow ) { + // console.log("NMEA0183 Encoder",name,"Caught Duplicate ", before); + return true; + } + // console.log("NMEA0183 Encoder",name,"Duplicate sent due to ttl"); + } + encoder.nextOutput = tnow+encoder.ttl; + return false; + + }).onValue(nmeaString => { + //console.log("NMEA0183 Encoder",name," ",nmeaString); + + app.emit('nmea0183out', nmeaString); + })); + } - HDT: { - title: "HDT - Heading True", - keys: [ - 'navigation.headingTrue' - ], - f: function mwv(heading) { - return toSentence([ - '$SKHDT', - radsToDeg(heading).toFixed(1), - 'T' - ]); - } - }, - HDM: { - title: "HDM - Heading Magnetic", - keys: [ - 'navigation.headingMagnetic' - ], - f: function mwv(heading) { - return toSentence([ - '$SKHDM', - radsToDeg(heading).toFixed(1), - 'M' - ]); - } - }, - ROT: { - title: "ROT - Rate of Turn", - keys: [ - 'navigation.rateOfTurn' - ], - f: function mwv(rot) { - var degm = rot * 3437.74677078493 - return toSentence([ - '$SKROT', - degm.toFixed(1), - 'A' - ]); - } - }, - DBK: { - title: "DBK - Depth Below Keel", - keys: [ - 'environment.depth.belowKeel' - ], - f: function mwv(depth) { - var feet = depth * 3.28084 - var fathoms = depth * 0.546807 - return toSentence([ - '$SKDBK', - feet.toFixed(1), - 'f', - depth.toFixed(2), - 'M', - fathoms.toFixed(1), - 'F' - ]); - } - }, + for (var i = plugin.sentences.length - 1; i >= 0; i--) { + var sentence = plugin.sentences[i]; + if ( options[sentence.optionKey]) { + mapToNmea(plugin.sentences[i], sentence.optionKey); + } + }; + } - DBS: { - title: "DBK - Depth Below Surface", - keys: [ - 'environment.depth.belowSurface' - ], - f: function mwv(depth) { - var feet = depth * 3.28084 - var fathoms = depth * 0.546807 - return toSentence([ - '$SKDBS', - feet.toFixed(1), - 'f', - depth.toFixed(2), - 'M', - fathoms.toFixed(1), - 'F' - ]); - } - }, + plugin.stop = function() { + plugin.unsubscribes.forEach(f => f()) + } - DBT: { - title: "DBK - Depth Below Transducer", - keys: [ - 'environment.depth.belowTransducer' - ], - f: function mwv(depth) { - var feet = depth * 3.28084 - var fathoms = depth * 0.546807 - return toSentence([ - '$SKDBT', - feet.toFixed(1), - 'f', - depth.toFixed(2), - 'M', - fathoms.toFixed(1), - 'F' - ]); - } - }, - MTW: { - title: "MTW - Water Temperature", - keys: [ - 'environment.water.temperature' - ], - f: function mwv(temperature) { - var celcius = temperature - 273.15; - return toSentence([ - '$SKMTW', - celcius.toFixed(1), - 'C' - ]); - } - } - }; + plugin.sentences = load_sentences(app, plugin, 'sentences') + plugin.sentences = [].concat.apply([], plugin.sentences) //=========================================================================== - - Object.keys(plugin.sentences).forEach(key => { - var sentence = plugin.sentences[key] - plugin.schema.properties[key] = { + for (var i = plugin.sentences.length - 1; i >= 0; i--) { + var sentence = plugin.sentences[i]; + plugin.schema.properties[sentence.optionKey] = { title: sentence['title'], type: "boolean", default: false } - }); + }; + - return plugin + return plugin; } -function toSentence(parts) { - var base = parts.join(','); - return base + computeChecksum(base); -} -var m_hex = [ - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'A', - 'B', - 'C', - 'D', - 'E', - 'F' -]; - -function computeChecksum(sentence) { - var c1; - var i; - // skip the $ - i = 1; - // init to first character var count; - c1 = sentence.charCodeAt(i); - // process rest of characters, zero delimited - for (i = 2; i < sentence.length; ++i) { - c1 = c1 ^ sentence.charCodeAt(i); - } - return '*' + toHexString(c1); -}; -function toHexString(v) { - var lsn; - var msn; - - msn = (v >> 4) & 0x0f; - lsn = (v >> 0) & 0x0f; - return m_hex[msn] + m_hex[lsn]; -}; - -function radsToDeg(radians) { - return radians * 180 / Math.PI -} - -function padd(n, p, c) -{ - var pad_char = typeof c !== 'undefined' ? c : '0'; - var pad = new Array(1 + p).join(pad_char); - return (pad + n).slice(-pad.length); -} - -function toNmeaDegrees(val) -{ - val = Math.abs(val) - var minutes = Math.floor(val) - var minutes_decimal = val % 1 - minutes_decimal *= 60.0; - return padd(minutes.toFixed(0),2) + padd(minutes_decimal.toFixed(4), 7) -} diff --git a/nmea.js b/nmea.js new file mode 100644 index 0000000..5df1d01 --- /dev/null +++ b/nmea.js @@ -0,0 +1,99 @@ +module.exports = function() { + function toSentence(parts) { + var base = parts.join(','); + return base + computeChecksum(base); + } + var m_hex = [ + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F' + ]; + + function computeChecksum(sentence) { + var c1; + var i; + + // skip the $ + i = 1; + + // init to first character var count; + + c1 = sentence.charCodeAt(i); + + // process rest of characters, zero delimited + for (i = 2; i < sentence.length; ++i) { + c1 = c1 ^ sentence.charCodeAt(i); + } + + return '*' + toHexString(c1); + }; + + function toHexString(v) { + var lsn; + var msn; + + msn = (v >> 4) & 0x0f; + lsn = (v >> 0) & 0x0f; + return m_hex[msn] + m_hex[lsn]; + }; + + function radsToDeg(radians) { + return radians * 180 / Math.PI + } + + function msToKnots(v) { + return v*3600/1852.0; + } + + function msToKM(v) { + return v*3600.0/1000.0; + } + + function mToNm(v) { + return v*0.000539957; + } + + + function padd(n, p, c) + { + var pad_char = typeof c !== 'undefined' ? c : '0'; + var pad = new Array(1 + p).join(pad_char); + return (pad + n).slice(-pad.length); + } + + function toNmeaDegrees(val) + { + val = Math.abs(val) + var minutes = Math.floor(val) + var minutes_decimal = val % 1 + minutes_decimal *= 60.0; + return padd(minutes.toFixed(0),2) + padd(minutes_decimal.toFixed(4), 7) + } + + function fixAngle(d) { + if ( d > Math.PI ) d = d - Math.PI; + if ( d < -Math.PI) d = d + Math.PI; + return d; + } + return { + toSentence: toSentence, + radsToDeg: radsToDeg, + msToKnots: msToKnots, + msToKM: msToKM, + toNmeaDegrees: toNmeaDegrees, + fixAngle: fixAngle + }; +}(); \ No newline at end of file diff --git a/sentences/APB.js b/sentences/APB.js new file mode 100644 index 0000000..769b506 --- /dev/null +++ b/sentences/APB.js @@ -0,0 +1,62 @@ + /* + ------------------------------------------------------------------------------ + 13 15 + 1 2 3 4 5 6 7 8 9 10 11 12| 14| + | | | | | | | | | | | | | | | + $--APB,A,A,x.x,a,N,A,A,x.x,a,c--c,x.x,a,x.x,a*hh + ------------------------------------------------------------------------------ + + Field Number: + + 1. Status + V = LORAN-C Blink or SNR warning + V = general warning flag or other navigation systems when a reliable + fix is not available + 2. Status + V = Loran-C Cycle Lock warning flag + A = OK or not used + 3. Cross Track Error Magnitude + 4. Direction to steer, L or R + 5. Cross Track Units, N = Nautical Miles + 6. Status + A = Arrival Circle Entered + 7. Status + A = Perpendicular passed at waypoint + 8. Bearing origin to destination + 9. M = Magnetic, T = True + 10. Destination Waypoint ID + 11. Bearing, present position to Destination + 12. M = Magnetic, T = True + 13. Heading to steer to destination waypoint + 14. M = Magnetic, T = True + 15. Checksum + + Example: $GPAPB,A,A,0.10,R,N,V,V,011,M,DEST,011,M,011,M*82 + */ +// to verify +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "APB - Autopilot info", + keys: [ + 'navigation.courseGreatCircle.crossTrackError', 'navigation.courseGreatCircle.bearingTrackTrue', 'navigation.courseGreatCircle.nextPoint' + ], + f: function(xte, originToDest, nextPoint) { + return nmea.toSentence([ + '$SKAPB', 'A', 'A', Math.abs(xte), xte > 0 + ? 'L' + : 'R', + 'M', + 'V', + 'V', + nmea.radsToDeg(originToDest).toFixed(0), + 'T', + '00', + nmea.radsToDeg(nextPoint.bearingTrue).toFixed(0), + 'T', + nmea.radsToDeg(nextPoint.bearingMagnetic).toFixed(0), + 'M' + ]); + } + }; +} diff --git a/sentences/DBK.js b/sentences/DBK.js new file mode 100644 index 0000000..5b25385 --- /dev/null +++ b/sentences/DBK.js @@ -0,0 +1,23 @@ +// NMEA0183 Encoder DBK $IIDBK,102.9,f,31.38,M,17.2,F*39 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "DBK - Depth Below Keel", + keys: [ + 'environment.depth.belowKeel' + ], + f: function mwv(depth) { + var feet = depth * 3.28084 + var fathoms = depth * 0.546807 + return nmea.toSentence([ + '$IIDBK', + feet.toFixed(1), + 'f', + depth.toFixed(2), + 'M', + fathoms.toFixed(1), + 'F' + ]); + } + }; +} diff --git a/sentences/DBS.js b/sentences/DBS.js new file mode 100644 index 0000000..1db7298 --- /dev/null +++ b/sentences/DBS.js @@ -0,0 +1,23 @@ +// to verify +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "DBS - Depth Below Surface", + keys: [ + 'environment.depth.belowSurface' + ], + f: function mwv(depth) { + var feet = depth * 3.28084 + var fathoms = depth * 0.546807 + return nmea.toSentence([ + '$IIDBS', + feet.toFixed(1), + 'f', + depth.toFixed(2), + 'M', + fathoms.toFixed(1), + 'F' + ]); + } + }; +} diff --git a/sentences/DBT.js b/sentences/DBT.js new file mode 100644 index 0000000..a97faf1 --- /dev/null +++ b/sentences/DBT.js @@ -0,0 +1,23 @@ +// NMEA0183 Encoder DBT $IIDBT,103.0,f,31.38,M,17.2,F*2E +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "DBT - Depth Below Transducer", + keys: [ + 'environment.depth.belowTransducer' + ], + f: function mwv(depth) { + var feet = depth * 3.28084 + var fathoms = depth * 0.546807 + return nmea.toSentence([ + '$IIDBT', + feet.toFixed(1), + 'f', + depth.toFixed(2), + 'M', + fathoms.toFixed(1), + 'F' + ]); + } + }; +}; diff --git a/sentences/DPT.js b/sentences/DPT.js new file mode 100644 index 0000000..f135363 --- /dev/null +++ b/sentences/DPT.js @@ -0,0 +1,28 @@ + + /** +Depth: +$IIDPT,x.x,x.x,,*hh + I I_Sensor offset, >0 = surface transducer distance, >0 = keel transducer distance. + I_Bottom transducer distance + + + + */ +// NMEA0183 Encoder DPT $IIDPT,69.21,-0.001*60 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "DPT - Depth", + keys: [ + 'environment.depth.belowTransducer', 'environment.depth.transducerToKeel' + ], + f: function dpt(belowTransducer, transducerToKeel) { + return nmea.toSentence([ + '$IIDPT', + belowTransducer.toFixed(2), + transducerToKeel.toFixed(3) + ]); + } + }; +} + diff --git a/sentences/GLL.js b/sentences/GLL.js new file mode 100644 index 0000000..d29e157 --- /dev/null +++ b/sentences/GLL.js @@ -0,0 +1,37 @@ + + + + /* +Geographical position, latitude and longitude: +$IIGLL,IIII.II,a,yyyyy.yy,a,hhmmss.ss,A,A*hh + I I I I I I_Statut, A= valid data, V= non valid data + I I I I I_UTC time + I I I___ I_Longitude, E/W + I__I_Latidude, N/S +*/ +// NMEA0183 Encoder GLL $IIGLL,5943.4970,N,2444.1983,E,200001.020,A*16 + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "GLL - Geographical position, latitude and longitude", + keys: [ + 'navigation.datetime', 'navigation.position' + ], + f: function gll(datetime8601, position) { + var datetime = new Date(datetime8601); + var hours = ('00' + datetime.getHours()).slice(-2); + var minutes = ('00' + datetime.getMinutes()).slice(-2); + var seconds = ('00' + datetime.getSeconds()).slice(-2); + return nmea.toSentence([ + '$IIGLL', + nmea.toNmeaDegrees(position.latitude), + position.latitude < 0 ? 'S' : 'N', + nmea.toNmeaDegrees(position.longitude), + position.longitude < 0 ? 'W' : 'E', + hours + minutes + seconds + '.020', + 'A' + ]); + } + }; +} diff --git a/sentences/HDG.js b/sentences/HDG.js new file mode 100644 index 0000000..7a378ed --- /dev/null +++ b/sentences/HDG.js @@ -0,0 +1,29 @@ + + + +/* +Heading magnetic: +$IIHDG,x.x,,,,*hh + I_Heading magnetic + */ +// NMEA0183 Encoder HDG $IIHDG,206.71,,,,*7B + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "HDG - Heading magnetic:.", + keys: [ + 'navigation.headingMagnetic' + ], + f: function hdg(headingMagnetic) { + return nmea.toSentence([ + '$IIHDG', + nmea.radsToDeg(headingMagnetic).toFixed(2), + '', + '', + '', + '' + ]); + } + }; +} \ No newline at end of file diff --git a/sentences/HDM.js b/sentences/HDM.js new file mode 100644 index 0000000..f56fe5f --- /dev/null +++ b/sentences/HDM.js @@ -0,0 +1,18 @@ +// NMEA0183 Encoder HDM $IIHDM,206.7,M*21 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "HDM - Heading Magnetic", + keys: [ + 'navigation.headingMagnetic' + ], + f: function mwv(heading) { + return nmea.toSentence([ + '$IIHDM', + nmea.radsToDeg(heading).toFixed(1), + 'M' + ]); + } + }; +} + diff --git a/sentences/HDMC.js b/sentences/HDMC.js new file mode 100644 index 0000000..60b192a --- /dev/null +++ b/sentences/HDMC.js @@ -0,0 +1,18 @@ +// NMEA0183 Encoder HDMC $IIHDM,212.2,M*21 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "HDM - Heading Magnetic, calculated from True", + keys: [ + 'navigation.headingTrue', 'navigation.magneticVariation' + ], + f: function mwv(headingTrue, magneticVariation) { + var heading = headingTrue + magneticVariation; + return nmea.toSentence([ + '$IIHDM', + nmea.radsToDeg(heading).toFixed(1), + 'M' + ]); + } + }; +} diff --git a/sentences/HDT.js b/sentences/HDT.js new file mode 100644 index 0000000..31890c9 --- /dev/null +++ b/sentences/HDT.js @@ -0,0 +1,20 @@ + +//NMEA0183 Encoder HDT $IIHDT,200.1,T*21 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "HDT - Heading True", + keys: [ + 'navigation.headingTrue' + ], + f: function mwv(heading) { + return nmea.toSentence([ + '$IIHDT', + nmea.radsToDeg(heading).toFixed(1), + 'T' + ]); + } + }; +} + + diff --git a/sentences/MMB.js b/sentences/MMB.js new file mode 100644 index 0000000..cc490b9 --- /dev/null +++ b/sentences/MMB.js @@ -0,0 +1,28 @@ + + +/* +Barometer: +$IIMMB,x.x,I,x.x,B*hh + I I I__I_Atmospheric pressure in bars + I_ I_Atmospheric pressure in inches of mercury + */ +// $IIMMB,29.6776,I,1.00,B*73 + const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "MMB - Environment outside pressure", + keys: [ + 'environment.outside.pressure' + ], + f: function hdg(pressure) { + //console.log("Got MMB--------------------------"); + return nmea.toSentence([ + '$IIMMB', + (pressure/3386.39).toFixed(4), + 'I', + (pressure/1.0E5).toFixed(4), + 'B' + ]); + } + }; +} \ No newline at end of file diff --git a/sentences/MTA.js b/sentences/MTA.js new file mode 100644 index 0000000..b9e6a0e --- /dev/null +++ b/sentences/MTA.js @@ -0,0 +1,25 @@ +/* +Air temperature: +$IIMTA,x.x,C*hh + I__I_Temperature in degrees C + */ +// $IIMTA,34.80,C*3A + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "MTA - Air temperature.", + keys: [ + 'environment.outside.temperature' + ], + f: function mta(temperature) { + //console.log("Got MTA--------------------------"); + var celcius = temperature - 273.15; + return nmea.toSentence([ + '$IIMTA', + celcius.toFixed(2), + 'C' + ]); + } + }; +} diff --git a/sentences/MTW.js b/sentences/MTW.js new file mode 100644 index 0000000..09d9cd5 --- /dev/null +++ b/sentences/MTW.js @@ -0,0 +1,20 @@ + + +// NMEA0183 Encoder MTW $IIMTW,40.0,C*17 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "MTW - Water Temperature", + keys: [ + 'environment.water.temperature' + ], + f: function mwv(temperature) { + var celcius = temperature - 273.15; + return nmea.toSentence([ + '$IIMTW', + celcius.toFixed(1), + 'C' + ]); + } + }; +} \ No newline at end of file diff --git a/sentences/MWD.js b/sentences/MWD.js new file mode 100644 index 0000000..96d312e --- /dev/null +++ b/sentences/MWD.js @@ -0,0 +1,38 @@ + + + + /** +True wind direction and speed: +$IIMWD,x.x,T,x.x,M,x.x,N,x.x,M*hh + I I I I I I I__I_Wind speed in m/s + I I I I I__I_ Wind speed in knots + I I I__I_Wind direction from 0° to 359° magnetic + I__I_Wind direction from 0° to 359° true + + speed Might be ground speed. + */ + +// NMEA0183 Encoder MWD $IIMWD,279.07,T,90.97,M,9.75,N,5.02,M*74 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "MWD - Wind relative to North, speed might be ground speed.", + keys: [ + 'environment.wind.directionTrue', 'navigation.magneticVariation', 'environment.wind.speedTrue' + ], + f: function mwd(directionTrue, magneticVariation, speedTrue) { + var directionMagnetic = nmea.fixAngle(directionTrue - magneticVariation); + return nmea.toSentence([ + '$IIMWD', + nmea.radsToDeg(directionTrue).toFixed(2), + 'T', + nmea.radsToDeg(directionMagnetic).toFixed(2), + 'M', + nmea.msToKnots(speedTrue).toFixed(2), + 'N', + speedTrue.toFixed(2), + 'M' + ]); + } + }; +} diff --git a/sentences/MWVR.js b/sentences/MWVR.js new file mode 100644 index 0000000..fcc3ce4 --- /dev/null +++ b/sentences/MWVR.js @@ -0,0 +1,39 @@ + /* + === MWV - Wind Speed and Angle === + + ------------------------------------------------------------------------------ + 1 2 3 4 5 + | | | | | + $--MWV,x.x,a,x.x,a*hh + ------------------------------------------------------------------------------ + + Field Number: + + 1. Wind Angle, 0 to 360 degrees + 2. Reference, R = Relative, T = True + 3. Wind Speed + 4. Wind Speed Units, K/M/N + 5. Status, A = Data Valid + 6. Checksum + */ + +// NMEA0183 Encoder MWVR $INMWV,35.01,R,7.9,M,A*30 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "MWV - Aparent Wind heading and speed", + keys: [ + 'environment.wind.angleApparent', 'environment.wind.speedApparent' + ], + f: function mwv(angle, speed) { + return nmea.toSentence([ + '$INMWV', + nmea.radsToDeg(angle).toFixed(2), + 'R', + speed.toFixed(2), + 'M', + 'A' + ]); + } + }; +} \ No newline at end of file diff --git a/sentences/MWVT.js b/sentences/MWVT.js new file mode 100644 index 0000000..f60fc2d --- /dev/null +++ b/sentences/MWVT.js @@ -0,0 +1,24 @@ + + +//NMEA0183 Encoder MWVTCB $INMWV,61.44,T,6.04,M,A*0A + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "MWV - True Wind heading and speed", + keys: [ + 'environment.wind.angleTrue', 'environment.wind.speedTrue' + ], + + f: function mwv(angle, speed) { + return nmea.toSentence([ + '$INMWV', + nmea.radsToDeg(angle).toFixed(2), + 'T', + speed.toFixed(2), + 'M', + 'A' + ]); + } + }; +} diff --git a/sentences/PNKEP01.js b/sentences/PNKEP01.js new file mode 100644 index 0000000..0d33ade --- /dev/null +++ b/sentences/PNKEP01.js @@ -0,0 +1,39 @@ + +/* +Man over board: +$TRWPL,,,,,MOB,*hh + I_Name of the WP +$PMLR,05,01,02,037,*hh (this phrase launches the “MOB” procedure on compatible MLR GPS). + I I I I_Checksum + I I I_Data bytes (02= MOB key of the GPS) + I I_Number of data bytes (01 = only 1 data byte) + I_Type of phrase (05 = simulating key pressing on the keyboard) +*/ +/* + Sentence 1 +$PNKEP,01,x.x,N,x.x,K*hh + | STW target in knots +| STW target in km/h +*/ + +// $PNKEP,01,3.69,N,6.83,K*69 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "PNKEP,01 - Target Polar speed", + keys: [ + 'performance.polarSpeed' + ], + f: function pnkep1(polarSpeed) { + //console.log("Got Polar speed --------------------------------------------------"); + return nmea.toSentence([ + '$PNKEP', + '01', + nmea.msToKnots(polarSpeed).toFixed(2), + 'N', + nmea.msToKM(polarSpeed).toFixed(2), + 'K' + ]); + } + }; +} diff --git a/sentences/PNKEP02.js b/sentences/PNKEP02.js new file mode 100644 index 0000000..5d08e1a --- /dev/null +++ b/sentences/PNKEP02.js @@ -0,0 +1,25 @@ + + +/** +$PNKEP,02,x.x*hh + \ Course (COG) on other tack from 0 to 359° +*/ +// to verify +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "PNKEP,02 - Course (COG) on other tack from 0 to 359°", + keys: [ + 'performance.tackMagnetic' + ], + f: function pnkep2(tackMagnetic) { + //console.log("Got tackMagnetic --------------------------------------------------"); + + return nmea.toSentence([ + '$PNKEP', + '02', + nmea.radsToDeg(tackMagnetic).toFixed(2) + ]); + } + }; +} \ No newline at end of file diff --git a/sentences/PNKEP03.js b/sentences/PNKEP03.js new file mode 100644 index 0000000..7c29994 --- /dev/null +++ b/sentences/PNKEP03.js @@ -0,0 +1,29 @@ + +/* +Sentence 3 +$PNKEP,03,x.x,x.x,x.x*hh + | optimum angle from 0 to 359° + | VMG efficiency up/down wind in % + | Polar efficiency in % + +*/ + +// to verify +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "PNKEP,03 - Polar and VMG, and optimum angle.", + keys: [ + 'performance.targetAngle', 'performance.polarVelocityMadeGoodRatio', 'performance.polarSpeedRatio' + ], + f: function pnkep2(targetAngle, polarVelocityMadeGoodRatio, polarSpeedRatio) { + return nmea.toSentence([ + '$PNKEP', + '03', + nmea.radsToDeg(targetAngle).toFixed(2), + (polarVelocityMadeGoodRatio*100.0).toFixed(2), + (polarSpeedRatio*100.0).toFixed(2) + ]); + } + }; +} \ No newline at end of file diff --git a/sentences/PNKEP99.js b/sentences/PNKEP99.js new file mode 100644 index 0000000..2f70982 --- /dev/null +++ b/sentences/PNKEP99.js @@ -0,0 +1,29 @@ + +/** test */ + +// to verify +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "PNKEP,99 - Debug", + keys: [ + 'environment.wind.angleApparent', 'environment.wind.speedApparent', + 'environment.wind.angleTrue', 'environment.wind.speedTrue', + 'navigation.speedThroughWater', 'performance.polarSpeed', 'performance.polarSpeedRatio' + ], + f: function pnkep1(angleApparent, speedApparent, angleTrueWater, speedTrue, speedThroughWater, polarSpeed, polarSpeedRatio) { + //console.log("Got Polar speed --------------------------------------------------"); + return nmea.toSentence([ + '$PNKEP', + '99', + nmea.radsToDeg(angleApparent), + nmea.msToKnots(speedApparent), + nmea.radsToDeg(angleTrueWater), + nmea.msToKnots(speedTrue), + nmea.msToKnots(speedThroughWater), + nmea.msToKnots(polarSpeed), + polarSpeedRatio + ]); + } + }; +} diff --git a/sentences/RMB.js b/sentences/RMB.js new file mode 100644 index 0000000..c865ec7 --- /dev/null +++ b/sentences/RMB.js @@ -0,0 +1,39 @@ + + + /* +Heading and distance to waypoint: +$IIRMB,A,x.x,a,,,IIII.II,a,yyyyy.yy,a,x.x,x.x,x.x,A,a*hh + I I I I I I I I I_Speed to WP in knots + I I I I I I I I_True heading to destination in degrees + I I I I I I I_Distance to destination in miles + I I I I I_ ___ I_Longitude of the WP to destination, E/W + I I I__ I_Latidude of the WP to destination, N/S + I I_Direction of cross-track error, L/R + I_Distance of cross-track error in miles +*/ +// to verify +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "RMB - Heading and distance to waypoint", + keys: [ + 'navigation.courseRhumbline.crossTrackError', 'resources.waypoints.next.position.latitude', 'resources.waypoints.next.position.longitude', + 'navigation.courseRhumbline.nextPoint.distance', 'navigation.courseRhumbline.bearingTrue' + ], + f: function gll(crossTrackError,wpLatitude, wpLongitude, wpDistance, bearingTrue) { + return nmea.toSentence([ + '$IIRMB', + crossTrackError.toFixed(2), + crossTrackError<0?'R':'L', + nmea.toNmeaDegrees(wpLatitude), + wpLatitude<0?'S':'N', + nmea.toNmeaDegrees(wpLongitude), + wpLongitude<0?'W':'E', + wpDistance.toFixed(2), + nmea.radsToDeg(bearingTrue).toFixed(2), + 'V', // dont set the arrival flag as it will set of alarms. + '' + ]); + } + }; +} diff --git a/sentences/RMC.js b/sentences/RMC.js new file mode 100644 index 0000000..d957e42 --- /dev/null +++ b/sentences/RMC.js @@ -0,0 +1,63 @@ + + /* + RMC - Recommended Minimum Navigation Information + This is one of the sentences commonly emitted by GPS units. + + 12 + 1 2 3 4 5 6 7 8 9 10 11| 13 + | | | | | | | | | | | | | + $--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a,m,*hh + Field Number: + 1 UTC Time + 2 Status, V=Navigation receiver warning A=Valid + 3 Latitude + 4 N or S + 5 Longitude + 6 E or W + 7 Speed over ground, knots + 8 Track made good, degrees true + 9 Date, ddmmyy + 10 Magnetic Variation, degrees + 11 E or W + 12 FAA mode indicator (NMEA 2.3 and later) + 13 Checksum + */ + // This needs to run faster that others. + +// NMEA0183 Encoder RMC $INRMC,200152.020,A,5943.2980,N,2444.1043,E,6.71,194.30,0000,8.1,E*40 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "RMC - GPS recommended minimum", + keys: [ + 'navigation.datetime', 'navigation.speedOverGround', 'navigation.courseOverGroundTrue', 'navigation.position', 'navigation.magneticVariation' + ], + f: function(datetime8601, sog, cog, position, variation) { + var datetime = new Date(datetime8601); + var hours = ('00' + datetime.getHours()).slice(-2); + var minutes = ('00' + datetime.getMinutes()).slice(-2); + var seconds = ('00' + datetime.getSeconds()).slice(-2); + var variationDir = 'E' + if (variation < 0 ) { + variationDir = 'W'; + variation = -variation; + } else if ( variation > Math.PI/2) { + variationDir = 'W'; + variation = variation-Math.PI; + } + return nmea.toSentence([ + '$INRMC', hours + minutes + seconds + '.020', + 'A', + nmea.toNmeaDegrees(position.latitude), + position.latitude < 0 ? 'S' : 'N', + nmea.toNmeaDegrees(position.longitude), + position.longitude < 0 ? 'W' : 'E', + (sog * 1.94384).toFixed(2), + nmea.radsToDeg(cog).toFixed(2), + '0000', + nmea.radsToDeg(variation).toFixed(2), + variationDir + ]); + } + }; +} diff --git a/sentences/ROT.js b/sentences/ROT.js new file mode 100644 index 0000000..6f81bb0 --- /dev/null +++ b/sentences/ROT.js @@ -0,0 +1,19 @@ +// to verify + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "ROT - Rate of Turn", + keys: [ + 'navigation.rateOfTurn' + ], + f: function mwv(rot) { + var degm = rot * 3437.74677078493 + return nmea.toSentence([ + '$SKROT', + degm.toFixed(2), + 'A' + ]); + } + }; +} diff --git a/sentences/TODO/PNKEP04.js b/sentences/TODO/PNKEP04.js new file mode 100644 index 0000000..1ee8991 --- /dev/null +++ b/sentences/TODO/PNKEP04.js @@ -0,0 +1,14 @@ +/* +$PNKEP,04 Angles to optimise the CMG and VMG and +ANGLE_OPT_CMG, ANGLE_OPT_VMG, +GAIN_ROUTE_CMG, GAIN_ROUTE_VMG. + +From OpenCPN needs verification. +$PNKEP,04,x.x,x.x,x.x,x.x*hh + | | | \ Gain VMG from 0 to 999% + \ \ \ Angle to optimise VMG from 0 to 359° + \ \ Gain CMG from 0 to 999% + \ Angle to optimise CMG from 0 to 359° + + +*/ diff --git a/sentences/TODO/PNKEP05.js b/sentences/TODO/PNKEP05.js new file mode 100644 index 0000000..d8ffe5f --- /dev/null +++ b/sentences/TODO/PNKEP05.js @@ -0,0 +1,17 @@ + +/* +Sentence 5 +Current direction and speed from the atlas +$PNKEP,05,x.x,x.x,N,x.x,K*hh + |Current direction from 0 to 359° + | Current speed in Knots + | Current speed in km/h + + DIREC_COURANT, VITES_COURANT. + +From OpenCPN + $PNKEP,05,x.x,x.x,N,x.x,K*hh + | \ \current speed in km/h + \ \ current speed in knots + \ current direction from 0 à 359° +*/ diff --git a/sentences/TODO/PNKEP11.js b/sentences/TODO/PNKEP11.js new file mode 100644 index 0000000..8137629 --- /dev/null +++ b/sentences/TODO/PNKEP11.js @@ -0,0 +1,8 @@ +/* +Battery 1 +$PNKEP,11,xx.x,x.xx,xx.x,xx.x*hh + | | | |_battery level % + | | |_used capacity + | |_current + |_voltage +*/ diff --git a/sentences/TODO/PNKEP12.js b/sentences/TODO/PNKEP12.js new file mode 100644 index 0000000..b73d67d --- /dev/null +++ b/sentences/TODO/PNKEP12.js @@ -0,0 +1,6 @@ + +/* +Battery 2 +$PNKEP,12,xx.x,,,*hh + |_voltage +*/ diff --git a/sentences/TODO/TODO.js b/sentences/TODO/TODO.js new file mode 100644 index 0000000..fa270f4 --- /dev/null +++ b/sentences/TODO/TODO.js @@ -0,0 +1,29 @@ + + + +/** + +TODO: + +$INGGA … Global Positioning System Fix Data +$INXDR …,N,x.x,N,FRST … Forestay +$INXDR …,A,x.x,D,ROLL … Heel angle +$INXDR ...,H,x.x,P,HYGR … Humidity +$INXDR …,A,x.x,D,KEEL … Keel Angle +$INXDR …,A,x.x,D,LEEW … Leeway angle +$INRSA … Rudder angle +$INVDR … Set and Drift +$INVPW … VMG +$INWCV … Waypoint closure velocity +$IIXDR Batteries voltage 1 Hz + + +GPS +$GPGGA GPS Fix Data 10 Hz +$GPGSA GNSS DOP and Active Satellites 1 Hz +$GPGSV GNSS Satellites in View 1 Hz +$IIXDR Internal temperature 1 Hz + + + +*/ \ No newline at end of file diff --git a/sentences/TODO/XDRHeel.js b/sentences/TODO/XDRHeel.js new file mode 100644 index 0000000..ac087a2 --- /dev/null +++ b/sentences/TODO/XDRHeel.js @@ -0,0 +1,3 @@ +/* +$IIXDR,A,2.5,D,Heel Angle*hh from http://www.cruisersforum.com/forums/f134/tactics-plugin-166909-20.html +*/ diff --git a/sentences/TODO/XDRMast.js b/sentences/TODO/XDRMast.js new file mode 100644 index 0000000..2bf9a99 --- /dev/null +++ b/sentences/TODO/XDRMast.js @@ -0,0 +1,5 @@ +/* +Mast angle: +$IIXDR,A,x.x,D,mastangle,*hh + I_Measurement of the mast angle in degrees +*/ diff --git a/sentences/TODO/sent.js b/sentences/TODO/sent.js new file mode 100644 index 0000000..e812f62 --- /dev/null +++ b/sentences/TODO/sent.js @@ -0,0 +1,9 @@ + plugin.sentences = { + + + + + + + + }; \ No newline at end of file diff --git a/sentences/VHW.js b/sentences/VHW.js new file mode 100644 index 0000000..9edbe11 --- /dev/null +++ b/sentences/VHW.js @@ -0,0 +1,42 @@ + + +/** +$IIVHW,x .x,T,x.x,M,x.x,N,x.x,K*hh + I I I I I I I__I_Surface speed in kph + I I I I I__I_Surface speed in knots + I I I__I_Magnetic compass heading + I__I_True compass heading + */ + +// NMEA0183 Encoder VHW $IIVHW,201.1,T,209.2,M,6.5,N,12.0,K*6E + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "VHW - Speed and direction", + keys: [ + 'navigation.headingTrue', 'navigation.magneticVariation', 'navigation.speedThroughWater' + ], + f: function vhw(headingTrue, magneticVariation, speedThroughWater) { + var headingMagnetic = headingTrue+magneticVariation; + if ( headingMagnetic > Math.PI*2) { + headingMagnetic -= Math.PI*2; + } + if ( headingMagnetic < 0 ) { + headingMagnetic += Math.PI*2; + } + return nmea.toSentence([ + '$IIVHW', + nmea.radsToDeg(headingTrue).toFixed(1), + 'T', + nmea.radsToDeg(headingMagnetic).toFixed(1), + 'M', + nmea.msToKnots(speedThroughWater).toFixed(2), + 'N', + nmea.msToKM(speedThroughWater).toFixed(2), + 'K' + ]); + } + }; +} + diff --git a/sentences/VLW.js b/sentences/VLW.js new file mode 100644 index 0000000..07cac99 --- /dev/null +++ b/sentences/VLW.js @@ -0,0 +1,26 @@ +/** +Total log and daily log: +$IIVLW,x.x,N,x.x,N*hh + I I I__I_Daily log in miles + I__I_Total log in miles + */ +// NMEA0183 Encoder VLW $IIVLW,9417.40,N,43.18,N*4C + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "VLW - Total log and daily log", + keys: [ + 'navigation.log', 'navigation.logTrip' + ], + f: function vhw(logDistance, tripDistance) { + return toSentence([ + '$IIVLW', + nmea.mToNm(logDistance).toFixed(2), + 'N', + nmea.mToNm(tripDistance).toFixed(2), + 'N' + ]); + } + }; +} diff --git a/sentences/VTG.js b/sentences/VTG.js new file mode 100644 index 0000000..a2fde7f --- /dev/null +++ b/sentences/VTG.js @@ -0,0 +1,34 @@ + + +/* +Bottom heading and speed: +$IIVTG,x.x,T,x.x,M,x.x,N,x.x,K,A*hh + I I I I I I I__I_Bottom speed in kph + I I I I I__I_Bottom speed in knots + I I I__I_Magnetic bottom heading + I__ I_True bottom heading + */ +// NMEA0183 Encoder VTG $IIVTG,224.17,T,224.17,M,12.95,N,23.98,K,A*3B +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "VTG - Track made good and Ground Speed (COG,SOG)", + keys: [ + 'navigation.courseOverGroundMagnetic', 'navigation.courseOverGroundTrue', 'navigation.speedOverGround' + ], + f: function gll(courseOverGroundMagnetic, courseOverGroundTrue, speedOverGround) { + return nmea.toSentence([ + '$IIVTG', + nmea.radsToDeg(courseOverGroundTrue).toFixed(2), + 'T', + nmea.radsToDeg(courseOverGroundMagnetic).toFixed(2), + 'M', + nmea.msToKnots(speedOverGround).toFixed(2), + 'N', + nmea.msToKM(speedOverGround).toFixed(2), + 'K', + 'A' + ]); + } + }; +} diff --git a/sentences/VWR.js b/sentences/VWR.js new file mode 100644 index 0000000..d744605 --- /dev/null +++ b/sentences/VWR.js @@ -0,0 +1,40 @@ + + /** +Apparent wind angle and speed: +$IIVWR,x.x,a,x.x,N,x.x,M,x.x,K*hh + I I I I I I I__I_Wind speed in kph + I I I I I__I_Wind speed in m/s + I I I__I_Wind speed in knots + I__I_Apparent wind angle from 0° to 180°, L=port, R=starboard + */ + +// NMEA0183 Encoder VWR $IIVWR,42.01,R,14.11,N,7.26,M,26.14,K*75 +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + optionKey: 'VWR', + title: "VWR - Apparent wind angle and speed", + keys: [ + 'environment.wind.speedApparent', 'environment.wind.angleApparent' + ], + f: function vwr(speedApparent, angleApparent) { + var windDirection = 'R' + if ( angleApparent < 0) { + angleApparent = -angleApparent; + windDirection = 'L'; + } + return nmea.toSentence([ + '$IIVWR', + nmea.radsToDeg(angleApparent).toFixed(2), + windDirection, + nmea.msToKnots(speedApparent).toFixed(2), + 'N', + speedApparent.toFixed(2), + 'M', + nmea.msToKM(speedApparent).toFixed(2), + 'K' + ]); + } + }; +} + diff --git a/sentences/VWT.js b/sentences/VWT.js new file mode 100644 index 0000000..9a3b58d --- /dev/null +++ b/sentences/VWT.js @@ -0,0 +1,32 @@ +/** +$IIVWT,x.x,a,x.x,N,x.x,M,x.x,K*hh + I I I I I I I__I_Wind speed in kph + I I I I I__I_Wind speed in m/s + I I I_ I_Wind speed in knots + I__I_True wind angle from 0° to 180° , L=port, R=starboard + */ + +// NMEA0183 Encoder VWT $IIVWT,86.71,a,12.58,N,6.47,M,23.29,K*45 + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "VWT - True wind speed relative to boat.", + keys: [ + 'environment.wind.angleTrue', 'environment.wind.speedTrue' + ], + f: function mwd(angleTrueWater, speedTrue) { + return nmea.toSentence([ + '$IIVWT', + nmea.radsToDeg(angleTrueWater).toFixed(2), + 'a', + nmea.msToKnots(speedTrue).toFixed(2), + 'N', + speedTrue.toFixed(2), + 'M', + nmea.msToKM(speedTrue).toFixed(2), + 'K' + ]); + } + }; +} diff --git a/sentences/XDRBaro.js b/sentences/XDRBaro.js new file mode 100644 index 0000000..b1f0b4f --- /dev/null +++ b/sentences/XDRBaro.js @@ -0,0 +1,25 @@ + + +/** + $IIXDR,P,1.02481,B,Barometer*0D +*/ +// $IIXDR,P,1.0050,B,Barometer*13 + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "XDR (Barometer) - Atomospheric Pressure", + keys: [ + 'environment.outside.pressure' + ], + f: function xdrbaro(pressure) { + return nmea.toSentence([ + '$IIXDR', + 'P', + (pressure/1.0E5).toFixed(4), + 'B', + 'Barometer' + ]); + } + }; +} diff --git a/sentences/XDRTemp.js b/sentences/XDRTemp.js new file mode 100644 index 0000000..f914a13 --- /dev/null +++ b/sentences/XDRTemp.js @@ -0,0 +1,25 @@ +/* + $IIXDR,C,19.52,C,TempAir*3D +*/ +// $IIXDR,C,34.80,C,TempAir*19 + + +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "XDR (TempAir) - Air temperature.", + keys: [ + 'environment.outside.temperature' + ], + f: function XDRTemp(temperature) { + var celcius = temperature - 273.15; + return nmea.toSentence([ + '$IIXDR', + 'C', + celcius.toFixed(2), + 'C', + 'TempAir' + ]); + } + }; +} diff --git a/sentences/XTE.js b/sentences/XTE.js new file mode 100644 index 0000000..744c4ef --- /dev/null +++ b/sentences/XTE.js @@ -0,0 +1,26 @@ + + /* +Cross-track error: +$IIXTE,A,A,x.x,a,N,A*hh + I_Cross-track error in miles, L= left, R= right + */ +// to verify +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "XTE - Cross-track error", + keys: [ + 'navigation.courseRhumbline.crossTrackError' + ], + f: function gll(crossTrackError) { + return nmea.toSentence([ + '$IIXTE', + 'A', + 'A', + crossTrackError.toFixed(3), + crossTrackError<0?'R':'L', + 'N' + ]); + } + }; +} diff --git a/sentences/ZDA.js b/sentences/ZDA.js new file mode 100644 index 0000000..816972c --- /dev/null +++ b/sentences/ZDA.js @@ -0,0 +1,37 @@ + +/* +UTC time and date: +$IIZDA,hhmmss.ss,xx,xx,xxxx,,*hh + I I I I_Year + I I I_Month + I I_Day + I_Time + */ +// NMEA0183 Encoder ZDA $IIZDA,200006.020,15,08,2014,,*4C +const nmea = require('../nmea.js'); +module.exports = function(app) { + return { + title: "ZDA - UTC time and date", + keys: [ + 'navigation.datetime' + ], + f: function zda(datetime8601) { + var datetime = new Date(datetime8601); + var hours = ('00' + datetime.getHours()).slice(-2); + var minutes = ('00' + datetime.getMinutes()).slice(-2); + var seconds = ('00' + datetime.getSeconds()).slice(-2); + var day = ('00' + datetime.getUTCDate()).slice(-2); + var month = ('00' + (datetime.getUTCMonth()+1)).slice(-2); + return nmea.toSentence([ + '$IIZDA', + hours + minutes + seconds + '.020', + day, + month, + datetime.getUTCFullYear(), + '', + '' + ]); + } + }; +} +