Skip to content

Commit d73e657

Browse files
committed
feature: new immediate-style API to replace Promise/events
Replace the mix of promises and events in the old API by a simpler API that returns a SignalK Delta object, null if there was no valid data (invalid gps fix, unsupported sentence or partial AIS message for example) and throws exception when something goes wrong (invalid checksum, invalid data fields, etc). Not using promises makes it easier for callers to use the library and should result in less memory usage and slightly improve performance.
1 parent 332a1d0 commit d73e657

35 files changed

+524
-1045
lines changed

README.md

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66

77
> A node.js/javascript parser of NMEA0183 sentences. Sentences are parsed to [Signal K delta](http://signalk.org/specification/master/data_model.html#delta-format) format.
88
9-
10-
### Supported sentences
9+
## Supported sentences
1110

1211
- [ALK - Seatalk](https://en.wikipedia.org/wiki/Seatalk)
1312
- [APB - Autopilot Sentence "B"](http://www.catb.org/gpsd/NMEA.html#_apb_autopilot_sentence_b)
@@ -36,37 +35,34 @@
3635
- [VWR - Relative Wind Speed and Angle](http://www.catb.org/gpsd/NMEA.html#_vwr_relative_wind_speed_and_angle)
3736
- [ZDA - UTC day, month, and year, and local time zone offset](http://www.trimble.com/oem_receiverhelp/v4.44/en/NMEA-0183messages_ZDA.html)
3837

38+
## Usage
3939

40-
### Usage
40+
### JavaScript API
4141

4242
```javascript
4343
const Parser = require('@signalk/nmea0183-signalk')
4444
const parser = new Parser()
4545

46-
parser.on('error', error => {
47-
console.error(`[error] ${error.message}`)
48-
})
49-
50-
parser.on('warning', warning => {
51-
console.warn(`[warning] ${warning.message}`)
52-
})
53-
54-
parser.on('signalk:delta', delta => {
55-
console.log(`[delta] ${JSON.stringify(delta, null, 2)}`)
56-
})
57-
58-
// Parse sentence
59-
parser.parse('$SDDBT,17.0,f,5.1,M,2.8,F*3E')
46+
try {
47+
const delta = parser.parse('$SDDBT,17.0,f,5.1,M,2.8,F*3E')
48+
if (delta !== null) {
49+
console.log(`[delta] ${JSON.stringify(delta, null, 2)}`)
50+
}
51+
}
52+
catch (e) {
53+
console.error(`[error] ${e.message}`)
54+
}
6055
```
6156

57+
### Command line
58+
6259
In addition to usage in your code, the parser can be used on the command-line if installed globally (`npm install --global`). This allows you to pipe data from one program into the parser directly, without using a Signal K server. The parser holds no Signal K tree in memory (a big change vs. 1.x), so the output will be stringified [Signal K delta](http://signalk.org/specification/master/data_model.html#delta-format) messages.
6360

6461
```bash
6562
$ echo '$SDDBT,17.0,f,5.1,M,2.8,F*3E' | nmea0183-signalk
6663
```
6764

68-
69-
### NMEA0183v4 tag blocks
65+
## NMEA0183v4 tag blocks
7066

7167
This parser has (limited) support of [NMEA0183v4 tag blocks](http://www.nmea.org/Assets/may%2009%20rtcm%200183_v400.pdf) (e.g. `\s:airmar dst800,c:1438489697*13\$SDDBT,17.0,f,5.1,M,2.8,F*3E`).
7268
Keep in mind that, since NMEA uses the backslash `\` as the start and end character of the tag block, you need to escape these characters *before* parsing them.
@@ -78,25 +74,42 @@ Example:
7874
const Parser = require('@signalk/nmea0183-signalk')
7975
const parser = new Parser()
8076

81-
parser.on('error', error => {
82-
console.error(`[error] ${error.message}`)
83-
})
84-
85-
parser.on('warning', warning => {
86-
console.warn(`[warning] ${warning.message}`)
87-
})
88-
89-
parser.on('signalk:delta', delta => {
90-
console.log(`[delta] ${JSON.stringify(delta, null, 2)}`)
91-
})
77+
try {
78+
const delta = parser.parse('\\s:airmar dst800,c:1438489697*13\\$SDDBT,17.0,f,5.1,M,2.8,F*3E')
79+
if (delta !== null) {
80+
console.log(`[delta] ${JSON.stringify(delta, null, 2)}`)
81+
}
82+
}
83+
catch (e) {
84+
console.error(`[error] ${e.message}`)
85+
}
86+
```
9287

93-
parser.parse('\\s:airmar dst800,c:1438489697*13\\$SDDBT,17.0,f,5.1,M,2.8,F*3E')
88+
Output:
89+
```json
90+
[delta] {
91+
"updates": [
92+
{
93+
"source": {
94+
"sentence": "DBT",
95+
"talker": "airmar dst800",
96+
"type": "NMEA0183"
97+
},
98+
"timestamp": "2015-08-02T04:28:17.000Z",
99+
"values": [
100+
{
101+
"path": "environment.depth.belowTransducer",
102+
"value": 5.1
103+
}
104+
]
105+
}
106+
]
107+
}
94108
```
95109

96110
**Note:** *at this time, the checksum of the tag block (`c:1438489697*13`) is not validated.*
97111

98-
99-
### License
112+
## License
100113

101114
```
102115
Copyright 2016/2017 Signal K and Fabian Tollenaar <fabian@signalk.org>.

bin/nmea0183-signalk

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,15 @@ process.stdin.pipe(require('split')()).on('data', data => {
1111
return
1212
}
1313

14-
data = data.trim()
15-
parser
16-
.parse(data)
17-
.then(result => {
18-
if (result != null) {
19-
console.log(JSON.stringify(result.delta))
20-
}
21-
})
22-
.catch(e => {
14+
try {
15+
const delta = parser.parse(data.trim())
16+
if (delta !== null) {
17+
console.log(JSON.stringify(delta))
18+
}
19+
}
20+
catch(e) {
2321
console.error('Encountered an error:', e.message)
24-
})
22+
}
2523
})
2624

2725
process.stdin.on('error', err => {

lib/index.js

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@
1616
* limitations under the License.
1717
*/
1818

19-
const EventEmitter = require('events')
20-
const parseSentence = require('./parse')
19+
const getTagBlock = require('./getTagBlock')
20+
const transformSource = require('./transformSource')
21+
const utils = require('@signalk/nmea0183-utilities')
22+
const hooks = require('../hooks')
2123
const pkg = require('../package.json')
2224

23-
class Parser extends EventEmitter {
25+
class Parser {
2426
constructor (opts) {
25-
super()
2627
this.options = (typeof opts === 'object' && opts !== null) ? opts : {}
28+
if (!Object.keys(this.options).includes('validateChecksum')) {
29+
this.options.validateChecksum = true
30+
}
2731
this.session = {}
2832

2933
this.name = pkg.name
@@ -32,28 +36,54 @@ class Parser extends EventEmitter {
3236
this.license = pkg.license
3337
}
3438

35-
parse (sentence) {
36-
if (typeof sentence === 'string' && sentence.trim().length > 0) {
37-
this.emit('nmea0183', sentence.trim())
39+
parse(sentence) {
40+
let tags = getTagBlock(sentence)
41+
if (tags !== false) {
42+
sentence = tags.sentence
43+
tags = tags.tags
44+
} else {
45+
tags = {}
46+
}
47+
48+
if (typeof tags.timestamp === 'undefined') {
49+
tags.timestamp = new Date().toISOString()
50+
}
51+
52+
let valid = utils.valid(sentence, this.options.validateChecksum)
53+
if (valid === false) {
54+
throw new Error(`Sentence "${sentence.trim()}" is invalid`)
55+
}
56+
57+
if (sentence.charCodeAt(sentence.length-1) == 10 ) {
58+
//in case there's a newline
59+
sentence = sentence.substr(0, sentence.length-1)
60+
}
61+
62+
const data = sentence.split('*')[0]
63+
const dataParts = data.split(',')
64+
const id = dataParts[0].substr(3, 3).toUpperCase()
65+
const talker = dataParts[0].substr(1, 2)
66+
const split = dataParts.slice(1, dataParts.length)
67+
68+
if (typeof tags.source === 'undefined') {
69+
tags.source = ':'
70+
} else {
71+
tags.source = `${tags.source}:${id}`
3872
}
3973

40-
try {
41-
var result = parseSentence(this, sentence, this.options)
42-
if (typeof result === 'object' && result !== null) {
43-
this.emit('signalk:delta', result || {})
44-
}
45-
// Return value kept for backwards compatibility.
46-
if (result !== null) {
47-
return Promise.resolve({ delta: result })
48-
}
49-
else {
50-
return Promise.resolve(null)
51-
}
74+
if (typeof hooks[id] === 'function') {
75+
const result = hooks[id]({
76+
id,
77+
sentence,
78+
parts: split,
79+
tags
80+
}, this.session)
81+
return transformSource(result, id, talker)
5282
}
53-
catch(e) {
54-
return Promise.reject(e)
83+
else {
84+
return null
5585
}
5686
}
5787
}
5888

59-
module.exports = Parser
89+
module.exports = Parser

lib/parse.js

Lines changed: 0 additions & 82 deletions
This file was deleted.

package-lock.json

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)