@signalk/nmea0183-signalk
Version:
A node.js/javascript parser for NMEA0183 sentences. Sentences are parsed to Signal K format.
133 lines (116 loc) • 3.79 kB
JavaScript
/**
* Copyright 2016 Signal K and Fabian Tollenaar <fabian@signalk.org>.
*
* 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.
*/
const getTagBlock = require('./getTagBlock')
const transformSource = require('./transformSource')
const utils = require('@signalk/nmea0183-utilities')
const defaultHooks = require('../hooks')
const pkg = require('../package.json')
const debug = require('debug')('signalk-parser-nmea0183')
class Parser {
constructor(
opts = {
emitPropertyValue: () => undefined,
onPropertyValues: () => undefined,
}
) {
this.options = typeof opts === 'object' && opts !== null ? opts : {}
if (!Object.keys(this.options).includes('validateChecksum')) {
this.options.validateChecksum = true
}
this.session = {}
this.name = pkg.name
this.version = pkg.version
this.author = pkg.author
this.license = pkg.license
this.hooks = { ...defaultHooks }
opts.onPropertyValues &&
opts.onPropertyValues('nmea0183sentenceParser', (propertyValues_) => {
if (propertyValues_ === undefined) {
return
}
const propValues = propertyValues_
.filter((v) => v)
.map((propValue) => propValue.value)
.filter(isValidSentenceParserEntry)
.map(({ sentence, parser }) => {
debug(`setting custom parser ${sentence}`)
this.hooks[sentence] = parser
})
})
}
parse(sentence) {
let tags = getTagBlock(sentence)
if (tags !== false) {
sentence = tags.sentence
tags = tags.tags
} else {
tags = {}
}
let valid = utils.valid(sentence, this.options.validateChecksum)
if (valid === false) {
throw new Error(`Sentence "${sentence.trim()}" is invalid`)
}
if (sentence.charCodeAt(sentence.length - 1) === 10) {
// in case there's a newline
sentence = sentence.substr(0, sentence.length - 1)
}
const data = sentence.split('*')[0]
const dataParts = data.split(',')
let id = ''
let talker = ''
let internalId = ''
if (dataParts[0].charAt(1).toUpperCase() === 'P') {
// proprietary sentence
id = dataParts[0].substr(-3, dataParts[0].length).toUpperCase()
talker = dataParts[0].substr(1, 2).toUpperCase()
internalId = dataParts[0].substr(1, dataParts[0].length)
} else {
id = dataParts[0].substr(3, 3).toUpperCase()
talker = dataParts[0].substr(1, 2)
internalId = id
}
const split = dataParts.slice(1, dataParts.length)
if (typeof tags.source === 'undefined') {
tags.source = ':'
} else {
tags.source = `${tags.source}:${id}`
}
if (typeof this.hooks[internalId] === 'function') {
const result = this.hooks[internalId](
{
id,
sentence,
parts: split,
tags,
},
this.session
)
return transformSource(result, id, talker)
} else {
return null
}
}
}
function isValidSentenceParserEntry(entry) {
const isValid =
typeof entry.sentence === 'string' && typeof entry.parser === 'function'
if (!isValid) {
console.error(`Invalid sentence parser entry:${JSON.stringify(entry)}`)
}
return isValid
}
module.exports = Parser