New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

nmea0183-signalk

Package Overview
Dependencies
Maintainers
3
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nmea0183-signalk - npm Package Compare versions

Comparing version 0.2.3 to 0.3.0

codecs/DSC.js

18

codecs/__GBS.js

@@ -0,1 +1,19 @@

/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** AIS? **/
/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
GSA - GPS DOP and active satellites

@@ -3,0 +20,0 @@

/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
GSV - Satellites in view

@@ -3,0 +20,0 @@

19

codecs/_bwc.js

@@ -1,11 +0,4 @@

/*
* BWC codec
/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* @repository https://github.com/signalk/nmea-signalk
* @author Fabian Tollenaar <fabian@starting-point.nl>
*
*
*
* Copyright 2014, Fabian Tollenaar
*
* Licensed under the Apache License, Version 2.0 (the "License");

@@ -22,2 +15,10 @@ * you may not use this file except in compliance with the License.

* limitations under the License.
*/
/*
* BWC codec
*
* @repository https://github.com/signalk/nmea-signalk
* @author Fabian Tollenaar <fabian@starting-point.nl>
*

@@ -24,0 +25,0 @@ */

@@ -1,11 +0,4 @@

/*
* ABT codec
/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* @repository https://github.com/signalk/nmea-signalk
* @author Fabian Tollenaar <fabian@starting-point.nl>
*
*
*
* Copyright 2014, Fabian Tollenaar
*
* Licensed under the Apache License, Version 2.0 (the "License");

@@ -22,2 +15,11 @@ * you may not use this file except in compliance with the License.

* limitations under the License.
*/
/*
* ABT codec
*
* @repository https://github.com/signalk/nmea-signalk
* @author Fabian Tollenaar <fabian@starting-point.nl>
*

@@ -34,3 +36,3 @@ */

where:
APB Autopilot format B
APB Autopilot format B
0 A Loran-C blink/SNR warning, general warning

@@ -45,5 +47,5 @@ 1 A Loran-C cycle warning

9 DEST destination waypoint ID
10,11 011,M magnetic bearing, present position to destination
12,13 011,M magnetic heading to steer (bearings could True as 033,T)
*3C Checksum
10,11 011,M magnetic bearing, present position to destination
12,13 011,M magnetic heading to steer (bearings could True as 033,T)
*3C Checksum
*/

@@ -68,3 +70,3 @@

var xte = this.transform(values[2], (values[4].toUpperCase() === 'N' ? 'nm' : 'km'), 'nm'); // value, inputFormat, outputFormat
var xte = this.transform(values[2], (values[4].toUpperCase() === 'N' ? 'nm' : 'km'), 'm'); // value, inputFormat, outputFormat

@@ -75,8 +77,8 @@ multiplexer

.set('currentRoute', {
source: this.source(),
source: this.source(input.instrument),
timestamp: this.timestamp(),
steer: (values[3].toUpperCase() == 'R' ? 'right' : 'left'),
bearingActual: this.float(values[10]),
bearingDirect: this.float(values[7]),
courseRequired: this.float(values[12]),
bearingActual: this.transform(this.float(values[10]), 'deg', 'rad'),
bearingDirect: this.transform(this.float(values[7]), 'deg', 'rad'),
courseRequired: this.transform(this.float(values[12]), 'deg', 'rad'),
waypoint: {

@@ -83,0 +85,0 @@ next: values[9],

@@ -52,15 +52,17 @@ /*

multiplexer
.self()
.group('environment')
.set('depth', {
belowTransducer: {
source: this.source(),
timestamp: this.timestamp(),
value: this.float(values[2])
}
})
;
multiplexer.self();
multiplexer.add({
"updates": [{
"source": this.source(input.instrument),
"timestamp": this.timestamp(),
"values": [{
"path": "environment.depth.belowTransducer",
"value": this.float(values[2])
}]
}],
"context": multiplexer._context
});
return true;
});

@@ -76,3 +76,3 @@ /*

var ts = this.timestamp(values[0]);
var src = this.source();
var src = this.source(input.instrument);
var self = this;

@@ -85,3 +85,3 @@

.set('position', {
source: this.source(),
source: this.source(input.instrument),
timestamp: ts,

@@ -98,3 +98,3 @@ longitude: this.coordinate(values[3], values[4]),

.set('gnss', {
source: this.source(),
source: this.source(input.instrument),
timestamp: ts,

@@ -101,0 +101,0 @@ quality: this.int(values[5]),

@@ -52,3 +52,3 @@ /*

if(values[5].toUpperCase() == 'V') {
if(values[5].toUpperCase() == 'V') {
// Don't parse this sentence as it's void, but report the exception to the main Codec.

@@ -78,14 +78,21 @@ this.reportError(this.errors.VOID, "Not parsing sentence for it's void.");

// Position
multiplexer
.self()
.group('navigation')
.set('position', {
source: this.source(),
timestamp: ts,
longitude: self.coordinate(values[2], values[3]),
latitude: self.coordinate(values[0], values[1])
})
;
multiplexer.self();
multiplexer.add({
"updates": [{
"source": this.source(input.instrument),
"timestamp": ts,
"values": [{
"path": "navigation.position",
"value": {
longitude: self.coordinate(values[2], values[3]),
latitude: self.coordinate(values[0], values[1])
}
}]
}],
"context": multiplexer._context
});
return true;
return true;

@@ -92,0 +99,0 @@ });

@@ -1,2 +0,2 @@

/*
/*
* index.js

@@ -15,3 +15,3 @@ *

* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0

@@ -27,16 +27,27 @@ *

var codecs = {};
var codecs = {
APB: require('./APB'),
DBT: require('./DBT'),
DSC: require('./DSC'),
GGA: require('./GGA'),
GLL: require('./GLL'),
HDM: require('./HDM'),
HDG: require('./HDG'),
HDT: require('./HDT'),
MTW: require('./MTW'),
MWV: require('./MWV'),
RMC: require('./RMC'),
VDM: require('./VDM'),
VDO: require('./VDO'),
VHW: require('./VHW'),
VPW: require('./VPW'),
VTG: require('./VTG'),
RPM: require('./RPM'),
ROT: require('./ROT'),
VDR: require('./VDR'),
VPW: require('./VPW'),
VWR: require('./VWR'),
STALK: require('./STALK'),
};
require("fs").readdirSync(__dirname).forEach(function(codec) {
if(codec !== 'index.js' && codec.charAt(0) !== '.' && codec.charAt(0) !== '_') {
var module = require('./' + codec);
if(typeof module === 'function') {
codecs[codec.replace('.js', '').toUpperCase()] = module();
} else {
codecs[codec.replace('.js', '').toUpperCase()] = module;
}
}
});
module.exports = codecs;
module.exports = codecs;

@@ -49,7 +49,7 @@ /*

function convertToWindAngle(self, angle) {
var numAngle = self.float(angle) % 360;
if (numAngle > 180 && numAngle <= 360) {
return numAngle - 360;
}
return numAngle;
var numAngle = self.float(angle) % 360;
if (numAngle > 180 && numAngle <= 360) {
return numAngle - 360;
}
return numAngle;
}

@@ -60,4 +60,4 @@

if(values[4].toUpperCase() != 'A') {
// Don't parse this sentence as it's void, but report the exception to the main Codec.
if(!values[4] || values[4].toUpperCase() != 'A') {
// Don't parse this sentence as it's void/has no data, but report the exception to the main Codec.
this.reportError(this.errors.VOID, "Not parsing sentence for it's void.");

@@ -68,3 +68,3 @@ return null;

var ts = this.timestamp();
var source = this.source();
var source = this.source(input.instrument);
var wsu = values[3].toUpperCase();

@@ -80,40 +80,25 @@

var angle = convertToWindAngle(this, values[0]);
var speed = this.transform(values[2], wsu, 'ms');
var angle = convertToWindAngle(this, values[0]);
var speed = this.transform(values[2], wsu, 'ms');
multiplexer
.self()
.group('environment')
;
multiplexer.self();
if(values[1].toUpperCase() == "R") {
multiplexer.set('wind', {
angleApparent: {
timestamp: ts,
source: source,
value: angle
},
var valueType = values[1].toUpperCase() == "R" ? 'Apparent' : 'True';
var angleType = values[1].toUpperCase() == "R" ? 'Apparent' : 'TrueWater';
speedApparent: {
timestamp: ts,
source: source,
value: speed
}
});
} else {
multiplexer.set('wind', {
angleTrue: {
timestamp: ts,
source: source,
value: angle
},
speedTrue: {
timestamp: ts,
source: source,
value: speed
}
});
}
multiplexer.add({
"updates": [{
"source": source,
"timestamp": ts,
"values": [{
"path": "environment.wind.speed" + valueType,
"value": speed
}, {
"path": "environment.wind.angle" + angleType,
"value": this.transform(angle, 'deg', 'rad')
}]
}],
"context": multiplexer._context
});
return true;
});
});

@@ -72,3 +72,3 @@ /*

.set('position', {
source: this.source(),
source: this.source(input.instrument),
timestamp: ts,

@@ -81,3 +81,3 @@ longitude: self.coordinate(values[4], String(values[5]).toUpperCase()),

var vals = [
{ path: 'courseOverGroundTrue', value: self.float(values[7]) },
{ path: 'courseOverGroundTrue', value: self.transform(self.float(values[7]), 'deg', 'rad') },
{ path: 'speedOverGround', value: self.transform(values[6], 'knots', 'ms') }

@@ -87,3 +87,3 @@ ];

if(typeof values[9] !== 'undefined' && typeof values[10] === 'string') {
vals.push({ path: 'magneticVariation', value: this.magneticVariaton(values[9], values[10]) });
vals.push({ path: 'magneticVariation', value: self.transform(this.magneticVariaton(values[9], values[10]), 'deg', 'rad') });
}

@@ -95,3 +95,3 @@

.group('navigation')
.source(this.source())
.source(this.source(input.instrument))
.timestamp(ts)

@@ -98,0 +98,0 @@ .values(vals)

@@ -0,46 +1,98 @@

/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
"use strict";
var Codec = require('../lib/NMEA0183');
var Decoder = require ("ggencoder").AisDecode;
var Codec = require('../lib/NMEA0183');
var Decoder = require("ggencoder").AisDecode;
/*
A QUICK HACK THAT WILL NOT WORK WITH MULTIPLE
AIS NMEA STREAMS. Implements ggencoder session
as a global singleton. Proper implementation would be
a per stream constructer NMEA0183 encoder that would be able
to keep a coherent internal parsing state.
*/
var session = {};
module.exports = new Codec('VDM', function(multiplexer, input, line) {
var data = new Decoder(line);
var data = new Decoder(line, session);
if(!data.valid) {
return this.reportError(this.errors.VOID, "Not parsing sentence for it isn't valid.");
if (!data.valid) {
return this.reportError(this.errors.VOID, "Not parsing sentence for it isn't valid.");
}
// console.log(JSON.stringify(data, null, 2));
// console.log('\n');
// MMSI
multiplexer.vessel(data.mmsi).set('mmsi', data.mmsi);
// Position
multiplexer
.vessel(data.mmsi)
.group('navigation')
.set('position', {
source: this.source(),
timestamp: this.timestamp(),
longitude: data.lon,
latitude: data.lat
var values = [];
if (data.mmsi) {
values.push({
path: "",
value: {
mmsi: data.mmsi
}
})
;
}
if (data.shipname) {
values.push({
path: "",
value: {
name: data.shipname
}
})
}
if (typeof data.sog != 'undefined') {
values.push({
path: "navigation.speedOverGround",
value: this.transform(data.sog, 'knots', 'ms')
})
}
if (typeof data.cog != 'undefined') {
values.push({
path: "navigation.courseOverGroundTrue",
value: this.transform(data.cog, 'deg', 'rad')
})
}
if (typeof data.hdg != 'undefined') {
values.push({
path: "navigation.headingTrue",
value: this.transform(data.hdg, 'deg', 'rad')
})
}
if (data.lon && data.lat) {
values.push({
path: "navigation.position",
value: {
longitude: data.lon,
latitude: data.lat
}
})
}
// Other values
multiplexer
.vessel(data.mmsi)
.group('navigation')
.timestamp(this.timestamp())
.source(this.source())
.values([
{ path: "speedOverGround", value: data.sog },
{ path: "courseOverGround", value: data.cog },
{ path: "state", value: data.GetNavStatus() },
{ path: "headingTrue", value: data.hdg }
])
;
if (values.length > 0) {
multiplexer.self();
multiplexer.add({
"updates": [{
"source": this.source(input.instrument),
"timestamp": this.timestamp(),
"values": values
}],
"context": 'vessels.urn:mrn:imo:mmsi:' + data.mmsi
});
}
return true;
});
});

@@ -0,1 +1,18 @@

/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = require('./VDM');

@@ -54,38 +54,36 @@ /*

function hasValue(value) {
return (typeof value !== 'undefined' &&
value !== '');
return (typeof value !== 'undefined' && value !== '' && value !== null);
}
module.exports = new Codec('VHW', function(multiplexer, input) {
var values = input.values;
var values = input.values;
var speed;
var parsedValues = [];
var speed;
var parsedValues = [];
if (hasValue(values[0])) {
parsedValues.push({ path: 'headingTrue', value: parseFloat(values[0]) });
}
if (hasValue(values[2])) {
parsedValues.push({ path: 'headingMagnetic', value: parseFloat(values[2]) });
}
if(hasValue(values[0])) {
parsedValues.push({ path: 'headingTrue', value: this.transform(this.float(values[0]), 'deg', 'rad') });
}
if(hasValue(values[2])) {
parsedValues.push({ path: 'headingMagnetic', value: this.transform(this.float(values[2]), 'deg', 'rad') });
}
if (hasValue(values[6])) {
speed = this.transform(values[6], 'kph', 'ms');
}
else if (hasValue(values[4])) {
speed = this.transform(values[4], 'knots', 'ms');
}
if(hasValue(values[6])) {
speed = this.transform(values[6], 'kph', 'ms');
} else if(hasValue(values[4])) {
speed = this.transform(values[4], 'knots', 'ms');
}
if (typeof speed !== 'undefined') {
parsedValues.push({ path: 'speedThroughWater', value: speed });
}
if (typeof speed !== 'undefined') {
parsedValues.push({ path: 'speedThroughWater', value: speed });
}
multiplexer
.self()
.group('navigation')
.timestamp(this.timestamp())
.source(this.source())
.values(parsedValues);
multiplexer
.self()
.group('navigation')
.timestamp(this.timestamp())
.source(this.source(input.instrument))
.values(parsedValues);
return true;
return true;
});

@@ -68,6 +68,6 @@ /*

.timestamp(this.timestamp())
.source(this.source())
.source(this.source(input.instrument))
.values([
{ path: 'courseOverGroundMagnetic', value: this.float(values[2]) },
{ path: 'courseOverGroundTrue', value: this.float(values[0]) },
{ path: 'courseOverGroundMagnetic', value: this.transform(this.float(values[2]), 'deg', 'rad') },
{ path: 'courseOverGroundTrue', value: this.transform(this.float(values[0]), 'deg', 'rad') },
{ path: 'speedOverGround', value: speed }

@@ -74,0 +74,0 @@ ]);

@@ -0,1 +1,17 @@

/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = require('./lib');

@@ -1,41 +0,61 @@

var Transform = require('stream').Transform;
var util = require('util');
var _ = require('lodash');
var codecs = require('../codecs');
var debug = require('debug')('signalk-parser-nmea0183');
var uuid = require('node-uuid').v4;
var Multiplexer = require('signalk-multiplexer');
/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var Transform = require('stream').Transform;
var util = require('util');
var _ = require('lodash');
var codecs = require('../codecs');
var debug = require('debug')('signalk-parser-nmea0183');
var uuid = require('uuid').v4;
var Multiplexer = require('signalk-multiplexer');
function Parser(opts) {
if(!(this instanceof Parser)) {
if (!(this instanceof Parser)) {
return new Parser(opts);
}
var self = this;
var options = opts || {};
var self = this;
var options = opts || {};
if(!options.stream) {
options.stream = {};
}
if (!options.stream) {
options.stream = {};
}
options.stream.objectMode = true;
Transform.call(this, options.stream);
options.stream.objectMode = true;
Transform.call(this, options.stream);
this._linesParsed = 0;
this._linesProcessed = 0;
this._options = options;
this._lineBuffer = "";
this.self = {};
this.self.id = this._options.selfId || String(uuid().split('-')[0]).toUpperCase();
this.self.type = this._options.selfType || 'uuid';
this._linesParsed = 0;
this._linesProcessed = 0;
this._options = options;
this._lineBuffer = "";
this.self = {};
this.self.id = this._options.selfId || String(uuid().split('-')[0]).toUpperCase();
this.self.type = this._options.selfType || 'uuid';
this._multiplexer = new Multiplexer(this.self.id, this.self.type);
this._codecs = require('../codecs');
this._multiplexer = new Multiplexer(this.self.id, this.self.type);
this._codecs = require('../codecs');
this._multiplexer.on('change', function() {
var data = self._multiplexer.retrieve();
if (self.listeners('sentence').length > 0 ||
self.listeners('signalk').length > 0 ||
self.listeners('data').length > 0) {
var data = self._multiplexer.retrieve();
self.emit('sentence', data, self._linesParsed, self._linesProcessed);
self.emit('signalk', data, self._linesParsed, self._linesProcessed);
self.push(data);
self.emit('sentence', data, self._linesParsed, self._linesProcessed);
self.emit('signalk', data, self._linesParsed, self._linesProcessed);
self.push(data);
}
});

@@ -51,9 +71,9 @@

Parser.prototype._validSentence = function(sentence) {
sentence = String(sentence).trim();
sentence = String(sentence).trim();
if(sentence === "") {
if (sentence === "") {
return false;
}
if((sentence.charAt(0) == '$' || sentence.charAt(0) == '!') && sentence.charAt(sentence.length - 3) == '*') {
if ((sentence.charAt(0) == '$' || sentence.charAt(0) == '!') && sentence.charAt(sentence.length - 3) == '*') {
var check = 0;

@@ -67,113 +87,129 @@ var split = sentence.split('*');

return (parseInt(split[1], 16) == check);
} else {
return false;
}
} else {
return false;
}
}
Parser.prototype._lineData = function(sentence) {
var split = sentence.split('*');
var raw = split[0].slice(1);
var values = raw.split(',');
this.emit('nmea0183', sentence);
var split = sentence.split('*');
var raw = split[0].slice(1);
var values = raw.split(',');
var data = {
instrument: values[0].slice(0, 2),
type: values[0].slice(-3),
values: []
};
if (values[0][0] == "P") {
var data = {
instrument: values[0].slice(0, 4),
type: values[0].slice(-3),
values: []
};
} else if (values[0] == "STALK") {
var data = {
instrument: "seatalk",
type: values[0],
values: []
};
} else {
var data = {
instrument: values[0].slice(0, 2),
type: values[0].slice(-3),
values: []
};
}
for(var i = 1; i < values.length; i++) {
data.values.push(values[i]);
}
return data;
for (var i = 1; i < values.length; i++) {
data.values.push(values[i]);
}
return data;
}
Parser.prototype._decode = function(data, line) {
if(typeof codecs[data.type.toUpperCase()] !== 'undefined') {
if (typeof codecs[data.type.toUpperCase()] !== 'undefined') {
return codecs[data.type.toUpperCase()].decode(this._multiplexer, data, line);
}
}
}
Parser.prototype._transform = function(chunk, encoding, done) {
if(Buffer.isBuffer(chunk)) {
if (Buffer.isBuffer(chunk)) {
chunk = chunk.toString();
}
var self = this;
var self = this;
this._lineBuffer += chunk;
this._lineBuffer += chunk;
this._lineBuffer = this._lineBuffer.replace(/\\r\\n/g, "\n");
if(this._lineBuffer.indexOf('\n') !== -1 || (this._lineBuffer.indexOf('\n') === -1 && this._lineBuffer.indexOf('$') !== -1 && this._lineBuffer.indexOf('*') !== -1)) {
var split = this._lineBuffer.split('\n');
var unfinished = "";
var lines = [];
if (this._lineBuffer.indexOf('\n') !== -1 || (this._lineBuffer.indexOf('\n') === -1 && this._lineBuffer.indexOf('$') !== -1 && this._lineBuffer.indexOf('*') !== -1)) {
var split = this._lineBuffer.split('\n');
var unfinished = "";
var lines = [];
_.each(split, function(line) {
line = line.trim();
_.each(split, function(line) {
line = line.trim();
if(line !== '') {
if(line.charAt(0) == '$' || line.charAt(0) == '!') {
if(line.charAt(line.length - 3) == '*') {
// we have a full line
lines.push(line);
} else {
unfinished = line;
}
} else {
unfinished += line;
}
}
if (line !== '') {
if (line.charAt(0) == '$' || line.charAt(0) == '!') {
if (line.charAt(line.length - 3) == '*') {
// we have a full line
lines.push(line);
} else {
unfinished = line;
}
} else {
unfinished += line;
}
}
if(unfinished.trim() != '' && (unfinished.charAt(0) == '$' || unfinished.charAt(0) == '!') && unfinished.charAt(unfinished.length - 3) == '*') {
// Unfinished is a full line
lines.push(unfinished);
}
});
if (unfinished.trim() != '' && (unfinished.charAt(0) == '$' || unfinished.charAt(0) == '!') && unfinished.charAt(unfinished.length - 3) == '*') {
// Unfinished is a full line
lines.push(unfinished);
}
});
_.each(lines, function(line) {
if(self._validSentence(line)) {
var data = self._lineData(line);
var valid = self._decode(data, line);
_.each(lines, function(line) {
if (self._validSentence(line)) {
var data = self._lineData(line);
var valid = self._decode(data, line);
// Internal counter counting lines that were processed
self._linesProcessed++;
// Internal counter counting lines that were processed
self._linesProcessed++;
if(valid) {
// Internal counter counting lines that were actually parsed.
// Lines that weren't parsed are either of an unsupported type (see codecs) or VOID.
self._linesParsed++;
}
}
});
if (valid) {
// Internal counter counting lines that were actually parsed.
// Lines that weren't parsed are either of an unsupported type (see codecs) or VOID.
self._linesParsed++;
}
}
});
if(split[split.length - 1].charAt(0) == '$' && split[split.length - 1].charAt(split[split.length - 1].length - 3) !== '*') {
this._lineBuffer = split[split.length - 1];
} else {
this._lineBuffer = "";
}
}
if (split[split.length - 1].charAt(0) == '$' && split[split.length - 1].charAt(split[split.length - 1].length - 3) !== '*') {
this._lineBuffer = split[split.length - 1];
} else {
this._lineBuffer = "";
}
}
return done();
return done();
}
Parser.prototype._flush = function(done) {
return done();
return done();
}
function parseLine(line, cb, opts) {
var parser = new Parser(opts);
var parser = new Parser(opts);
parser.on('sentence', function(signal) {
cb(null, signal);
parser.end();
parser.on('sentence', function(signal) {
cb(null, signal);
parser.end();
parser = undefined;
});
});
parser.write(line);
parser.write(line);
};
module.exports = {
Parser: Parser,
parse: parseLine
};
Parser: Parser,
parse: parseLine
};

@@ -1,225 +0,264 @@

!function() {
"use strict";
/*
* Copyright 2015 Fabian Tollenaar <fabian@starting-point.nl>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
! function() {
"use strict";
Math.radians = function(degrees) {
return degrees * Math.PI / 180;
};
var NMEA0183 = function(name, decoder) {
if(!(this instanceof NMEA0183)) return new NMEA0183();
if (!(this instanceof NMEA0183)) return new NMEA0183();
this.name = name;
this._decoder = decoder;
this.exceptions = [];
this.name = name;
this._decoder = decoder;
this.exceptions = [];
this.errors = {
GENERAL: 0,
MALFORMED: 1,
VOID: 2,
VOID_MODE: 3
};
this.errors = {
GENERAL: 0,
MALFORMED: 1,
VOID: 2,
VOID_MODE: 3
};
this.RATIOS = {
// DISTANCE
NM_IN_KM: 1.852,
KM_IN_NM: 0.539956803,
// SPEED
// Knots
KNOTS_IN_MS: 0.514444,
KNOTS_IN_MPH: 1.150779,
KNOTS_IN_KPH: 1.852,
// MPH
MPH_IN_MS: 0.44704,
MPH_IN_KPH: 1.609344,
MPH_IN_KNOTS: 0.868976,
// KPH
KPH_IN_MS: 0.277778,
KPH_IN_MPH: 0.621371,
KPH_IN_KNOTS: 0.539957,
// MS
MS_IN_KPH: 3.6,
MS_IN_MPH: 2.236936,
MS_IN_KNOTS: 1.943844,
};
};
this.RATIOS = {
// DISTANCE
NM_IN_KM: 1.852,
KM_IN_NM: 0.539956803,
// SPEED
// Knots
KNOTS_IN_MS: 0.514444,
KNOTS_IN_MPH: 1.150779,
KNOTS_IN_KPH: 1.852,
// MPH
MPH_IN_MS: 0.44704,
MPH_IN_KPH: 1.609344,
MPH_IN_KNOTS: 0.868976,
// KPH
KPH_IN_MS: 0.277778,
KPH_IN_MPH: 0.621371,
KPH_IN_KNOTS: 0.539957,
// MS
MS_IN_KPH: 3.6,
MS_IN_MPH: 2.236936,
MS_IN_KNOTS: 1.943844,
};
};
NMEA0183.prototype.source = function() {
return {
type: 'NMEA0183',
src: this.name,
label: 'signalk-parser-nmea0183'
};
};
NMEA0183.prototype.source = function(talker) {
var source = {
type: 'NMEA0183',
sentence: this.name,
label: 'signalk-parser-nmea0183'
};
NMEA0183.prototype.transform = function(value, inputFormat, outputFormat) {
value = this.float(value);
if(typeof talker === 'string' && talker.trim().length > 0) {
source.talker = talker.toUpperCase()
}
inputFormat = inputFormat.toLowerCase();
outputFormat = outputFormat.toLowerCase();
return source
};
if(inputFormat === outputFormat) {
return value;
}
NMEA0183.prototype.transform = function(value, inputFormat, outputFormat) {
value = this.float(value);
// KM
if(inputFormat == 'km') {
if(outputFormat == 'nm') return value / this.RATIOS.NM_IN_KM;
}
inputFormat = inputFormat.toLowerCase();
outputFormat = outputFormat.toLowerCase();
// NM
if(inputFormat == 'nm') {
if(outputFormat == 'km') return value / this.RATIOS.KM_IN_NM;
}
// KNOTS
if(inputFormat == 'knots') {
if(outputFormat == 'kph') return value / this.RATIOS.KPH_IN_KNOTS;
if(outputFormat == 'ms') return value / this.RATIOS.MS_IN_KNOTS;
if(outputFormat == 'mph') return value / this.RATIOS.MPH_IN_KNOTS;
}
if (inputFormat === outputFormat) {
return value;
}
// KPH
if(inputFormat == 'kph') {
if(outputFormat == 'knots') return value / this.RATIOS.KNOTS_IN_KPH;
if(outputFormat == 'ms') return value / this.RATIOS.MS_IN_KPH;
if(outputFormat == 'mph') return value / this.RATIOS.MPH_IN_KPH;
}
// M
if (inputFormat == 'm') {
if (outputFormat == 'nm') return (value / 1000) / this.RATIOS.NM_IN_KM;
}
// MPH
if(inputFormat == 'mph') {
if(outputFormat == 'knots') return value / this.RATIOS.KNOTS_IN_MPH;
if(outputFormat == 'ms') return value / this.RATIOS.MS_IN_MPH;
if(outputFormat == 'kph') return value / this.RATIOS.KPH_IN_MPH;
}
// KM
if (inputFormat == 'km') {
if (outputFormat == 'nm') return value / this.RATIOS.NM_IN_KM;
if (outputFormat == 'm') return value * 1000;
}
// MS
if(inputFormat == 'ms') {
if(outputFormat == 'knots') return value / this.RATIOS.KNOTS_IN_MS;
if(outputFormat == 'mph') return value / this.RATIOS.MPH_IN_MS;
if(outputFormat == 'kph') return value / this.RATIOS.KPH_IN_MS;
}
// NM
if (inputFormat == 'nm') {
if (outputFormat == 'km') return value / this.RATIOS.KM_IN_NM;
if (outputFormat == 'm') return (value / this.RATIOS.KM_IN_NM) * 1000;
}
// Just return input if input/output formats are not recognised.
return value;
};
// KNOTS
if (inputFormat == 'knots') {
if (outputFormat == 'kph') return value / this.RATIOS.KPH_IN_KNOTS;
if (outputFormat == 'ms') return value / this.RATIOS.MS_IN_KNOTS;
if (outputFormat == 'mph') return value / this.RATIOS.MPH_IN_KNOTS;
}
NMEA0183.prototype.reportError = function(errorCode, errorMsg) {
/*
* @TODO
*/
// KPH
if (inputFormat == 'kph') {
if (outputFormat == 'knots') return value / this.RATIOS.KNOTS_IN_KPH;
if (outputFormat == 'ms') return value / this.RATIOS.MS_IN_KPH;
if (outputFormat == 'mph') return value / this.RATIOS.MPH_IN_KPH;
}
this.exceptions.push({
source: this.name,
code: errorCode,
message: errorMsg,
time: new Date().toISOString()
});
};
// MPH
if (inputFormat == 'mph') {
if (outputFormat == 'knots') return value / this.RATIOS.KNOTS_IN_MPH;
if (outputFormat == 'ms') return value / this.RATIOS.MS_IN_MPH;
if (outputFormat == 'kph') return value / this.RATIOS.KPH_IN_MPH;
}
NMEA0183.prototype.magneticVariaton = function(degrees, pole) {
// MS
if (inputFormat == 'ms') {
if (outputFormat == 'knots') return value / this.RATIOS.KNOTS_IN_MS;
if (outputFormat == 'mph') return value / this.RATIOS.MPH_IN_MS;
if (outputFormat == 'kph') return value / this.RATIOS.KPH_IN_MS;
}
// DEGREES
if (inputFormat == 'deg') {
if (outputFormat == 'rad') return Math.radians(value)
}
// Celsius
if (inputFormat == 'c') {
if (outputFormat == 'k') return value + 273.15
}
// Just return input if input/output formats are not recognised.
return value;
};
NMEA0183.prototype.reportError = function(errorCode, errorMsg) {
this.exceptions.push({
source: this.name,
code: errorCode,
message: errorMsg,
time: new Date().toISOString()
});
};
NMEA0183.prototype.magneticVariaton = function(degrees, pole) {
pole = pole.toUpperCase();
degrees = this.float(degrees);
degrees = this.float(degrees);
if(pole == "S" || pole == "W") {
degrees *= -1;
}
if (pole == "S" || pole == "W") {
degrees *= -1;
}
return degrees;
}
return degrees;
}
NMEA0183.prototype.timestamp = function(time, date) {
/* TIME (UTC) */
if(time) {
var hours, minutes, seconds;
hours = this.int(time.slice(0, 2), true);
minutes = this.int(time.slice(2, 4), true);
seconds = this.int(time.slice(-2), true);
} else {
var dt, hours, minutes, seconds;
dt = new Date();
hours = dt.getUTCHours();
minutes = dt.getUTCMinutes();
seconds = dt.getUTCSeconds();
}
NMEA0183.prototype.timestamp = function(time, date) {
/* TIME (UTC) */
if (time) {
var hours, minutes, seconds;
hours = this.int(time.slice(0, 2), true);
minutes = this.int(time.slice(2, 4), true);
seconds = this.int(time.slice(-2), true);
} else {
var dt, hours, minutes, seconds;
dt = new Date();
hours = dt.getUTCHours();
minutes = dt.getUTCMinutes();
seconds = dt.getUTCSeconds();
}
/* DATE (UTC) */
if(date) {
var year, month, day;
day = this.int(date.slice(0, 2), true);
month = this.int(date.slice(2, 4), true);
year = this.int(date.slice(-2));
/* DATE (UTC) */
if (date) {
var year, month, day;
day = this.int(date.slice(0, 2), true);
month = this.int(date.slice(2, 4), true);
year = this.int(date.slice(-2));
// HACK copied from jamesp/node-nmea
if(year < 73) {
year = this.int("20" + year);
} else {
year = this.int("19" + year);
}
} else {
var dt, year, month, day;
// HACK copied from jamesp/node-nmea
if (year < 73) {
year = this.int("20" + year);
} else {
year = this.int("19" + year);
}
} else {
var dt, year, month, day;
dt = new Date();
year = dt.getUTCFullYear();
month = dt.getUTCMonth() + 1;
day = dt.getUTCDate();
}
dt = new Date();
year = dt.getUTCFullYear();
month = dt.getUTCMonth();
day = dt.getUTCDate();
}
/* construct */
var d = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
return d.toISOString();
}
/* construct */
var d = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
return d.toISOString();
}
NMEA0183.prototype.coordinate = function(value, pole) {
// N 5222.3277 should be read as 52°22.3277'
// E 454.5824 should be read as 4°54.5824'
//
// 1. split at .
// 2. last two characters of split[0] (.slice(-2)) + everything after . (split[1]) are the minutes
// 3. degrees: split[0][a]
// 4. minutes: split[0][b] + '.' + split[1]
//
// 52°22'19.662'' N -> 52.372128333
// 4°54'34.944'' E -> 4.909706667
// S & W should be negative.
NMEA0183.prototype.coordinate = function(value, pole) {
// N 5222.3277 should be read as 52°22.3277'
// E 454.5824 should be read as 4°54.5824'
//
// 1. split at .
// 2. last two characters of split[0] (.slice(-2)) + everything after . (split[1]) are the minutes
// 3. degrees: split[0][a]
// 4. minutes: split[0][b] + '.' + split[1]
//
// 52°22'19.662'' N -> 52.372128333
// 4°54'34.944'' E -> 4.909706667
// S & W should be negative.
pole = pole.toUpperCase();
pole = pole.toUpperCase();
var split = value.split('.');
var degrees = this.float(split[0].slice(0, -2));
var minsec = this.float(split[0].slice(-2) + '.' + split[1]);
var decimal = this.float(degrees + (minsec / 60));
var split = value.split('.');
var degrees = this.float(split[0].slice(0, -2));
var minsec = this.float(split[0].slice(-2) + '.' + split[1]);
var decimal = this.float(degrees + (minsec / 60));
if (pole == "S" || pole == "W") {
decimal *= -1;
}
return this.float(decimal);
}
if (pole == "S" || pole == "W") {
decimal *= -1;
}
NMEA0183.prototype.zero = function(n) {
if(this.float(n) < 10) {
return "0" + n;
} else {
return "" + n;
}
}
return this.float(decimal);
}
NMEA0183.prototype.int = function(n) {
if(("" + n).trim() === '') {
return 0;
} else {
return parseInt(n, 10);
}
}
NMEA0183.prototype.zero = function(n) {
if (this.float(n) < 10) {
return "0" + n;
} else {
return "" + n;
}
}
NMEA0183.prototype.float = function(n) {
if(("" + n).trim() === '') {
return 0.0;
} else {
return parseFloat(n);
}
}
NMEA0183.prototype.int = function(n) {
if (("" + n).trim() === '') {
return 0;
} else {
return parseInt(n, 10);
}
}
NMEA0183.prototype.decode = function() {
return this._decoder.apply(this, Array.prototype.slice.call(arguments));
}
NMEA0183.prototype.float = function(n) {
if (("" + n).trim() === '') {
return 0.0;
} else {
return parseFloat(n);
}
}
module.exports = NMEA0183;
NMEA0183.prototype.decode = function() {
return this._decoder.apply(this, Array.prototype.slice.call(arguments));
}
}();
module.exports = NMEA0183;
}();
{
"name": "nmea0183-signalk",
"version": "0.2.3",
"description": "NMEA0183 to Signal K parser",
"main": "index.js",
"scripts": {
"start": "node ./index",
"test": "mocha"
},
"bin": {
"nmea0183-signalk": "./bin/nmea0183-signalk",
"nmea2signalk": "./bin/nmea0183-signalk"
},
"dependencies": {
"debug": "^2.1.0",
"ggencoder": "^0.1.5",
"lodash": "~2.4.1",
"mocha": "^2.1.0",
"node-uuid": "^1.4.1",
"signalk-multiplexer": "^0.1.7"
},
"devDependencies": {
"signalk-schema": "SignalK/specification",
"mocha": "^2.1.0"
},
"repository": {
"type": "git",
"url": "https://github.com/signalk/nmea0183-signalk"
},
"keywords": [
"nmea",
"nmea0183",
"signalk",
"signal",
"k",
"parser"
],
"author": "Fabian Tollenaar <fabian@starting-point.nl>",
"license": "MIT",
"bugs": {
"url": "https://github.com/signalk/nmea0183-signalk/issues"
},
"homepage": "https://github.com/signalk/nmea0183-signalk"
}
"name": "nmea0183-signalk",
"version": "0.3.0",
"description": "NMEA0183 to Signal K parser",
"main": "index.js",
"scripts": {
"start": "node ./index",
"test": "mocha"
},
"bin": {
"nmea0183-signalk": "./bin/nmea0183-signalk",
"nmea2signalk": "./bin/nmea0183-signalk"
},
"dependencies": {
"ggencoder": "^0.1.5",
"lodash": "^4.0.0",
"signalk-multiplexer": "git://github.com/SignalK/signalk-multiplexer-node.git",
"uuid": "^3.0.0"
},
"devDependencies": {
"chai": "^3.4.1",
"chai-things": "^0.2.0",
"debug": "^2.2.0",
"mocha": "^2.3.4",
"signalk-schema": "0.0.1-0"
},
"repository": {
"type": "git",
"url": "https://github.com/signalk/nmea0183-signalk"
},
"keywords": [
"nmea",
"nmea0183",
"signalk",
"signal",
"k",
"parser"
],
"author": "Fabian Tollenaar <fabian@starting-point.nl>",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/signalk/nmea0183-signalk/issues"
},
"homepage": "https://github.com/signalk/nmea0183-signalk"
}

@@ -1,54 +0,78 @@

signalk-parser-nmea0183
=======================
# signalk-parser-nmea0183
[![Build Status](https://travis-ci.org/SignalK/signalk-parser-nmea0183.svg?branch=master)](https://travis-ci.org/SignalK/signalk-parser-nmea0183)
A parser written in node.js to parse NMEA 0183 sentences into Signal K.
A Node.js [stream.Transform](https://nodejs.org/api/stream.html#stream_class_stream_transform)
which converts [NMEA 0183](http://www.nmea.org/content/nmea_standards/nmea_0183_v_410.asp)
sentences into Signal K delta messages.
SUPPORTED NMEA SENTENCES
------------------------
- APB
- DBT
- GGA
- GLL
- MWV
- RMC
- VDM
- VDO
- VTG
## Supported Sentences
The following is the list of sentences the parser supports. Pull requests welcome!
- [APB - Autopilot Sentence "B"](http://www.catb.org/gpsd/NMEA.html#_apb_autopilot_sentence_b)
- [DBT - Depth Below Transducer](http://www.catb.org/gpsd/NMEA.html#_dbt_depth_below_transducer)
- [DSC - Digital Selective Calling Class-D Radios](http://continuouswave.com/whaler/reference/DSC_Datagrams.html)
- [GGA - Global Positioning System Fix Data](http://www.catb.org/gpsd/NMEA.html#_gga_global_positioning_system_fix_data)
- [GLL - Geographic Position - Latitude/Longitude](http://www.catb.org/gpsd/NMEA.html#_gll_geographic_position_latitude_longitude)
- [HDM - Heading - Magnetic](http://www.catb.org/gpsd/NMEA.html#_hdm_heading_magnetic)
- [HDT - Heading - True](http://www.catb.org/gpsd/NMEA.html#_hdt_heading_true)
- [MTW - Mean Temperature of Water](http://catb.org/gpsd/NMEA.html#_mtw_mean_temperature_of_water)
- [MWV - Wind Speed and Angle](http://www.catb.org/gpsd/NMEA.html#_mwv_wind_speed_and_angle)
- [RMC - Recommended Minimum Navigation Information](http://www.catb.org/gpsd/NMEA.html#_rmc_recommended_minimum_navigation_information)
- [ROT - Rate of Turn](http://www.catb.org/gpsd/NMEA.html#_rot_rate_of_turn)
- [RPM - Revolutions](http://www.catb.org/gpsd/NMEA.html#_rpm_revolutions)
- [VDM - AIS Other Vessel Data](http://catb.org/gpsd/AIVDM.html)
- [VDO - AIS Own Vessel Data](http://catb.org/gpsd/AIVDM.html)
- [VDR - Set and Drift](http://www.catb.org/gpsd/NMEA.html#_vdr_set_and_drift)
- [VHW - Water Speed and Heading](http://www.catb.org/gpsd/NMEA.html#_vhw_water_speed_and_heading)
- [VPW - Speed - Measured Parallel to Wind](http://www.catb.org/gpsd/NMEA.html#_vpw_speed_measured_parallel_to_wind)
- [VTG - Track Made Good and Ground Speed](http://www.catb.org/gpsd/NMEA.html#_vtg_track_made_good_and_ground_speed)
- [VWR - Relative Wind Speed and Angle](http://www.catb.org/gpsd/NMEA.html#_vwr_relative_wind_speed_and_angle)
TODO (SENTENCES)
----------------
- GSA*
- GBS*
- GSV*
- BWC* (Started work, but needs an update)
- ZDA
- AAM
- BOD
- RMB
- XTE
- DPT
- MTW
- VLW
- VHW
- HDG
- MWD
- XDR
## Installation and Use
```
$ git clone https://github.com/SignalK/signalk-parser-nmea0183.git
$ cd signalk-parser-nmea0183
$ npm install
$ echo '$IIDBT,035.53,f,010.83,M,005.85,F*23' | ./bin/nmea0183-signalk
```
Acknowledgements
---------------
Should return something like this:
Special thanks to my fellow collaborators on [Signal K](http://signalk.github.io).
```
{
"self": "D344B1D0",
"version": "1",
"vessels": {
"D344B1D0": {
"uuid": "D344B1D0",
"environment": {
"depth": {
"belowTransducer": {
"value": 10.83,
"source": {
"type": "NMEA0183",
"sentence": "DBT",
"label": "signalk/signalk-parser-nmea0183",
"talker": "II"
},
"timestamp": "2016-04-15T17:56:52.000Z"
}
}
}
}
}
}
```
Thanks to [@jamesp](https://github.com/jamesp) for his work on node-nmea (his codecs provided a starting point for the codecs included in this Parser).
You can also pipe a file into the parser CLI:
```
$ cat some-nmea-file.log | ./bin/nmea0183-signalk
```
## Use as a Node Module
See https://github.com/SignalK/signalk-server-node/blob/master/providers/nmea0183-signalk.js for an
example in a Node application.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc