@canboat/canboatjs 2.10.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ name: Publish to npm
2
+ on:
3
+ release:
4
+ types: [created]
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - uses: actions/setup-node@v1
11
+ with:
12
+ node-version: '18.x'
13
+ registry-url: 'https://registry.npmjs.org'
14
+ - run: |
15
+ npm ci && npm cache clean --force
16
+ if [[ "$tag" == *beta* ]];
17
+ then
18
+ npm publish --tag beta
19
+ else
20
+ npm publish --access public
21
+ fi
22
+ env:
23
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,27 @@
1
+ name: 'Release on tag'
2
+ on:
3
+ push:
4
+ tags:
5
+ - '*'
6
+
7
+ jobs:
8
+ release:
9
+ permissions:
10
+ contents: write
11
+ if: startsWith(github.ref, 'refs/tags/')
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Build Changelog
15
+ id: github_release
16
+ uses: mikepenz/release-changelog-builder-action@v5
17
+ env:
18
+ GITHUB_TOKEN: ${{ secrets.RELEASE_PAT }}
19
+
20
+ - name: Create Release
21
+ uses: actions/create-release@v1
22
+ with:
23
+ tag_name: ${{ github.ref }}
24
+ release_name: ${{ github.ref }}
25
+ body: ${{steps.github_release.outputs.changelog}}
26
+ env:
27
+ GITHUB_TOKEN: ${{ secrets.RELEASE_PAT }}
@@ -0,0 +1,13 @@
1
+ name: Pull Request Labels
2
+ on:
3
+ pull_request:
4
+ types: [opened, labeled, unlabeled, synchronize]
5
+ jobs:
6
+ label:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: mheap/github-action-required-labels@v1
10
+ with:
11
+ mode: exactly
12
+ count: 1
13
+ labels: "fix, feature, doc, chore, test, ignore, other, dependencies"
package/bin/to-pgn CHANGED
@@ -4,14 +4,14 @@ const argv = require('minimist')(process.argv.slice(2), {
4
4
  string: ['format'],
5
5
  alias: { h: 'help' }
6
6
  })
7
- const { pgnToActisenseSerialFormat, pgnToActisenseN2KAsciiFormat, pgnToiKonvertSerialFormat, pgnToYdgwRawFormat, pgnToPCDIN, pgnToMXPGN } = require('../index')
7
+ const { pgnToActisenseSerialFormat, pgnToActisenseN2KAsciiFormat, pgnToiKonvertSerialFormat, pgnToYdgwRawFormat, pgnToYdgwFullRawFormat, pgnToPCDIN, pgnToMXPGN } = require('../index')
8
8
  const { toActisenseSerialFormat } = require('../lib/stringMsg')
9
9
 
10
10
  if ( argv['help'] ) {
11
11
  console.error(`Usage: ${process.argv[0]} [options]
12
12
 
13
13
  Options:
14
- --format <format> actisense, actisensen2kascii, ikconvert, ydgw, pcdin, mxpgn
14
+ --format <format> actisense, actisensen2kascii, ikconvert, ydgw, yd-full, pcdin, mxpgn
15
15
  -h, --help output usage information`)
16
16
  process.exit(1)
17
17
  }
@@ -23,7 +23,8 @@ const formatters = {
23
23
  ikconvert: pgnToiKonvertSerialFormat,
24
24
  ydgw: pgnToYdgwRawFormat,
25
25
  'pcdin': pgnToPCDIN,
26
- 'mxpgn': pgnToMXPGN
26
+ 'mxpgn': pgnToMXPGN,
27
+ 'yd-full': pgnToYdgwFullRawFormat
27
28
  }
28
29
 
29
30
  const format = argv['format'] || 'actisense'
@@ -0,0 +1,11 @@
1
+ export default function (app: any): Plugin;
2
+ interface Plugin {
3
+ start: (app: any) => void;
4
+ stop: () => void;
5
+ sendKeepAlive: () => void;
6
+ id: string;
7
+ name: string;
8
+ description: string;
9
+ schema: any;
10
+ }
11
+ export {};
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2025 Scott Bender <scott@scottbender.net>
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ var canboatjs = require('@canboat/canboatjs');
18
+ var util = require('util');
19
+ var keepAlivePGN = '%s,7,65305,%s,255,8,41,9f,01,17,1c,01,00,00';
20
+ function default_1(app) {
21
+ var error = app.error;
22
+ var debug = app.debug;
23
+ var props;
24
+ var onStop = [];
25
+ var device;
26
+ var plugin = {
27
+ start: function (properties) {
28
+ var _this = this;
29
+ props = properties;
30
+ var n2kOptions = {
31
+ app: app,
32
+ canDevice: props.candevice,
33
+ preferredAddress: props.sourceAddress,
34
+ disableDefaultTransmitPGNs: true,
35
+ transmitPGNs: [126996],
36
+ addressClaim: {
37
+ 'Unique Number': 1731561,
38
+ 'Manufacturer Code': 'Navico',
39
+ 'Device Function': 190,
40
+ 'Device Class': 'Internal Environment',
41
+ 'Device Instance Lower': 0,
42
+ 'Device Instance Upper': 0,
43
+ 'System Instance': 0,
44
+ 'Industry Group': 'Marine'
45
+ },
46
+ productInfo: {
47
+ 'NMEA 2000 Version': 2100,
48
+ 'Product Code': 246,
49
+ 'Model ID': 'H5000 CPU',
50
+ 'Software Version Code': '2.0.45.0.29',
51
+ 'Model Version': '',
52
+ 'Model Serial Code': '005469',
53
+ 'Certification Level': 2,
54
+ 'Load Equivalency': 1
55
+ }
56
+ };
57
+ if (props.emulationType === 'socketcan') {
58
+ device = new canboatjs.SimpleCan(n2kOptions);
59
+ device.start();
60
+ }
61
+ else {
62
+ app.on('nmea2000OutAvailable', function () {
63
+ device = new canboatjs.YdDevice(n2kOptions);
64
+ device.start();
65
+ });
66
+ }
67
+ var timer = setInterval(function () {
68
+ _this.sendKeepAlive();
69
+ }, 1000);
70
+ onStop.push(function () { clearInterval(timer); });
71
+ },
72
+ sendKeepAlive: function () {
73
+ var msg = util.format(keepAlivePGN, (new Date()).toISOString(), device.address);
74
+ device.sendActisenseFormat(msg);
75
+ /*
76
+ device.sendPGN({
77
+ "prio":2,
78
+ "dst":255,
79
+ "pgn":127245,
80
+ "fields":{
81
+ "Instance":252,
82
+ "Direction Order":4,
83
+ "Angle Order":-0.0021,
84
+ "Position":-0.0029,
85
+ "Reserved1":null,
86
+ "Reserved2":null
87
+ }
88
+ })
89
+ */
90
+ },
91
+ stop: function () {
92
+ onStop.forEach(function (f) { return f(); });
93
+ onStop = [];
94
+ },
95
+ id: 'signalk-device-emulator',
96
+ name: 'signalk-device-emulator',
97
+ description: 'signalk-device-emulator',
98
+ schema: function () {
99
+ var schema = {
100
+ type: 'object',
101
+ properties: {
102
+ emulationType: {
103
+ type: 'string',
104
+ title: 'Emulation Device',
105
+ enum: ['socketcan', 'yd'],
106
+ enumNames: [
107
+ 'SocketCan',
108
+ 'Yacht Devices'
109
+ ],
110
+ default: 'yd'
111
+ },
112
+ candevice: {
113
+ type: "string",
114
+ title: "Candevice to use for device emulation)",
115
+ default: "can0"
116
+ },
117
+ sourceAddress: {
118
+ type: "number",
119
+ title: "Source device id for device emulation to use.",
120
+ default: 199
121
+ },
122
+ }
123
+ };
124
+ return schema;
125
+ }
126
+ };
127
+ return plugin;
128
+ }
129
+ exports.default = default_1;
@@ -0,0 +1 @@
1
+ module.exports = require('./dist/').default
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "signalk-device-emulator",
3
+ "version": "1.0.0",
4
+ "description": "Signal K Plugin which emulates a device",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "format": "prettier-standard 'src/*.ts'",
8
+ "build": "tsc",
9
+ "watch": "npm run build -- -w"
10
+ },
11
+ "keywords": [
12
+ "signalk-node-server-plugin"
13
+ ],
14
+ "author": "scott@scottbender.net",
15
+ "license": "Apache-2.0",
16
+ "dependencies": {
17
+ "@canboat/canboatjs": "^2.10.0"
18
+ },
19
+ "devDependencies": {
20
+ "@types/node": "^14.14.10",
21
+ "prettier-standard": "^16.4.1",
22
+ "typescript": "^4.1.2"
23
+ }
24
+ }
package/index.js CHANGED
@@ -28,6 +28,7 @@ module.exports = {
28
28
  pgnToActisenseN2KAsciiFormat: require('./lib/toPgn').pgnToActisenseN2KAsciiFormat,
29
29
  pgnToiKonvertSerialFormat: require('./lib/toPgn').pgnToiKonvertSerialFormat,
30
30
  pgnToYdgwRawFormat: require('./lib/toPgn').pgnToYdgwRawFormat,
31
+ pgnToYdgwFullRawFormat: require('./lib/toPgn').pgnToYdgwFullRawFormat,
31
32
  pgnToPCDIN: require('./lib/toPgn').pgnToPCDIN,
32
33
  pgnToMXPGN: require('./lib/toPgn').pgnToMXPGN,
33
34
  canbus: require('./lib/canbus'),
@@ -39,6 +40,7 @@ module.exports = {
39
40
  VenusMQTT: require('./lib/venus-mqtt'),
40
41
  discover: require('./lib/discovery'),
41
42
  SimpleCan: require('./lib/simpleCan'),
43
+ YdDevice: require('./lib/yddevice'),
42
44
  addCustomPgns: pgns.addCustomPgns,
43
45
  lookupEnumerationValue: pgns.lookupEnumerationValue,
44
46
  lookupEnumerationName: pgns.lookupEnumerationName
@@ -48,3 +50,4 @@ try {
48
50
  module.exports.serial = require('./lib/serial')
49
51
  } catch ( ex ) {
50
52
  }
53
+
package/lib/candevice.js CHANGED
@@ -20,8 +20,9 @@ const _ = require('lodash')
20
20
  const Uint64LE = require('int64-buffer').Uint64LE
21
21
  const { defaultTransmitPGNs, getIndustryCode, getManufacturerCode, getDeviceClassCode } = require('./codes')
22
22
  const { toPgn } = require('./toPgn')
23
- let packageJson
23
+ const N2kDevice = require('./n2kDevice')
24
24
 
25
+ let packageJson
25
26
  try
26
27
  {
27
28
  packageJson = require('../' + 'package.json')
@@ -30,344 +31,21 @@ try
30
31
 
31
32
  const deviceTransmitPGNs = [ 60928, 59904, 126996, 126464 ]
32
33
 
33
- class CanDevice extends EventEmitter {
34
+ class CanDevice extends N2kDevice {
34
35
  constructor (canbus, options) {
35
- super()
36
-
37
- if ( options.addressClaim ) {
38
- this.addressClaim = options.addressClaim
39
- this.addressClaim.pgn = 60928
40
- this.addressClaim.dst = 255
41
- this.addressClaim.prio = 6
42
- } else {
43
- this.addressClaim = {
44
- pgn: 60928,
45
- dst: 255,
46
- prio:6,
47
- "Unique Number": 1263,
48
- "Manufacturer Code": 999,
49
- "Device Function": 130, // PC gateway
50
- "Device Class": 25, // Inter/Intranetwork Device
51
- "Device Instance Lower": 0,
52
- "Device Instance Upper": 0,
53
- "System Instance": 0,
54
- "Industry Group": 4, // Marine
55
- "Reserved1": 1,
56
- "Reserved2": 2
57
- }
58
- this.addressClaim["Unique Number"] = options.uniqueNumber || Math.floor(Math.random() * Math.floor(2097151))
59
- }
60
-
61
- let version = packageJson ? packageJson.version : "1.0"
62
-
63
- if ( options.productInfo ) {
64
- this.productInfo = options.productInfo
65
- this.productInfo.pgn = 126996
66
- this.productInfo.dst = 255
67
- } else {
68
- this.productInfo = {
69
- pgn: 126996,
70
- dst: 255,
71
- "NMEA 2000 Version": 1300,
72
- "Product Code": 667, // Just made up..
73
- "Model ID": "Signal K",
74
- "Model Version": "canboatjs",
75
- "Model Serial Code": options.uniqueNumber ? options.uniqueNumber.toString() : "000001",
76
- "Certification Level": 0,
77
- "Load Equivalency": 1
78
- }
79
- }
80
-
81
- this.productInfo["Software Version Code"] = version
82
-
83
- if ( options.serverVersion && options.serverUrl ) {
84
- this.configurationInfo = {
85
- pgn: 126998,
86
- dst: 255,
87
- "Installation Description #1": options.serverUrl,
88
- "Installation Description #2": options.serverDescription,
89
- "Manufacturer Information": options.serverVersion
90
- }
91
- }
92
-
36
+ super(options)
93
37
  this.canbus = canbus
94
- this.options = _.isUndefined(options) ? {} : options
95
-
96
- this.address = _.isUndefined(options.preferredAddress) ? 100 : options.preferredAddress
97
- this.cansend = false
98
- this.foundConflict = false
99
- this.heartbeatCounter = 0
100
- this.devices = {}
101
-
102
- if ( !options.disableDefaultTransmitPGNs ) {
103
- this.transmitPGNs = _.union(deviceTransmitPGNs, defaultTransmitPGNs)
104
- } else {
105
- this.transmitPGNs = [...deviceTransmitPGNs]
106
- }
107
-
108
- if ( this.options.transmitPGNs ) {
109
- this.transmitPGNs = _.union(this.transmitPGNs,
110
- this.options.transmitPGNs)
111
- }
112
38
 
113
39
  if ( options.app ) {
114
40
  options.app.on(options.analyzerOutEvent || 'N2KAnalyzerOut', this.n2kMessage.bind(this))
115
41
  }
116
42
  }
117
43
 
118
- start() {
119
- sendISORequest(this, 60928, 254)
120
- setTimeout(() => {
121
- sendAddressClaim(this)
122
- }, 1000)
123
- }
124
-
125
- n2kMessage(pgn) {
126
- if ( pgn.dst == 255 || pgn.dst == this.address ) {
127
- try {
128
- if ( pgn.pgn == 59904 ) {
129
- handleISORequest(this, pgn)
130
- } else if ( pgn.pgn == 126208 ) {
131
- handleGroupFunction(this, pgn)
132
- } else if ( pgn.pgn == 60928 ) {
133
- handleISOAddressClaim(this, pgn)
134
- } else if ( pgn.pgn == 126996 ) {
135
- handleProductInformation(this, pgn)
136
- }
137
- } catch ( err ) {
138
- console.error(err)
139
- console.error(err.stack)
140
- }
141
-
142
- /*
143
- var handler = this.handlers[pgn.pgn.toString()]
144
- if ( pgn.dst == this.address )
145
- debug(`handler ${handler}`)
146
- if ( _.isFunction(handler) ) {
147
- debug(`got handled PGN %j ${handled}`, pgn)
148
- handler(pgn)
149
- }
150
- */
151
- }
152
- }
153
- }
154
-
155
- function sendPGN(device, pgn, src, dest) {
156
- pgn.src = src || device.address
157
- debug('Sending PGN %j', pgn)
158
- device.canbus.sendPGN(pgn)
159
- }
160
-
161
- function handleISORequest(device, n2kMsg) {
162
- debug('handleISORequest %j', n2kMsg)
163
-
164
- switch (n2kMsg.fields.PGN) {
165
- case 126996: // Product Information request
166
- sendProductInformation(device)
167
- break;
168
- case 126998: // Config Information request
169
- sendConfigInformation(device)
170
- break;
171
- case 60928: // ISO address claim request
172
- sendPGN(device, device.addressClaim)
173
- break;
174
- case 126464:
175
- sendPGNList(device)
176
- break;
177
- default:
178
- if ( !device.options.disableNAKs ) {
179
- debug(`Got unsupported ISO request for PGN ${n2kMsg.fields.PGN}. Sending NAK.`)
180
- sendNAKAcknowledgement(device, n2kMsg.src, n2kMsg.fields.PGN)
181
- }
182
- }
183
- }
184
-
185
- function handleGroupFunction(device, n2kMsg) {
186
- debug('handleGroupFunction %j', n2kMsg)
187
- if(n2kMsg.fields["Function Code"] === 'Request') {
188
- handleRequestGroupFunction(device, n2kMsg)
189
- } else if(n2kMsg.fields["Function Code"] === 'Command') {
190
- handleCommandGroupFunction(device, n2kMsg)
191
- } else {
192
- debug('Got unsupported Group Function PGN: %j', n2kMsg)
193
- }
194
-
195
- function handleRequestGroupFunction(device, n2kMsg) {
196
- if ( !device.options.disableNAKs ) {
197
- // We really don't support group function requests for any PGNs yet -> always respond with pgnErrorCode 1 = "PGN not supported"
198
- debug("Sending 'PGN Not Supported' Group Function response for requested PGN", n2kMsg.fields.PGN)
199
-
200
- const acknowledgement = {
201
- pgn: 126208,
202
- dst: n2kMsg.src,
203
- "Function Code": 2,
204
- "PGN": n2kMsg.fields.PGN,
205
- "PGN error code": 4,
206
- "Transmission interval/Priority error code": 0,
207
- "# of Parameters": 0
208
- }
209
- sendPGN(device, acknowledgement)
210
- }
211
- }
212
-
213
- function handleCommandGroupFunction(device, n2kMsg) {
214
- if ( !device.options.disableNAKs ) {
215
- // We really don't support group function commands for any PGNs yet -> always respond with pgnErrorCode 1 = "PGN not supported"
216
- debug("Sending 'PGN Not Supported' Group Function response for commanded PGN", n2kMsg.fields.PGN)
217
-
218
- const acknowledgement = {
219
- pgn: 126208,
220
- dst: n2kMsg.src,
221
- "Function Code": 2,
222
- "PGN": n2kMsg.fields.PGN,
223
- "PGN error code": 4,
224
- "Transmission interval/Priority error code": 0,
225
- "# of Parameters": 0
226
- }
227
- sendPGN(device, acknowledgement)
228
- }
229
- }
230
- }
231
-
232
- function handleISOAddressClaim(device, n2kMsg) {
233
- if ( n2kMsg.src != device.address ) {
234
- if ( !device.devices[n2kMsg.src] ) {
235
- debug(`registering device ${n2kMsg.src}`)
236
- device.devices[n2kMsg.src] = { addressClaim: n2kMsg }
237
- if ( device.cansend ) {
238
- //sendISORequest(device, 126996, undefined, n2kMsg.src)
239
- }
240
- }
241
- return
242
- }
243
-
244
- debug('Checking ISO address claim. %j', n2kMsg)
245
-
246
- const uint64ValueFromReceivedClaim = getISOAddressClaimAsUint64(n2kMsg)
247
- const uint64ValueFromOurOwnClaim = getISOAddressClaimAsUint64(device.addressClaim)
248
-
249
- if(uint64ValueFromOurOwnClaim < uint64ValueFromReceivedClaim) {
250
- debug(`Address conflict detected! Kept our address as ${device.address}.`)
251
- sendAddressClaim(device) // We have smaller address claim data -> we can keep our address -> re-claim it
252
- } else if(uint64ValueFromOurOwnClaim > uint64ValueFromReceivedClaim) {
253
- this.foundConflict = true
254
- increaseOwnAddress(device) // We have bigger address claim data -> we have to change our address
255
- sendAddressClaim(device)
256
- debug(`Address conflict detected! Changed our address to ${device.address}.`)
257
- }
258
- }
259
-
260
- function increaseOwnAddress(device) {
261
- var start = device.address
262
- do {
263
- device.address = (device.address + 1) % 253
264
- } while ( device.address != start && device.devices[device.address] )
265
- }
266
-
267
- function handleProductInformation(device, n2kMsg) {
268
- if ( !device.devices[n2kMsg.src] ) {
269
- device.devices[n2kMsg.src] = {}
270
- }
271
- debug('got production information %j', n2kMsg)
272
- device.devices[n2kMsg.src].productInformation = n2kMsg
273
- }
274
-
275
- function sendHeartbeat(device)
276
- {
277
- device.heartbeatCounter = device.heartbeatCounter + 1
278
- if ( device.heartbeatCounter > 252 )
279
- {
280
- device.heartbeatCounter = 0
281
- }
282
- sendPGN(device,{
283
- pgn: 126993,
284
- dst: 255,
285
- prio:7,
286
- "Data transmit offset": "00:01:00",
287
- "Sequence Counter": device.heartbeatCounter,
288
- "Controller 1 State":"Error Active"
289
- })
290
- }
291
-
292
-
293
- function sendAddressClaim(device) {
294
- if ( device.devices[device.address] ) {
295
- //someone already has this address, so find a free one
296
- increaseOwnAddress(device)
297
- }
298
- debug(`Sending address claim ${device.address}`)
299
- sendPGN(device, device.addressClaim)
300
- setTimeout(() => {
301
- if ( !device.foundConflict ) {
302
- debug('no address conflics, enabling send')
303
- device.cansend = true
304
- if ( device.options.app ) {
305
- device.options.app.emit('nmea2000OutAvailable')
306
- }
307
- sendISORequest(device, 126996)
308
- device.heartbeatInterval = setInterval(() => {
309
- sendHeartbeat(device)
310
- }, 60*1000)
311
- /*
312
- _.keys(device.devices).forEach((address) => {
313
- sendISORequest(device, 126996, undefined, address)
314
- })
315
- */
316
-
317
- }
318
- }, 250)
319
- }
320
-
321
- function sendISORequest(device, pgn, src, dst=255) {
322
- debug(`Sending iso request for ${pgn} to ${dst}`)
323
-
324
- const isoRequest = {
325
- pgn: 59904,
326
- dst: dst,
327
- "PGN": pgn
328
- }
329
- sendPGN(device, isoRequest, src)
330
- }
331
-
332
-
333
- function sendProductInformation(device) {
334
- debug("Sending product info..")
335
-
336
- sendPGN(device, device.productInfo)
337
- }
338
-
339
- function sendConfigInformation(device) {
340
- if ( device.configurationInfo ) {
341
- debug("Sending config info..")
342
- sendPGN(device, device.configurationInfo)
44
+ sendPGN(pgn, src) {
45
+ pgn.src = src || this.address
46
+ debug('Sending PGN %j', pgn)
47
+ this.canbus.sendPGN(pgn)
343
48
  }
344
49
  }
345
50
 
346
- function sendNAKAcknowledgement(device, src, requestedPGN) {
347
- const acknowledgement = {
348
- pgn: 59392,
349
- dst: src,
350
- Control: 1,
351
- "Group Function": 255,
352
- PGN: requestedPGN
353
- }
354
- sendPGN(device, acknowledgement)
355
- }
356
-
357
- function sendPGNList(device, src) {
358
- //FIXME: for now, adding everything that signalk-to-nmea2000 supports
359
- //need a way for plugins, etc. to register the pgns they provide
360
- const pgnList = {
361
- pgn: 126464,
362
- dst: src,
363
- "Function Code": 0,
364
- list: device.transmitPGNs
365
- }
366
- sendPGN(device, pgnList)
367
- }
368
-
369
- function getISOAddressClaimAsUint64(pgn) {
370
- return new Uint64LE(toPgn(pgn))
371
- }
372
-
373
51
  module.exports = CanDevice
package/lib/fromPgn.js CHANGED
@@ -847,7 +847,7 @@ fieldTypeReaders[
847
847
  buf.writeUInt8(c, idx)
848
848
  }
849
849
 
850
- return buf.toString('ascii', 0, idx)
850
+ return buf.toString('utf-8', 0, idx)
851
851
  }
852
852
 
853
853
  fieldTypeReaders["String with start/stop byte"] = (pgn, field, bs) => {
@@ -891,18 +891,27 @@ fieldTypeReaders['STRING_FIX'] = (pgn, field, bs) => {
891
891
  }
892
892
 
893
893
  var lastbyte = buf[len-1]
894
- if (lastbyte == 0xff ||
895
- lastbyte == 32 ||
896
- lastbyte == 0 ||
897
- lastbyte == 64
898
- )
899
- {
900
- while (len > 0 && (buf[len - 1] == lastbyte))
901
- {
902
- len--;
903
- }
904
- }
905
- return buf.toString('ascii', 0, len)
894
+ while (len > 0 && (lastbyte == 0xff ||
895
+ lastbyte == 32 ||
896
+ lastbyte == 0 ||
897
+ lastbyte == 64
898
+ )) {
899
+ len--
900
+ lastbyte = buf[len-1]
901
+ }
902
+
903
+ //look for a zero byte, some proprietary Raymarine pgns do this
904
+ let zero = 0
905
+ while ( zero < len ) {
906
+ if ( buf[zero] == 0 ) {
907
+ len = zero
908
+ break
909
+ }
910
+ zero++
911
+ }
912
+ len = zero
913
+ let res = len > 0 ? buf.toString('ascii', 0, len) : undefined
914
+ return res
906
915
  }
907
916
 
908
917
  fieldTypeReaders['BITLOOKUP'] = (pgn, field, bs) => {