@canboat/canboatjs 1.22.2 → 1.24.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.
package/README.md CHANGED
@@ -50,6 +50,12 @@ This program takes input in the candump format and outputs canboat json format
50
50
 
51
51
  Example: `candump can0 | candumpanalyzerjs`
52
52
 
53
+ ## ydvr-file
54
+
55
+ This program takes input in the [YDVR](https://www.yachtd.com/products/recorder.html) file format and outputs canboat json format
56
+
57
+ Example: `ydvr-file <file>`
58
+
53
59
  # Usage
54
60
 
55
61
  ## Installation
package/W2K_NOTES ADDED
@@ -0,0 +1,5 @@
1
+ N2K Actisense corruption?
2
+ Docs don't match
3
+ What is that last byte?
4
+
5
+ Not seeing 126996
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ const debug = require('debug')('canboatjs:w2k01')
4
+ const net = require('net');
5
+ const { readN2KActisense } = require('../lib/n2k-actisense')
6
+
7
+ const argv = require('minimist')(process.argv.slice(2), {
8
+ alias: { h: 'help' }
9
+ })
10
+
11
+ if ( argv['help'] ) {
12
+ console.error(`Usage: ${process.argv[0]} [options] host port
13
+
14
+ Options:
15
+ -h, --help output usage information`)
16
+ process.exit(1)
17
+ }
18
+
19
+ if ( argv['_'].length < 2 ) {
20
+ console.error('Please specify a host and port')
21
+ process.exit(1)
22
+ }
23
+
24
+
25
+ var client = new net.Socket();
26
+ client.connect(argv['_'][1], argv['_'][0], function() {
27
+ debug('Connected');
28
+ });
29
+
30
+ const context = {}
31
+ client.on('data', function(data) {
32
+ readN2KActisense(data, true, context, (result) => {
33
+ console.log(result)
34
+ })
35
+ });
36
+
37
+ client.on('close', function() {
38
+ debug('Connection closed');
39
+ })
40
+
41
+ process.on('SIGINT', () => {
42
+ debug('SIGINT signal received.');
43
+ client.destroy()
44
+ });
45
+
package/bin/candumpjs ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+
3
+ const canboatjs = require('../index')
4
+ const Parser = require('../index').FromPgn
5
+ const { parseCanId } = require('../lib/canId')
6
+ const socketcan = require('socketcan')
7
+
8
+ var parser = new canboatjs.FromPgn()
9
+
10
+
11
+ const argv = require('minimist')(process.argv.slice(2), {
12
+ alias: { h: 'help' }
13
+ })
14
+
15
+ if ( argv['help'] ) {
16
+ console.error(`Usage: ${process.argv[0]} [options] candevice
17
+
18
+ Options:
19
+ -h, --help output usage information`)
20
+ process.exit(1)
21
+ }
22
+
23
+ if ( argv['_'].length === 0 ) {
24
+ console.error('Please specify a device')
25
+ process.exit(1)
26
+ }
27
+
28
+ /*
29
+
30
+ let messageCb = (data) => {
31
+ let jsonData = parser.parse(data, (err) => { if ( err ) console.error(err) })
32
+ if ( jsonData ) {
33
+ console.log(data)
34
+ }
35
+ }
36
+
37
+ let simpleCan = new canboatjs.SimpleCan({
38
+ canDevice: argv['_'][0],
39
+ preferredAddress: 35,
40
+ disableDefaultTransmitPGNs: true,
41
+ transmitPGNs: [],
42
+ }, messageCb)
43
+
44
+ simpleCan.start()
45
+
46
+ */
47
+
48
+ parser.on('error', (pgn, error) => {
49
+ console.error(`Error parsing ${pgn.pgn} ${error}`)
50
+ console.error(error.stack)
51
+ })
52
+
53
+ parser.on('pgn', (pgn) => {
54
+ console.log(JSON.stringify(pgn))
55
+ })
56
+
57
+
58
+ const canDevice = argv['_'][0]
59
+
60
+ this.channel = socketcan.createRawChannel(canDevice);
61
+
62
+ this.channel.addListener('onMessage', (msg) => {
63
+ var pgn = parseCanId(msg.id)
64
+
65
+ pgn.timestamp = new Date().toISOString()
66
+
67
+ parser.parse({ pgn, length: msg.data.length, data: msg.data })
68
+ })
69
+
70
+ this.channel.start()
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, pgnToiKonvertSerialFormat, pgnToYdgwRawFormat, pgnToPCDIN, pgnToMXPGN } = require('../index')
7
+ const { pgnToActisenseSerialFormat, pgnToActisenseN2KAsciiFormat, pgnToiKonvertSerialFormat, pgnToYdgwRawFormat, 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, ikconvert, ydgw, pcdin, mxpgn
14
+ --format <format> actisense, actisensen2kascii, ikconvert, ydgw, pcdin, mxpgn
15
15
  -h, --help output usage information`)
16
16
  process.exit(1)
17
17
  }
@@ -19,6 +19,7 @@ Options:
19
19
 
20
20
  const formatters = {
21
21
  actisense: pgnToActisenseSerialFormat,
22
+ 'n2kascii': pgnToActisenseN2KAsciiFormat,
22
23
  ikconvert: pgnToiKonvertSerialFormat,
23
24
  ydgw: pgnToYdgwRawFormat,
24
25
  'pcdin': pgnToPCDIN,
package/bin/ydvr-file ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+
3
+ const YdvrStream = require('../lib/ydvr.js');
4
+
5
+ const argv = require('minimist')(process.argv.slice(2), {
6
+ alias: { h: 'help' },
7
+ });
8
+
9
+ if (argv['help']) {
10
+ console.error(`Usage: ${process.argv[0]} file
11
+
12
+ Options:
13
+ -h, --help output usage information`);
14
+ process.exit(1);
15
+ }
16
+
17
+ if (argv['_'].length === 0) {
18
+ console.error('Please specify a file');
19
+ process.exit(1);
20
+ }
21
+
22
+ const serial = YdvrStream();
23
+
24
+ filestream = require('fs').createReadStream(argv['_'][0]);
25
+ filestream.on('error', (err) => {
26
+ console.error(err.message);
27
+ });
28
+ filestream.on('end', () => {
29
+ process.exit(0);
30
+ });
31
+ filestream.pipe(serial).on("data", (chunk) => {
32
+ console.log(JSON.stringify(chunk));
33
+ });
@@ -0,0 +1,42 @@
1
+
2
+ const canboatjs = require('../index')
3
+ //const canboatjs = require('@canboat/canboatjs')
4
+ const Parser = require('../index').FromPgn
5
+ var parser = new canboatjs.FromPgn()
6
+
7
+ let messageCb = (data) => {
8
+ let jsonData = parser.parse(data, (err) => { if ( err ) console.error(err) })
9
+ if ( jsonData ) {
10
+ //process
11
+ }
12
+ }
13
+
14
+ let simpleCan = new canboatjs.SimpleCan({
15
+ canDevice: 'can0',
16
+ preferredAddress: 35,
17
+ disableDefaultTransmitPGNs: true,
18
+ transmitPGNs: [],
19
+ addressClaim: {
20
+ "Unique Number": 139725,
21
+ "Manufacturer Code": 'Fusion Electronics',
22
+ "Device Function": 130,
23
+ "Device Class": 'Entertainment',
24
+ "Device Instance Lower": 0,
25
+ "Device Instance Upper": 0,
26
+ "System Instance": 0,
27
+ "Industry Group": 'Marine'
28
+ },
29
+ productInfo: {
30
+ "NMEA 2000 Version": 1300,
31
+ "Product Code": 667,
32
+ "Model ID": "MS-UD650",
33
+ "Software Version Code": "1.0",
34
+ "Model Version": "1.0",
35
+ "Model Serial Code": "123456",
36
+ "Certification Level": 0,
37
+ "Load Equivalency": 1
38
+ }
39
+ }, messageCb)
40
+
41
+ simpleCan.start()
42
+
package/index.js CHANGED
@@ -23,6 +23,7 @@ module.exports = {
23
23
  toPgn: require('./lib/toPgn').toPgn,
24
24
  toActisenseSerialFormat: require('./lib/stringMsg').toActisenseSerialFormat,
25
25
  pgnToActisenseSerialFormat: require('./lib/toPgn').pgnToActisenseSerialFormat,
26
+ pgnToActisenseN2KAsciiFormat: require('./lib/toPgn').pgnToActisenseN2KAsciiFormat,
26
27
  pgnToiKonvertSerialFormat: require('./lib/toPgn').pgnToiKonvertSerialFormat,
27
28
  pgnToYdgwRawFormat: require('./lib/toPgn').pgnToYdgwRawFormat,
28
29
  pgnToPCDIN: require('./lib/toPgn').pgnToPCDIN,
@@ -31,6 +32,7 @@ module.exports = {
31
32
  iKonvert: require('./lib/ikonvert'),
32
33
  Ydwg02: require('./lib/ydgw02'),
33
34
  Ydgw02: require('./lib/ydgw02'),
35
+ W2k01: require('./lib/w2k01'),
34
36
  Venus: require('./lib/venus'),
35
37
  VenusMQTT: require('./lib/venus-mqtt'),
36
38
  discover: require('./lib/discovery'),
package/lib/fromPgn.js CHANGED
@@ -29,7 +29,7 @@ const { parse: parseDate } = require('date-fns')
29
29
  const { getPGNFromCanId } = require('./utilities')
30
30
  const { getIndustryName, getManufacturerName } = require('./codes')
31
31
  const { parseCanId } = require('./canId')
32
- const { parseN2kString, parseYDRAW, isN2KOver0183, parseN2KOver0183, parsePDGY } = require('./stringMsg')
32
+ const { parseN2kString, parseYDRAW, isN2KOver0183, parseN2KOver0183, parsePDGY, parseActisenseN2KASCII } = require('./stringMsg')
33
33
 
34
34
  var fieldTypeReaders = {}
35
35
  var fieldTypePostProcessors = {}
@@ -299,7 +299,7 @@ class Parser extends EventEmitter {
299
299
  } else if ( _.isBuffer(data) ) {
300
300
  return this.parseBuffer(data, cb)
301
301
  } else {
302
- return this.parsePgnData(data.pgn, data.length, data.data, false, cb)
302
+ return this.parsePgnData(data.pgn, data.length, data.data, data.coalesced === true)
303
303
  }
304
304
  }
305
305
 
@@ -381,6 +381,29 @@ class Parser extends EventEmitter {
381
381
  return undefined
382
382
  }
383
383
 
384
+ //Yacht Devices NMEA2000 Wifi gateway
385
+ parseActisenceN2KAscii(pgn_data, cb) {
386
+ try {
387
+ const { data, error, ...pgn } = parseActisenseN2KASCII(pgn_data)
388
+ if (!error ) {
389
+ const bs = new BitStream(data)
390
+ delete pgn.format
391
+ const res = this._parse(pgn, bs, data.length, false, cb, pgn_data)
392
+ if ( res ) {
393
+ debug('parsed n2k ascii pgn %j', pgn_data)
394
+ return res
395
+ }
396
+ } else if ( error ) {
397
+ cb && cb(error)
398
+ this.emit('error', pgn_data, error)
399
+ }
400
+ } catch ( error ) {
401
+ cb && cb(error)
402
+ this.emit('error', pgn_data, error)
403
+ }
404
+ return undefined
405
+ }
406
+
384
407
  parsePDGY(pgn_data, cb) {
385
408
  if ( pgn_data[0] != '!') {
386
409
  return
@@ -0,0 +1,124 @@
1
+ const debug = require('debug')('canboatjs:w2k01')
2
+ const debugData = require('debug')('canboatjs:w2k01-data')
3
+ const { parseCanId, encodeCanId } = require('./canId')
4
+ const BitStream = require('bit-buffer').BitStream
5
+
6
+ exports.readN2KActisense = function (data, plainText, context, cb) {
7
+ const inBuf = Buffer.from(data)
8
+ let inOffset = 0
9
+ let last
10
+
11
+ if ( debugData.enabled ) {
12
+ debugData('Received: (' + data.length + ') ' + Buffer.from(data).toString('hex'))
13
+ }
14
+
15
+ try {
16
+ while ( true ) {
17
+ let len = inBuf.readUInt16LE(inOffset+3)
18
+
19
+ if ( inBuf.length < inOffset + 5 + len ) {
20
+ /*
21
+ I've never seen this happen
22
+ context.lastChunk = Buffer.alloc(inBuf.length - inOffset)
23
+ inBuf.copy(context.lastChunk, 0, inOffset, inBuf.length-1)
24
+ */
25
+
26
+ if ( debug.enabled ) {
27
+ debug('incomplete packet: (' + len + ') ' + inBuf.toString('hex', inOffset))
28
+ }
29
+
30
+ return
31
+ } else if ( inBuf[inOffset + 5 + len -1] != 0x03 ||
32
+ inBuf[inOffset + 5 + len -2] != 0x10 ) {
33
+ if ( debug.enabled ) {
34
+ debug('bad packet: (' + len + ') ' + inBuf.toString('hex', inOffset))
35
+ }
36
+ //context.lastChunk = null
37
+ return
38
+ }
39
+
40
+ let buf = Buffer.alloc(len)
41
+ inBuf.copy(buf, 0, inOffset+5, inOffset+len+5)
42
+
43
+ //console.log('NextBuf: (' + buf.length + ') ' + buf.toString('hex'))
44
+
45
+ let offset = 0
46
+ let dst = buf.readUInt8(offset)
47
+ offset += 1
48
+ let canid = buf.readUInt32LE(offset)
49
+ offset += 4
50
+ let timestamp = buf.readUInt32LE(offset)
51
+ offset += 4
52
+ let mhs = buf.readUInt8(offset)
53
+ offset += 1
54
+
55
+ let info = parseCanId(canid)
56
+
57
+ //console.log(`${len} ${mhs} ${dst} (${info.src}, ${info.dst}) ${info.pgn} ${timestamp}`)
58
+
59
+ let pgnData = Buffer.alloc(len-offset-3)
60
+ buf.copy(pgnData, 0, offset, len-3)
61
+ info.timestamp = new Date().toISOString()
62
+
63
+ if ( plainText ) {
64
+ last = binToActisense(info, pgnData, pgnData.length)
65
+ cb && cb(last)
66
+ } else {
67
+ last = { pgn:info, length: pgnData.length, data: pgnData, coalesced: true }
68
+ cb && cb(last)
69
+ }
70
+
71
+ inOffset += len + 5
72
+ if ( inOffset == inBuf.length ) {
73
+ return last
74
+ }
75
+ }
76
+ } catch ( error ) {
77
+ debug(`[error] ${error}`)
78
+ //context.lastChunk = null
79
+ return
80
+ }
81
+ }
82
+
83
+ exports.encodeN2KActisense = ({
84
+ pgn, data, timestamp, prio = 2, dst = 255, src = 0 }) => {
85
+ const bs = new BitStream(Buffer.alloc(18 + data.length))
86
+
87
+ bs.writeUint8(0x10) //BST Message ID
88
+ bs.writeUint8(0x02)
89
+ bs.writeUint8(0xd0)
90
+
91
+ bs.writeUint16(13 + data.length) //len
92
+ bs.writeUint8(dst)
93
+ bs.writeUint32(encodeCanId({dst, pgn, prio, src}))
94
+ bs.writeUint32(0) //timestamp
95
+ bs.writeUint8(0) //mhs
96
+ data.copy(bs.view.buffer, bs.byteIndex, 0)
97
+ bs.byteIndex += data.length
98
+ bs.writeUint8(0) // ??
99
+ bs.writeUint8(0x10)
100
+ bs.writeUint8(0x03)
101
+
102
+ if ( debugData.enabled ) {
103
+ debugData('encoded: ' + bs.view.buffer.toString('hex'))
104
+ }
105
+
106
+ return bs.view.buffer
107
+ }
108
+
109
+
110
+ function binToActisense(pgn, data, length) {
111
+ return (
112
+ pgn.timestamp +
113
+ `,${pgn.prio},${pgn.pgn},${pgn.src},${pgn.dst},${length},` +
114
+ new Uint32Array(data)
115
+ .reduce(function(acc, i) {
116
+ acc.push(i.toString(16));
117
+ return acc;
118
+ }, [])
119
+ .map(x => (x.length === 1 ? "0" + x : x))
120
+ .join(",")
121
+ );
122
+ }
123
+
124
+
@@ -0,0 +1,59 @@
1
+ const { readN2KActisense, encodeN2KActisense } = require('./n2k-actisense')
2
+
3
+
4
+ describe('readN2KActisense', () => {
5
+ test('basic msg', () => {
6
+ const buffer = Buffer.from('1002d01500ff0502f809004c86fe00fffccba56800ffff7310031002d01500ff0501f809004c86fe000d474717e2da69d29c1003', 'hex')
7
+ const res = readN2KActisense(buffer, false, {})
8
+ delete res.pgn.timestamp
9
+ expect(res).toEqual({
10
+ "coalesced": true,
11
+ "data": Buffer.from('0d474717e2da69d2', 'hex'),
12
+ "length": 8,
13
+ "pgn": {
14
+ "canId": 167248133,
15
+ "dst": 255,
16
+ "pgn": 129025,
17
+ "prio": 2,
18
+ "src": 5,
19
+ }
20
+ })
21
+ })
22
+ })
23
+
24
+
25
+ describe('encodeN2KActisense', () => {
26
+ test('basic msg', () => {
27
+ const expected = '1002d01500ff0501f80900000000000d474717e2da69d2001003'
28
+ const pgn = {
29
+ "data": Buffer.from('0d474717e2da69d2', 'hex'),
30
+ "dst": 255,
31
+ "pgn": 129025,
32
+ "prio": 2,
33
+ "src": 5,
34
+ }
35
+
36
+ const encoded = encodeN2KActisense(pgn)
37
+ expect(encoded).toEqual(Buffer.from(expected, 'hex'))
38
+
39
+ const read = readN2KActisense(encoded, false, {})
40
+ delete read.pgn.timestamp
41
+
42
+ expect(read).toEqual({
43
+ "coalesced": true,
44
+ "data": Buffer.from('0d474717e2da69d2', 'hex'),
45
+ "length": 8,
46
+ "pgn": {
47
+ "canId": 167248133,
48
+ "dst": 255,
49
+ "pgn": 129025,
50
+ "prio": 2,
51
+ "src": 5,
52
+ }
53
+ })
54
+
55
+
56
+ })
57
+ })
58
+
59
+
package/lib/stringMsg.js CHANGED
@@ -63,6 +63,34 @@ exports.toActisenseSerialFormat = (pgn, data, dst=255, src=0) => exports.encodeA
63
63
  pgn, data, dst, src,
64
64
  })
65
65
 
66
+ // A764027.880 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
67
+ exports.isActisenseN2KASCII = input => input.charAt(0) === 'A' && input.charAt(7) === '.' && input.charAt(11) === ' '
68
+ exports.parseActisenseN2KASCII = (input) => {
69
+ const [ timestamp, srcdstp, pgn, data ] = input.split(' ')
70
+ const src = parseInt(srcdstp.substring(0, 2), 16)
71
+ const dst = parseInt(srcdstp.substring(2,4), 16)
72
+ const prio = parseInt(srcdstp.substring(4))
73
+ return buildMsg(
74
+ buildCanId(prio, parseInt(pgn, 16), dst, src),
75
+ 'Actisense N2K ASCII',
76
+ Buffer.from(data, 'hex'),
77
+ { len: data.length, time: timestamp.substring(1) },
78
+ )
79
+ }
80
+ exports.encodeActisenseN2KACSII = ({
81
+ pgn, data, timestamp, prio = 2, dst = 255, src = 0 }) => {
82
+ timestamp = 'A000000.000'
83
+
84
+ const srcdstp = hexByte(src) + hexByte(dst) + prio
85
+ return ([
86
+ timestamp,
87
+ srcdstp.toUpperCase(),
88
+ toPaddedHexString(pgn, 5).toUpperCase(),
89
+ byteString(data, '').toUpperCase()
90
+ ].join(' '))
91
+ }
92
+
93
+
66
94
  // 16:29:27.082 R 09F8017F 50 C3 B8 13 47 D8 2B C6
67
95
  exports.isYDRAW = (input) => {
68
96
  if (input.charAt(2) !== ':') return false
@@ -232,6 +260,7 @@ exports.parseN2kString = cond([
232
260
  [exports.isCandump2, exports.parseCandump2],
233
261
  [exports.isCandump3, exports.parseCandump3],
234
262
  [exports.isPDGYdebug, exports.parsePDGYdebug],
263
+ [exports.isActisenseN2KASCII, exports.parseActisenseN2KASCII],
235
264
  [stubTrue, buildErr('MISSING_PARSER', 'Parser not found for input.')],
236
265
  ])
237
266
 
@@ -246,6 +275,7 @@ exports.isN2KString = cond([
246
275
  [exports.isCandump2, () => true],
247
276
  [exports.isCandump3, () => true],
248
277
  [exports.isPDGYdebug, () => true],
278
+ [exports.isActisenseN2KASCII, () => true],
249
279
  [stubTrue, () => false],
250
280
  ])
251
281
 
@@ -1,6 +1,6 @@
1
1
  const {
2
2
  encodeActisense, encodeYDRAW, parseActisense, parseCandump1, parseCandump2,
3
- parsePCDIN, parsePDGY, parseN2kString, parsePDGYdebug, parseYDRAW,
3
+ parsePCDIN, parsePDGY, parseN2kString, parsePDGYdebug, parseYDRAW, encodeActisenseN2KACSII, parseActisenseN2KASCII
4
4
  } = require('./stringMsg')
5
5
 
6
6
  /* globals describe test expect */
@@ -185,6 +185,32 @@ describe('encodeYDRAW', () => {
185
185
  ])
186
186
  })
187
187
  })
188
+
189
+ describe('parseActisenseN2KASCII', () => {
190
+ test('basic msg', () => {
191
+ const msg = 'A000021.293 05FF2 1F802 FFFC289A1600FFFF'
192
+ expect(parseActisenseN2KASCII(msg)).toEqual({
193
+ data: Buffer.from('FFFC289A1600FFFF', 'hex'),
194
+ "dst": 255,
195
+ "format": "Actisense N2K ASCII",
196
+ "len": 16,
197
+ "pgn": 129026,
198
+ "prio": 2,
199
+ "src": 5,
200
+ "time": "000021.293"
201
+ })
202
+ })
203
+ })
204
+ describe('encodeActisenseN2KACSII', () => {
205
+ test('basic msg', () => {
206
+ const msg = 'A000000.000 05FF2 1F802 FFFC289A1600FFFF'
207
+ const n2k = parseActisenseN2KASCII(msg)
208
+ const res = encodeActisenseN2KACSII(n2k)
209
+ expect(res).toEqual(msg)
210
+ })
211
+ })
212
+
213
+
188
214
  describe('parseN2kString', () => {
189
215
  test('empty string or not string', () => {
190
216
  const emptyMsg = 'Input not string or empty.'
package/lib/toPgn.js CHANGED
@@ -21,7 +21,8 @@ const BitStream = require('bit-buffer').BitStream
21
21
  const Int64LE = require('int64-buffer').Int64LE
22
22
  const Uint64LE = require('int64-buffer').Uint64LE
23
23
  const { getPlainPGNs } = require('./utilities')
24
- const { encodeActisense, encodeYDRAW, parseActisense, encodePCDIN, encodeMXPGN, encodePDGY } = require('./stringMsg')
24
+ const { encodeActisense, encodeActisenseN2KACSII, encodeYDRAW, parseActisense, encodePCDIN, encodeMXPGN, encodePDGY } = require('./stringMsg')
25
+ const { encodeN2KActisense } = require('./n2k-actisense')
25
26
  const { encodeCanId } = require('./canId')
26
27
  const { getIndustryCode, getManufacturerCode } = require('./codes')
27
28
  const debug = require('debug')('canboatjs:toPgn')
@@ -291,6 +292,14 @@ function pgnToActisenseSerialFormat(pgn) {
291
292
  return encodeActisense({ pgn: pgn.pgn, data: toPgn(pgn), dst: pgn.dst})
292
293
  }
293
294
 
295
+ function pgnToActisenseN2KAsciiFormat(pgn) {
296
+ return encodeActisenseN2KACSII({ pgn: pgn.pgn, data: toPgn(pgn), dst: pgn.dst})
297
+ }
298
+
299
+ function pgnToN2KActisenseFormat(pgn) {
300
+ return encodeN2KActisense({ pgn: pgn.pgn, data: toPgn(pgn), dst: pgn.dst})
301
+ }
302
+
294
303
  function toiKonvertSerialFormat(pgn, data, dst=255) {
295
304
  return `!PDGY,${pgn},${dst},${data.toString('base64')}`
296
305
  }
@@ -315,6 +324,8 @@ const actisenseToYdgwRawFormat = _.flow(parseActisense, encodeYDRAW)
315
324
  const actisenseToPCDIN = _.flow(parseActisense, encodePCDIN)
316
325
  const actisenseToMXPGN = _.flow(parseActisense, encodeMXPGN)
317
326
  const actisenseToiKonvert = _.flow(parseActisense, encodePDGY)
327
+ const actisenseToN2KAsciiFormat = _.flow(parseActisense, encodeActisenseN2KACSII)
328
+ const actisenseToN2KActisenseFormat = _.flow(parseActisense, encodeN2KActisense)
318
329
 
319
330
  fieldTypeWriters['ASCII text'] = (pgn, field, value, bs) => {
320
331
 
@@ -431,8 +442,12 @@ module.exports.pgnToiKonvertSerialFormat = pgnToiKonvertSerialFormat
431
442
  module.exports.pgnToYdgwRawFormat = pgnToYdgwRawFormat
432
443
  module.exports.actisenseToYdgwRawFormat = actisenseToYdgwRawFormat
433
444
  module.exports.pgnToActisenseSerialFormat = pgnToActisenseSerialFormat
445
+ module.exports.pgnToActisenseN2KAsciiFormat = pgnToActisenseN2KAsciiFormat
446
+ module.exports.pgnToN2KActisenseFormat = pgnToN2KActisenseFormat
434
447
  module.exports.pgnToPCDIN = pgnToPCDIN
435
448
  module.exports.actisenseToPCDIN = actisenseToPCDIN
436
449
  module.exports.pgnToMXPGN = pgnToMXPGN
437
450
  module.exports.actisenseToMXPGN = actisenseToMXPGN
438
451
  module.exports.actisenseToiKonvert = actisenseToiKonvert
452
+ module.exports.actisenseToN2KAsciiFormat = actisenseToN2KAsciiFormat
453
+ module.exports.actisenseToN2KActisenseFormat = actisenseToN2KActisenseFormat
package/lib/w2k01.js ADDED
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Copyright 2018 Scott Bender (scott@scottbender.net)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
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
+
17
+ const debug = require('debug')('canboatjs:w2k01')
18
+ const debugData = require('debug')('canboatjs:w2k01-data')
19
+ const Transform = require('stream').Transform
20
+ const _ = require('lodash')
21
+ const { pgnToActisenseN2KAsciiFormat, actisenseToN2KAsciiFormat, pgnToN2KActisenseFormat, actisenseToN2KActisenseFormat } = require('./toPgn')
22
+ const { readN2KActisense, encodeN2KActisense } = require('./n2k-actisense')
23
+
24
+ const pgnsSent = {}
25
+
26
+ const N2K_ASCII = 0
27
+ const N2K_ACTISENSE = 1
28
+
29
+ function W2K01Stream (options, type, outEvent) {
30
+ if (!(this instanceof W2K01Stream)) {
31
+ return new W2K01Stream(options)
32
+ }
33
+
34
+ Transform.call(this, {
35
+ objectMode: true
36
+ })
37
+
38
+ this.sentAvailable = false
39
+ this.options = options
40
+ this.outEvent = outEvent || 'w2k-1-out'
41
+
42
+ this.format = type === 'ascii' ? N2K_ASCII : N2K_ACTISENSE
43
+
44
+ if ( this.format === N2K_ASCII ) {
45
+ if ( options.app ) {
46
+ options.app.on(this.options.outEevent || 'nmea2000out', (msg) => {
47
+ if ( typeof msg === 'string' ) {
48
+ this.sendW2KPGN(msg)
49
+ } else {
50
+ this.sendPGN(msg)
51
+ }
52
+ })
53
+
54
+ options.app.on('nmea2000JsonOut', (msg) => {
55
+ this.sendPGN(msg)
56
+ })
57
+ }
58
+ }
59
+
60
+ debug('started')
61
+ }
62
+
63
+ W2K01Stream.prototype.send = function (msg) {
64
+ debug('sending %s', msg)
65
+ this.options.app.emit(this.outEvent, msg)
66
+ }
67
+
68
+ W2K01Stream.prototype.sendPGN = function (pgn) {
69
+ let now = Date.now()
70
+ let lastSent = pgnsSent[pgn.pgn]
71
+ if ( this.format === N2K_ASCII ) {
72
+ let ascii = pgnToActisenseN2KAsciiFormat(pgn)
73
+ this.send(ascii + '\r\n')
74
+ } else {
75
+ let buf = pgnToN2KActisenseFormat(pgn)
76
+ this.send(buf)
77
+ }
78
+ pgnsSent[pgn.pgn] = now
79
+ }
80
+
81
+ W2K01Stream.prototype.sendW2KPGN = function (msg) {
82
+ if ( this.format === N2K_ASCII ) {
83
+ let ascii = actisenseToN2KAsciiFormat(msg)
84
+ this.send(ascii + '\r\n')
85
+ } else {
86
+ let buf = actisenseToN2KActisenseFormat
87
+ this.send(buf)
88
+ }
89
+ }
90
+
91
+ require('util').inherits(W2K01Stream, Transform)
92
+
93
+ W2K01Stream.prototype._transform = function (chunk, encoding, done) {
94
+ if ( !this.sentAvailable && this.format === N2K_ASCII ) {
95
+ debug('emit nmea2000OutAvailable')
96
+ this.options.app.emit('nmea2000OutAvailable')
97
+ this.sentAvailable = true
98
+ }
99
+
100
+ if ( this.format === N2K_ASCII ) {
101
+ if ( debugData.enabled ) {
102
+ debugData('Received: ' + chunk)
103
+ }
104
+ this.push(chunk)
105
+ } else {
106
+ readN2KActisense(chunk, this.plainText, this, (data) => {
107
+ this.push(data)
108
+ })
109
+ }
110
+
111
+ done()
112
+ }
113
+
114
+ W2K01Stream.prototype.pipe = function (pipeTo) {
115
+ if ( !pipeTo.fromPgn ) {
116
+ this.plainText = true
117
+ } else {
118
+ this.plainText = false
119
+ }
120
+ return W2K01Stream.super_.prototype.pipe.call(this, pipeTo)
121
+ }
122
+
123
+
124
+ W2K01Stream.prototype.end = function () {
125
+ }
126
+
127
+ module.exports = W2K01Stream
package/lib/ydvr.js ADDED
@@ -0,0 +1,204 @@
1
+ const BitStream = require('bit-buffer').BitStream;
2
+ const Transform = require('stream').Transform;
3
+ const FromPgn = require('./fromPgn').Parser
4
+ const parseCanId = require('./canId').parseCanId;
5
+
6
+ // https://www.yachtd.com/downloads/ydvr04.pdf Appendix D
7
+ var sequencePgns = new Set([
8
+ 65240,
9
+ 126208,
10
+ 126464,
11
+ 126720,
12
+ 126983,
13
+ 126984,
14
+ 126985,
15
+ 126986,
16
+ 126987,
17
+ 126988,
18
+ 126996,
19
+ 126998,
20
+ 127233,
21
+ 127237,
22
+ 127489,
23
+ 127496,
24
+ 127497,
25
+ 127498,
26
+ 127503,
27
+ 127504,
28
+ 127506,
29
+ 127507,
30
+ 127509,
31
+ 127510,
32
+ 127511,
33
+ 127512,
34
+ 127513,
35
+ 127514,
36
+ 128275,
37
+ 128520,
38
+ 129029,
39
+ 129038,
40
+ 129039,
41
+ 129040,
42
+ 129041,
43
+ 129044,
44
+ 129045,
45
+ 129284,
46
+ 129285,
47
+ 129301,
48
+ 129302,
49
+ 129538,
50
+ 129540,
51
+ 129541,
52
+ 129542,
53
+ 129545,
54
+ 129547,
55
+ 129549,
56
+ 129551,
57
+ 129556,
58
+ 129792,
59
+ 129793,
60
+ 129794,
61
+ 129795,
62
+ 129796,
63
+ 129797,
64
+ 129798,
65
+ 129799,
66
+ 129800,
67
+ 129801,
68
+ 129802,
69
+ 129803,
70
+ 129804,
71
+ 129805,
72
+ 129806,
73
+ 129807,
74
+ 129808,
75
+ 129809,
76
+ 129810,
77
+ 130052,
78
+ 130053,
79
+ 130054,
80
+ 130060,
81
+ 130061,
82
+ 130064,
83
+ 130065,
84
+ 130066,
85
+ 130067,
86
+ 130068,
87
+ 130069,
88
+ 130070,
89
+ 130071,
90
+ 130072,
91
+ 130073,
92
+ 130074,
93
+ 130320,
94
+ 130321,
95
+ 130322,
96
+ 130323,
97
+ 130324,
98
+ 130567,
99
+ 130577,
100
+ 130578,
101
+ 130816,
102
+ ]);
103
+
104
+ function YdvrStream() {
105
+ if (!(this instanceof YdvrStream)) {
106
+ return new YdvrStream();
107
+ }
108
+
109
+ this.parser = new FromPgn();
110
+
111
+ this.parser.on('error', (pgn, error) => {
112
+ console.error(`Error parsing ${pgn.pgn} ${error}`);
113
+ console.error(error.stack);
114
+ });
115
+
116
+ this.parser.on('warning', (pgn, error) => {
117
+ //console.error(`Warning parsing ${pgn.pgn} ${error}`)
118
+ });
119
+
120
+ // this.parser.on('pgn', (pgn) => {
121
+ // console.log(JSON.stringify(pgn));
122
+ // });
123
+
124
+ Transform.call(this, {
125
+ objectMode: true,
126
+ });
127
+ }
128
+
129
+ require('util').inherits(YdvrStream, Transform);
130
+
131
+ YdvrStream.prototype.end = function () {
132
+ // console.log('end');
133
+ };
134
+
135
+ YdvrStream.prototype.parseNextRecord = function () {
136
+ if (this.bs.bitsLeft < 6 * 8) {
137
+ return false;
138
+ }
139
+
140
+ var time = this.bs.readUint16();
141
+ let timeAbsolute;
142
+ if (this.lastTime != null && time < this.lastTime) {
143
+ this.timeOffset = (this.timeOffset || 0) + 60000;
144
+ timeAbsolute = time + timeOffset;
145
+ } else {
146
+ timeAbsolute = time;
147
+ }
148
+ this.lastTime = time;
149
+
150
+ var identifier = this.bs.readUint32();
151
+ if (identifier === 0xffffffff) {
152
+ // service record
153
+ var srData = this.bs.readArrayBuffer(8);
154
+ } else {
155
+ const pgn = parseCanId(identifier);
156
+
157
+ var bodyLen;
158
+ if (pgn.pgn == 59904) {
159
+ bodyLen = 3;
160
+ } else if (sequencePgns.has(pgn.pgn)) {
161
+ var seq = this.bs.readUint8();
162
+ bodyLen = this.bs.readUint8();
163
+ } else {
164
+ bodyLen = 8;
165
+ }
166
+ var body = this.bs.readArrayBuffer(bodyLen);
167
+
168
+ const parsed = this.parser.parsePgnData(
169
+ { ...pgn, time: new Date(time).toISOString().slice(11, 23) },
170
+ bodyLen,
171
+ Buffer.from(body),
172
+ false,
173
+ undefined
174
+ );
175
+ if (parsed) {
176
+ this.push(parsed);
177
+ }
178
+ }
179
+
180
+ return true;
181
+ }
182
+
183
+ YdvrStream.prototype._transform = function (chunk, encoding, done) {
184
+ if (this.bs == null) {
185
+ this.bs = new BitStream(chunk);
186
+ } else {
187
+ var remainingBuffer = this.bs.view.buffer.subarray(this.bs.byteIndex);
188
+ this.bs = new BitStream(Buffer.concat([remainingBuffer, chunk]));
189
+ }
190
+ while (true) {
191
+ var startIndex = this.bs.byteIndex
192
+ let parsed = false;
193
+ try {
194
+ parsed = this.parseNextRecord();
195
+ } catch (ex) { }
196
+ if (!parsed) {
197
+ this.bs.byteIndex = startIndex;
198
+ break;
199
+ }
200
+ }
201
+ done();
202
+ };
203
+
204
+ module.exports = YdvrStream
package/n2ka.js ADDED
@@ -0,0 +1,123 @@
1
+ var net = require('net');
2
+ const BitStream = require('bit-buffer').BitStream
3
+ const BitView = require('bit-buffer').BitView
4
+ const cid = require('./lib/canId')
5
+ const FromPgn = require('./lib/fromPgn').Parser
6
+ const debug = require('debug')('canboatjs:w2k01')
7
+
8
+ var client = new net.Socket();
9
+ client.connect(60003, '192.168.1.145', function() {
10
+ console.log('Connected');
11
+ });
12
+
13
+ client.on('data', function(data) {
14
+ const parser = new FromPgn()
15
+
16
+ /*
17
+ var obuf = Buffer.from(data)
18
+ let len = obuf.readUInt16LE(3)
19
+
20
+ let buf = Buffer.alloc(len)
21
+ obuf.copy(buf, 0, 5, len+5)
22
+ console.log('New Buf: ' + buf.toString('hex'))
23
+ let offset = 0
24
+ let dst = buf.readUInt8(offset)
25
+ offset += 1
26
+ let canid = buf.readUInt32LE(offset)
27
+ offset += 4
28
+ let timestamp = buf.readUInt32LE(offset)
29
+ offset += 4
30
+ let mhs = buf.readUInt8(offset)
31
+ offset += 1
32
+
33
+ let info = cid.parseCanId(canid)
34
+
35
+ console.log(`(${len}, ${data.length}) (${info.src}, ${info.dst}) ${info.pgn} ${timestamp}`)
36
+
37
+
38
+ try {
39
+ let pgnData = Buffer.alloc(len-offset-2)
40
+ buf.copy(pgnData, 0, offset, len-2)
41
+ console.log('pgnData: ' + pgnData.toString('hex'))
42
+ let pgn = parser.parsePgnData(info, pgnData.length, pgnData, true)
43
+ console.log(pgn)
44
+ } catch (error) {
45
+
46
+ console.log(error)
47
+ }
48
+ */
49
+
50
+ debug('Received: (' + data.length + ') ' + Buffer.from(data).toString('hex'))
51
+
52
+ var inBuf = Buffer.from(data)
53
+ var inOffset = 0
54
+
55
+ while ( true ) {
56
+ let len = inBuf.readUInt16LE(inOffset+3)
57
+
58
+ if ( inBuf.length < inOffset + 5 + len ) {
59
+ console.log('PARTIAL PGN')
60
+ this.lastChunk = Buffer.alloc(inBuf.length - inOffset)
61
+ inBuf.copy(this.lastChunk, 0, inOffset, inBuf.length-1)
62
+ return
63
+ } else if ( inBuf[inOffset + 5 + len -1] != 0x03 ||
64
+ inBuf[inOffset + 5 + len -2] != 0x10 ) {
65
+ //console.log('Received: (' + data.length + ') ' + Buffer.from(data).toString('hex'))
66
+ //console.log('LENGTH MISMATCH ' + inBuf[inOffset + 5 + len -1])
67
+ return
68
+ }
69
+
70
+ let buf = Buffer.alloc(len)
71
+ inBuf.copy(buf, 0, inOffset+5, inOffset+len+5)
72
+
73
+
74
+ let offset = 0
75
+ let dst = buf.readUInt8(offset)
76
+ offset += 1
77
+ let canid = buf.readUInt32LE(offset)
78
+ offset += 4
79
+ let timestamp = buf.readUInt32LE(offset)
80
+ offset += 4
81
+ let mhs = buf.readUInt8(offset)
82
+ offset += 1
83
+
84
+ let info = cid.parseCanId(canid)
85
+
86
+ if ( info.pgn != 129025)
87
+ return
88
+
89
+ let pgnData = Buffer.alloc(len-offset-3)
90
+ buf.copy(pgnData, 0, offset, len-3)
91
+
92
+ /*
93
+ console.log('inputLen: ' + inBuf.length)
94
+ console.log('NextBuf: (' + buf.length + ') ' + buf.toString('hex'))
95
+ console.log('pgnData: (' + pgnData.length + ') ' + pgnData.toString('hex'))
96
+
97
+ console.log(`${len} ${mhs} ${dst} (${info.src}, ${info.dst}) ${info.pgn} ${timestamp}`)
98
+ */
99
+
100
+ let pgn = parser.parsePgnData(info, pgnData.length, pgnData, true)
101
+ if ( pgn ) {
102
+ //console.log(JSON.stringify(pgn))
103
+
104
+ }
105
+
106
+ inOffset += len + 5
107
+ //console.log(`inOffset ${inOffset} `)
108
+ if ( inOffset >= inBuf.length ) {
109
+ return
110
+ }
111
+ break
112
+ }
113
+ });
114
+
115
+ client.on('close', function() {
116
+ console.log('Connection closed');
117
+ })
118
+
119
+ process.on('SIGINT', () => {
120
+ console.info('SIGINT signal received.');
121
+ client.destroy()
122
+ });
123
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canboat/canboatjs",
3
- "version": "1.22.2",
3
+ "version": "1.24.0",
4
4
  "description": "Native javascript version of canboat",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -53,7 +53,7 @@
53
53
  "@canboat/pgns": "^1.4.0",
54
54
  "bit-buffer": "0.2.3",
55
55
  "date-fns": "2.0.0-alpha.27",
56
- "debug": "^4.1.1",
56
+ "debug": "^4.3.4",
57
57
  "dnssd": "^0.4.1",
58
58
  "int64-buffer": "^0.1.10",
59
59
  "lodash": "^4.17.4",
package/wk2.out ADDED
@@ -0,0 +1,224 @@
1
+ A000021.144 05FF2 1F801 F04E4717B2E569D2
2
+ A000021.244 05FF2 1F801 EF4E4717B3E569D2
3
+ A000021.293 05FF2 1F802 FFFC289A1600FFFF
4
+ A000021.344 05FF2 1F801 EF4E4717B3E569D2
5
+ A000021.355 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
6
+ A000021.360 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
7
+ A000021.363 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
8
+ A000021.367 05FF3 1F903 FFF0FFFFFF7FFFFF
9
+ A000021.444 05FF2 1F801 EE4E4717B4E569D2
10
+ A000021.544 05FF2 1F802 FFFC289A1700FFFF
11
+ A000021.544 05FF2 1F801 F04E4717AFE569D2
12
+ A000021.644 05FF2 1F801 F14E4717ABE569D2
13
+ A000021.700 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
14
+ A000021.744 05FF2 1F801 F24E4717A8E569D2
15
+ A000021.794 05FF2 1F802 FFFC289A1900FFFF
16
+ A000021.844 05FF2 1F801 F34E4717A4E569D2
17
+ A000021.944 05FF2 1F801 F34E4717A1E569D2
18
+ A000022.041 05FF7 1EF00 E5984819020203030101030F08FF0F00303CA31C0113C6A90F
19
+ A000022.044 05FF3 1F805 FFDB4BA48A7822C068149B75826B05808477E7A7D762F5998A99000000000014FC06CD002A03AAF2FFFF00
20
+ A000022.046 05FF6 1F11A FFF2DB4B69F8FFFF
21
+ A000022.068 05FF6 1FA03 FFDACD0010036F02
22
+ A000022.068 05FF7 1EF00 E5981700040453487B42F4D0E942AFB70443000000000000000000000000000000000000000000000000F29C0340CE06FB4022C10141BA7EC74000000000
23
+ A000022.073 05FF2 1F802 FFFC289A1D00FFFF
24
+ A000022.073 05FF2 1F801 F44E47179EE569D2
25
+ A000022.144 05FF2 1F801 F14E471797E569D2
26
+ A000022.244 05FF2 1F801 EC4E471799E569D2
27
+ A000022.294 05FF2 1F802 FFFC289A2800FFFF
28
+ A000022.344 05FF2 1F801 E74E47179BE569D2
29
+ A000022.355 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
30
+ A000022.360 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
31
+ A000022.362 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
32
+ A000022.366 05FF3 1F903 FFF0FFFFFF7FFFFF
33
+ A000022.387 05FF7 1EF00 E598E008020203090012E8071900
34
+ A000022.389 05FF7 1EF00 E598E008020203090112E8071900
35
+ A000022.391 05FF7 1EF00 E598E008020203090B11011900
36
+ A000022.392 05FF7 1EF00 E598E008020203090C12E8071900
37
+ A000022.444 05FF2 1F801 E04E47179CE569D2
38
+ A000022.544 05FF2 1F802 FFFC289A3200FFFF
39
+ A000022.544 05FF2 1F801 F54E471771E569D2
40
+ A000022.644 05FF2 1F801 ED4E471772E569D2
41
+ A000022.700 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
42
+ A000022.744 05FF2 1F801 E54E471772E569D2
43
+ A000022.794 05FF2 1F802 FFFC289A4600FFFF
44
+ A000022.844 05FF2 1F801 DB4E471772E569D2
45
+ A000022.944 05FF2 1F801 D24E471771E569D2
46
+ A000023.044 05FF3 1F805 FFDB4BDBB17822804FA0566B826B0580C203F09CD762F53F9891000000000014FC06CD002A03AAF2FFFF00
47
+ A000023.049 05FF6 1F11A FFF2DB4B69F8FFFF
48
+ A000023.068 05FF6 1FA03 FFDACD0010036F02
49
+ A000023.068 05FF7 1EF00 E598170004043EAD77420D9DE84217C303430000000000000000000000000000000000000000000000007193034085F4FA40B0B701418E6FC74000000000
50
+ A000023.072 05FF2 1F802 FFFC289A5300FFFF
51
+ A000023.072 05FF2 1F801 C84E47176FE569D2
52
+ A000023.144 05FF2 1F801 C24E47176DE569D2
53
+ A000023.244 05FF2 1F801 B84E47176BE569D2
54
+ A000023.294 05FF2 1F802 FFFC289A5900FFFF
55
+ A000023.344 05FF2 1F801 AE4E471769E569D2
56
+ A000023.355 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
57
+ A000023.360 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
58
+ A000023.362 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
59
+ A000023.366 05FF3 1F903 FFF0FFFFFF7FFFFF
60
+ A000023.443 05FF2 1F801 9E4E471764E569D2
61
+ A000023.541 05FF7 1EF00 E5984719020206030101030F08FF0F00303CA31C011100190022904E2B9EA10C
62
+ A000023.544 05FF2 1F802 FFFC8B956500FFFF
63
+ A000023.545 05FF2 1F801 914E471761E569D2
64
+ A000023.644 05FF2 1F801 984E471762E569D2
65
+ A000023.700 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
66
+ A000023.744 05FF2 1F801 3A4E471754E569D2
67
+ A000023.794 05FF2 1F802 FFFC488E6900FFFF
68
+ A000023.844 05FF2 1F801 314E471752E569D2
69
+ A000023.944 05FF2 1F801 2A4E471752E569D2
70
+ A000024.041 05FF7 1EF00 E5984819020203030101030F08FF0F00303CA31C0113C7A90F
71
+ A000024.044 05FF3 1F805 FFDB4BC4D87822C0589B0945826B0500F03E8196D762F52BF085000000000014FC06CD002A03AAF2FFFF00
72
+ A000024.048 05FF6 1F11A FFF2DB4B69F8FFFF
73
+ A000024.068 05FF6 1FA03 FFDACD0010036F02
74
+ A000024.068 05FF7 1EF00 E59817000404AF8B764259E0E742CB4D0343000000000000000000000000000000000000000000000000EB8903401DE2FA402EAE01414C60C74000000000
75
+ A000024.071 05FF2 1F802 FFFCDE896200FFFF
76
+ A000024.075 05FF2 1F801 234E471753E569D2
77
+ A000024.144 05FF2 1F801 204E471754E569D2
78
+ A000024.244 05FF2 1F801 1D4E471754E569D2
79
+ A000024.294 05FF2 1F802 FFFC78865600FFFF
80
+ A000024.344 05FF2 1F801 1A4E471754E569D2
81
+ A000024.354 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
82
+ A000024.360 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
83
+ A000024.362 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
84
+ A000024.364 05FF3 1F903 FFF0FFFFFF7FFFFF
85
+ A000024.387 05FF7 1EF00 E598E008020203090012E8071900
86
+ A000024.389 05FF7 1EF00 E598E008020203090112E8071900
87
+ A000024.391 05FF7 1EF00 E598E008020203090B11011900
88
+ A000024.392 05FF7 1EF00 E598E008020203090C12E8071900
89
+ A000024.444 05FF2 1F801 174E471755E569D2
90
+ A000024.544 05FF2 1F802 FFFC78865000FFFF
91
+ A000024.545 05FF2 1F801 144E471755E569D2
92
+ A000024.644 05FF2 1F801 114E471756E569D2
93
+ A000024.700 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
94
+ A000024.744 05FF2 1F801 074E471756E569D2
95
+ A000024.794 05FF2 1F802 FFFC78864900FFFF
96
+ A000024.844 05FF2 1F801 FF4D471755E569D2
97
+ A000024.944 05FF2 1F801 F84D471755E569D2
98
+ A000025.044 05FF3 1F805 FFDB4BD4FF7822C025B34D38826B0500CB59C196D762F5753F7F000000000014FC06CD002A03AAF2FFFF00
99
+ A000025.049 05FF6 1F11A FFF2DB4B69F8FFFF
100
+ A000025.066 05FF6 1FA03 FFDACD000F036E02
101
+ A000025.068 05FF7 1EF00 E59817000404677C7742E7F1E742D47103430000000000000000000000000000000000000000000000005F800340A2CFFA40A3A40141F950C74000000000
102
+ A000025.072 05FF2 1F802 FFFC78864500FFFF
103
+ A000025.072 05FF2 1F801 EC4D471754E569D2
104
+ A000025.144 05FF2 1F801 E14D471754E569D2
105
+ A000025.244 05FF2 1F801 D64D471754E569D2
106
+ A000025.294 05FF2 1F802 FFFC78864300FFFF
107
+ A000025.344 05FF2 1F801 CB4D471754E569D2
108
+ A000025.355 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
109
+ A000025.360 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
110
+ A000025.362 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
111
+ A000025.365 05FF3 1F903 FFF0FFFFFF7FFFFF
112
+ A000025.444 05FF2 1F801 C04D471754E569D2
113
+ A000025.544 05FF2 1F802 FFFC78864000FFFF
114
+ A000025.544 05FF2 1F801 B54D471754E569D2
115
+ A000025.644 05FF2 1F801 AA4D471754E569D2
116
+ A000025.700 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
117
+ A000025.744 05FF2 1F801 A44D471755E569D2
118
+ A000025.794 05FF2 1F802 FFFC78863E00FFFF
119
+ A000025.844 05FF2 1F801 9E4D471755E569D2
120
+ A000025.944 05FF2 1F801 7A4D471756E569D2
121
+ A000026.044 05FF3 1F805 FFDB4B0B277922005557F01B826B05004210BF97D762F528937E000000000014FC06CD002A03AAF2FFFF00
122
+ A000026.049 05FF6 1F11A FFF2DB4B69F8FFFF
123
+ A000026.063 05FF6 1FA03 FFDACD000F036E02
124
+ A000026.068 05FF7 1EF00 E59817000404E2F8784290E3E84238090443000000000000000000000000000000000000000000000000CB76034014BDFA400E9B01419741C74000000000
125
+ A000026.073 05FF2 1F802 FFFC78864200FFFF
126
+ A000026.073 05FF2 1F801 734D471759E569D2
127
+ A000026.073 05FF7 1EF00 E5984719020206030101030F08FF0F00303CA31C011100190022904E2B9FA10C
128
+ A000026.078 05FF7 1EF00 E5984819020203030101030F08FF0F00303CA31C0113C8A90F
129
+ A000026.144 05FF2 1F801 6A4D47175BE569D2
130
+ A000026.244 05FF2 1F801 614D47175EE569D2
131
+ A000026.294 05FF2 1F802 FFFC78865300FFFF
132
+ A000026.344 05FF2 1F801 574D471760E569D2
133
+ A000026.355 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
134
+ A000026.360 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
135
+ A000026.362 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
136
+ A000026.365 05FF3 1F903 FFF0FFFFFF7FFFFF
137
+ A000026.387 05FF7 1EF00 E598E008020203090012E8071900
138
+ A000026.389 05FF7 1EF00 E598E008020203090112E8071900
139
+ A000026.391 05FF7 1EF00 E598E008020203090B11011900
140
+ A000026.392 05FF7 1EF00 E598E008020203090C12E8071900
141
+ A000026.444 05FF2 1F801 4C4D471763E569D2
142
+ A000026.544 05FF2 1F802 FFFCE6846100FFFF
143
+ A000026.544 05FF2 1F801 464D471763E569D2
144
+ A000026.644 05FF2 1F801 404D471762E569D2
145
+ A000026.700 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
146
+ A000026.744 05FF2 1F801 394D471761E569D2
147
+ A000026.794 05FF2 1F802 FFFC38826B00FFFF
148
+ A000026.844 05FF2 1F801 324D471760E569D2
149
+ A000026.944 05FF2 1F801 2B4D471760E569D2
150
+ A000027.044 05FF3 1F805 FFDB4BF44D7922402890A309826B0580C6D36299D762F5B41E7E000000000014FC06CD002903AAF2FFFF00
151
+ A000027.048 05FF6 1F11A FFF2DB4B69F8FFFF
152
+ A000027.065 05FF6 1FA03 FFDACD000F036E02
153
+ A000027.065 05FF7 1EF00 E5981700040469777B42F0FAE942BFCF04430000000000000000000000000000000000000000000000002F6D034068AAFA406B9101411E32C74000000000
154
+ A000027.072 05FF2 1F802 FFFCC07E7800FFFF
155
+ A000027.072 05FF2 1F801 244D471760E569D2
156
+ A000027.144 05FF2 1F801 184D47175FE569D2
157
+ A000027.244 05FF2 1F801 0B4D47175FE569D2
158
+ A000027.294 05FF2 1F802 FFFC6F7C7D00FFFF
159
+ A000027.344 05FF2 1F801 FE4C47175EE569D2
160
+ A000027.355 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
161
+ A000027.360 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
162
+ A000027.362 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
163
+ A000027.366 05FF3 1F903 FFF0FFFFFF7FFFFF
164
+ A000027.444 05FF2 1F801 F34C47175FE569D2
165
+ A000027.544 05FF2 1F802 FFFC5E7A8000FFFF
166
+ A000027.544 05FF2 1F801 C34C47175FE569D2
167
+ A000027.642 05FF2 1F801 B64C471760E569D2
168
+ A000027.707 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
169
+ A000027.744 05FF2 1F801 AA4C47175FE569D2
170
+ A000027.794 05FF2 1F802 FFFC177A8700FFFF
171
+ A000027.844 05FF2 1F801 A24C47175EE569D2
172
+ A000027.944 05FF2 1F801 874C47175FE569D2
173
+ A000028.041 05FF7 1EF00 E5984819020203030101030F08FF0F00303CA31C0113C9A90F
174
+ A000028.044 05FF3 1F805 FFDB4B0475792200D0CA4FE2816B0580641E6B99D762F5ACF17D000000000014FC06CD002903AAF2FFFF00
175
+ A000028.048 05FF6 1F11A FFF2DB4B69F8FFFF
176
+ A000028.068 05FF6 1FA03 FFDACD000F036E02
177
+ A000028.068 05FF7 1EF00 E598170004049E9A7E42D81AEB42C6AD05430000000000000000000000000000000000000000000000008A630340A097FA40B88701418E22C74000000000
178
+ A000028.074 05FF2 1F802 FFFC92798600FFFF
179
+ A000028.074 05FF2 1F801 7B4C471760E569D2
180
+ A000028.144 05FF2 1F801 764C471762E569D2
181
+ A000028.244 05FF2 1F801 714C471764E569D2
182
+ A000028.294 05FF2 1F802 FFFCFA768000FFFF
183
+ A000028.344 05FF2 1F801 5C4C47176BE569D2
184
+ A000028.355 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
185
+ A000028.359 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
186
+ A000028.362 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
187
+ A000028.367 05FF3 1F903 FFF0FFFFFF7FFFFF
188
+ A000028.386 05FF7 1EF00 E598E008020203090012E8071900
189
+ A000028.389 05FF7 1EF00 E598E008020203090112E8071900
190
+ A000028.391 05FF7 1EF00 E598E008020203090B11011900
191
+ A000028.392 05FF7 1EF00 E598E008020203090C12E8071900
192
+ A000028.444 05FF2 1F801 584C47176EE569D2
193
+ A000028.541 05FF7 1EF00 E5984719020206030101030F08FF0F00303CA31C011100190022904E2BA0A10C
194
+ A000028.544 05FF2 1F802 FFFC82737900FFFF
195
+ A000028.545 05FF2 1F801 4C4C471778E569D2
196
+ A000028.644 05FF2 1F801 464C471780E569D2
197
+ A000028.707 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
198
+ A000028.744 05FF2 1F801 404C47177EE569D2
199
+ A000028.794 05FF2 1F802 FFFC146C6C00FFFF
200
+ A000028.844 05FF2 1F801 3C4C471780E569D2
201
+ A000028.944 05FF2 1F801 354C471787E569D2
202
+ A000029.044 05FF3 1F805 FFDB4B149C7922801525F6D0816B050017A601A3D762F5F8567D000000000014FC06CD002903AAF2FFFF00
203
+ A000029.048 05FF6 1F11A FFF2DB4B69F8FFFF
204
+ A000029.067 05FF6 1FA03 FFDACD000E036E02
205
+ A000029.068 05FF7 1EF00 E598170004045FD480425FF3EB424A6A0643000000000000000000000000000000000000000000000000D75A0340A886FA40F67E01417F14C74000000000
206
+ A000029.074 05FF2 1F802 FFFCCE696A00FFFF
207
+ A000029.074 05FF2 1F801 314C471789E569D2
208
+ A000029.144 05FF2 1F801 2C4C47178BE569D2
209
+ A000029.244 05FF2 1F801 254C471792E569D2
210
+ A000029.293 05FF2 1F802 FFFCE0646700FFFF
211
+ A000029.344 05FF2 1F801 294C47178CE569D2
212
+ A000029.355 05FF7 1EF00 E59861060202FFFFFFFF03030000FFFFFFFFFFFFFFFFFFFF0000FFFFFF7FFFFFFF7FFFFFFF7F0000FF7F
213
+ A000029.359 05FF7 1EF00 E59812070202FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7F
214
+ A000029.362 05FF3 1F904 FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF7FFF7F
215
+ A000029.362 05FF3 1F903 FFF0FFFFFF7FFFFF
216
+ A000029.444 05FF2 1F801 244C471790E569D2
217
+ A000029.544 05FF2 1F802 FFFCB0636800FFFF
218
+ A000029.544 05FF2 1F801 1B4C471796E569D2
219
+ A000029.644 05FF2 1F801 134C47179CE569D2
220
+ A000029.708 05FF7 1EF00 E598E708000A0301030DDDB7C684051101
221
+ A000029.744 05FF2 1F801 0A4C4717A3E569D2
222
+ A000029.792 05FF2 1F802 FFFC74656800FFFF
223
+ A000029.844 05FF2 1F801 004C4717A9E569D2
224
+ A000029.944 05FF2 1F801 F64B4717AEE569D2