@canboat/canboatjs 3.0.2 → 3.2.2

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.
Files changed (222) hide show
  1. package/.github/workflows/publish.yml +18 -9
  2. package/.github/workflows/test.yml +2 -2
  3. package/.github/workflows/test_canboat_changes.yml +91 -0
  4. package/.husky/pre-commit +4 -0
  5. package/.mocharc.js +7 -0
  6. package/.prettierrc.json +5 -0
  7. package/README.md +5 -14
  8. package/dist/actisense-serial.d.ts +17 -0
  9. package/dist/actisense-serial.d.ts.map +1 -0
  10. package/dist/actisense-serial.js +569 -0
  11. package/dist/actisense-serial.js.map +1 -0
  12. package/dist/bin/actisense-file.d.ts +3 -0
  13. package/dist/bin/actisense-file.d.ts.map +1 -0
  14. package/dist/bin/actisense-file.js +49 -0
  15. package/dist/bin/actisense-file.js.map +1 -0
  16. package/dist/bin/actisense-n2k-tcp.d.ts +3 -0
  17. package/dist/bin/actisense-n2k-tcp.d.ts.map +1 -0
  18. package/dist/bin/actisense-n2k-tcp.js +46 -0
  19. package/dist/bin/actisense-n2k-tcp.js.map +1 -0
  20. package/dist/bin/actisense-serialjs.d.ts +3 -0
  21. package/dist/bin/actisense-serialjs.d.ts.map +1 -0
  22. package/dist/bin/actisense-serialjs.js +51 -0
  23. package/dist/bin/actisense-serialjs.js.map +1 -0
  24. package/dist/bin/analyzerjs.d.ts +3 -0
  25. package/dist/bin/analyzerjs.d.ts.map +1 -0
  26. package/dist/bin/analyzerjs.js +61 -0
  27. package/dist/bin/analyzerjs.js.map +1 -0
  28. package/dist/bin/candumpjs.d.ts +3 -0
  29. package/dist/bin/candumpjs.d.ts.map +1 -0
  30. package/dist/bin/candumpjs.js +73 -0
  31. package/dist/bin/candumpjs.js.map +1 -0
  32. package/dist/bin/cansend.d.ts +3 -0
  33. package/dist/bin/cansend.d.ts.map +1 -0
  34. package/dist/bin/cansend.js +123 -0
  35. package/dist/bin/cansend.js.map +1 -0
  36. package/dist/bin/ikonvert-serial.d.ts +3 -0
  37. package/dist/bin/ikonvert-serial.d.ts.map +1 -0
  38. package/dist/bin/ikonvert-serial.js +36 -0
  39. package/dist/bin/ikonvert-serial.js.map +1 -0
  40. package/dist/bin/to-pgn.d.ts +3 -0
  41. package/dist/bin/to-pgn.d.ts.map +1 -0
  42. package/dist/bin/to-pgn.js +57 -0
  43. package/dist/bin/to-pgn.js.map +1 -0
  44. package/dist/canId.d.ts +21 -0
  45. package/dist/canId.d.ts.map +1 -0
  46. package/dist/canId.js +66 -0
  47. package/dist/canId.js.map +1 -0
  48. package/dist/canId.test.d.ts +2 -0
  49. package/dist/canId.test.d.ts.map +1 -0
  50. package/dist/canId.test.js +58 -0
  51. package/dist/canId.test.js.map +1 -0
  52. package/dist/canbus.d.ts +17 -0
  53. package/dist/canbus.d.ts.map +1 -0
  54. package/dist/canbus.js +261 -0
  55. package/dist/canbus.js.map +1 -0
  56. package/dist/candevice.d.ts +23 -0
  57. package/dist/candevice.d.ts.map +1 -0
  58. package/dist/candevice.js +36 -0
  59. package/dist/candevice.js.map +1 -0
  60. package/dist/codes.d.ts +2 -0
  61. package/dist/codes.d.ts.map +1 -0
  62. package/dist/codes.js +24 -0
  63. package/dist/codes.js.map +1 -0
  64. package/dist/discovery.d.ts +17 -0
  65. package/dist/discovery.d.ts.map +1 -0
  66. package/dist/discovery.js +119 -0
  67. package/dist/discovery.js.map +1 -0
  68. package/dist/fromPgn.d.ts +51 -0
  69. package/dist/fromPgn.d.ts.map +1 -0
  70. package/dist/fromPgn.js +989 -0
  71. package/dist/fromPgn.js.map +1 -0
  72. package/dist/fromPgnStream.d.ts +17 -0
  73. package/dist/fromPgnStream.d.ts.map +1 -0
  74. package/dist/fromPgnStream.js +47 -0
  75. package/dist/fromPgnStream.js.map +1 -0
  76. package/dist/ikonvert.d.ts +17 -0
  77. package/dist/ikonvert.d.ts.map +1 -0
  78. package/dist/ikonvert.js +224 -0
  79. package/dist/ikonvert.js.map +1 -0
  80. package/dist/index.d.ts +31 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +60 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/n2k-actisense.d.ts +24 -0
  85. package/dist/n2k-actisense.d.ts.map +1 -0
  86. package/dist/n2k-actisense.js +126 -0
  87. package/dist/n2k-actisense.js.map +1 -0
  88. package/dist/n2k-actisense.test.d.ts +2 -0
  89. package/dist/n2k-actisense.test.d.ts.map +1 -0
  90. package/dist/n2k-actisense.test.js +49 -0
  91. package/dist/n2k-actisense.test.js.map +1 -0
  92. package/dist/n2kDevice.d.ts +44 -0
  93. package/dist/n2kDevice.d.ts.map +1 -0
  94. package/dist/n2kDevice.js +436 -0
  95. package/dist/n2kDevice.js.map +1 -0
  96. package/dist/pgns.d.ts +22 -0
  97. package/dist/pgns.d.ts.map +1 -0
  98. package/dist/pgns.js +157 -0
  99. package/dist/pgns.js.map +1 -0
  100. package/dist/pgns.test.d.ts +2 -0
  101. package/dist/pgns.test.d.ts.map +1 -0
  102. package/dist/pgns.test.js +14 -0
  103. package/dist/pgns.test.js.map +1 -0
  104. package/dist/simpleCan.d.ts +17 -0
  105. package/dist/simpleCan.d.ts.map +1 -0
  106. package/dist/simpleCan.js +125 -0
  107. package/dist/simpleCan.js.map +1 -0
  108. package/dist/stringMsg.d.ts +33 -0
  109. package/dist/stringMsg.d.ts.map +1 -0
  110. package/dist/stringMsg.js +359 -0
  111. package/dist/stringMsg.js.map +1 -0
  112. package/dist/stringMsg.test.d.ts +2 -0
  113. package/dist/stringMsg.test.d.ts.map +1 -0
  114. package/dist/stringMsg.test.js +244 -0
  115. package/dist/stringMsg.test.js.map +1 -0
  116. package/dist/toPgn.d.ts +34 -0
  117. package/dist/toPgn.d.ts.map +1 -0
  118. package/dist/toPgn.js +500 -0
  119. package/dist/toPgn.js.map +1 -0
  120. package/dist/utilities.d.ts +28 -0
  121. package/dist/utilities.d.ts.map +1 -0
  122. package/dist/utilities.js +159 -0
  123. package/dist/utilities.js.map +1 -0
  124. package/dist/utilities.test.d.ts +2 -0
  125. package/dist/utilities.test.d.ts.map +1 -0
  126. package/dist/utilities.test.js +9 -0
  127. package/dist/utilities.test.js.map +1 -0
  128. package/dist/venus-mqtt.d.ts +11 -0
  129. package/dist/venus-mqtt.d.ts.map +1 -0
  130. package/dist/venus-mqtt.js +100 -0
  131. package/dist/venus-mqtt.js.map +1 -0
  132. package/dist/venus.d.ts +11 -0
  133. package/dist/venus.d.ts.map +1 -0
  134. package/dist/venus.js +71 -0
  135. package/dist/venus.js.map +1 -0
  136. package/dist/w2k01.d.ts +17 -0
  137. package/dist/w2k01.d.ts.map +1 -0
  138. package/dist/w2k01.js +119 -0
  139. package/dist/w2k01.js.map +1 -0
  140. package/dist/yddevice.d.ts +25 -0
  141. package/dist/yddevice.d.ts.map +1 -0
  142. package/dist/yddevice.js +43 -0
  143. package/dist/yddevice.js.map +1 -0
  144. package/dist/ydgw02.d.ts +17 -0
  145. package/dist/ydgw02.d.ts.map +1 -0
  146. package/dist/ydgw02.js +163 -0
  147. package/dist/ydgw02.js.map +1 -0
  148. package/dist/ydvr.d.ts +17 -0
  149. package/dist/ydvr.d.ts.map +1 -0
  150. package/dist/ydvr.js +120 -0
  151. package/dist/ydvr.js.map +1 -0
  152. package/eslint.config.js +58 -0
  153. package/jest.config.js +5 -0
  154. package/lib/actisense-serial.ts +644 -0
  155. package/lib/bin/actisense-file.ts +53 -0
  156. package/lib/bin/actisense-n2k-tcp.ts +50 -0
  157. package/lib/bin/actisense-serialjs.ts +55 -0
  158. package/{bin/analyzerjs → lib/bin/analyzerjs.ts} +16 -15
  159. package/{bin/candumpjs → lib/bin/candumpjs.ts} +19 -20
  160. package/lib/bin/cansend.ts +131 -0
  161. package/lib/bin/ikonvert-serial.ts +44 -0
  162. package/{bin/to-pgn → lib/bin/to-pgn.ts} +23 -17
  163. package/lib/bin/ydvr-file +33 -0
  164. package/lib/canId.test.js +35 -15
  165. package/lib/canId.ts +84 -0
  166. package/lib/canbus.ts +293 -0
  167. package/lib/candevice.ts +41 -0
  168. package/lib/codes.ts +21 -0
  169. package/lib/{discovery.js → discovery.ts} +32 -30
  170. package/lib/fromPgn.ts +1207 -0
  171. package/lib/{fromPgnStream.js → fromPgnStream.ts} +17 -12
  172. package/lib/{ikonvert.js → ikonvert.ts} +99 -94
  173. package/lib/index.ts +48 -0
  174. package/lib/n2k-actisense.test.js +31 -32
  175. package/lib/n2k-actisense.ts +152 -0
  176. package/lib/n2kDevice.ts +516 -0
  177. package/lib/pgns.test.ts +12 -0
  178. package/lib/pgns.ts +191 -0
  179. package/lib/simpleCan.ts +140 -0
  180. package/lib/stringMsg.test.js +58 -41
  181. package/lib/stringMsg.ts +464 -0
  182. package/lib/toPgn.ts +597 -0
  183. package/lib/utilities.ts +169 -0
  184. package/lib/venus-mqtt.js +69 -73
  185. package/lib/venus.js +8 -8
  186. package/lib/w2k01.ts +142 -0
  187. package/lib/{yddevice.js → yddevice.ts} +18 -16
  188. package/lib/{ydgw02.js → ydgw02.ts} +58 -51
  189. package/lib/ydvr.js +65 -147
  190. package/package.json +54 -18
  191. package/tsconfig.json +19 -0
  192. package/tsconfig.tsbuildinfo +1 -0
  193. package/CHANGELOG.md +0 -101
  194. package/bin/actisense-file +0 -47
  195. package/bin/actisense-n2k-tcp +0 -45
  196. package/bin/actisense-serialjs +0 -52
  197. package/bin/candumpanalyzerjs +0 -29
  198. package/bin/cansend +0 -130
  199. package/bin/ikonvert-serial +0 -50
  200. package/bin/ydgw-analyzerjs +0 -36
  201. package/bin/ydvr-file +0 -33
  202. package/index.js +0 -53
  203. package/ios_canboat.js/main.js +0 -2
  204. package/ios_canboat.js/main.js.LICENSE.txt +0 -17
  205. package/ios_canboat.js/main.js.map +0 -1
  206. package/lib/canId.js +0 -64
  207. package/lib/canbus.js +0 -278
  208. package/lib/candevice.js +0 -51
  209. package/lib/codes.js +0 -69
  210. package/lib/codes.test.js +0 -17
  211. package/lib/codesMfgs.json +0 -166
  212. package/lib/fromPgn.js +0 -1027
  213. package/lib/n2k-actisense.js +0 -108
  214. package/lib/n2kDevice.js +0 -390
  215. package/lib/pgns.js +0 -196
  216. package/lib/pgns.test.js +0 -13
  217. package/lib/serial.js +0 -647
  218. package/lib/simpleCan.js +0 -105
  219. package/lib/stringMsg.js +0 -339
  220. package/lib/toPgn.js +0 -518
  221. package/lib/utilities.js +0 -111
  222. package/lib/w2k01.js +0 -129
@@ -0,0 +1,989 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright 2018 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
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.Parser = void 0;
22
+ exports.getField = getField;
23
+ // FIXME: MMSI sould be a string
24
+ const ts_pgns_1 = require("@canboat/ts-pgns");
25
+ const utilities_1 = require("./utilities");
26
+ const node_events_1 = require("node:events");
27
+ const package_json_1 = __importDefault(require("../package.json"));
28
+ const lodash_1 = __importDefault(require("lodash"));
29
+ const pgns_1 = require("./pgns");
30
+ const bit_buffer_1 = require("bit-buffer");
31
+ const int64_buffer_1 = require("int64-buffer");
32
+ const stringMsg_1 = require("./stringMsg");
33
+ const debug = (0, utilities_1.createDebug)('canboatjs:fromPgn');
34
+ const trace = (0, utilities_1.createDebug)('canboatjs:fromPgn:trace');
35
+ const fieldTypeReaders = {};
36
+ const fieldTypePostProcessors = {};
37
+ const FORMAT_PLAIN = 0;
38
+ const FORMAT_COALESCED = 1;
39
+ const RES_BINARY = 'Binary data';
40
+ const FASTPACKET_INDEX = 0;
41
+ const FASTPACKET_SIZE = 1;
42
+ const FASTPACKET_BUCKET_0_SIZE = 6;
43
+ const FASTPACKET_BUCKET_N_SIZE = 7;
44
+ const FASTPACKET_BUCKET_0_OFFSET = 2;
45
+ const FASTPACKET_BUCKET_N_OFFSET = 1;
46
+ const FASTPACKET_MAX_INDEX = 0x1f;
47
+ class Parser extends node_events_1.EventEmitter {
48
+ options;
49
+ name;
50
+ version;
51
+ author;
52
+ license;
53
+ format;
54
+ devices;
55
+ mixedFormat;
56
+ constructor(opts = {}) {
57
+ super();
58
+ this.options = opts === undefined ? {} : opts;
59
+ if (this.options.returnNulls === undefined) {
60
+ this.options.returnNulls = false;
61
+ }
62
+ if (this.options.useCamel === undefined) {
63
+ this.options.useCamel = true;
64
+ }
65
+ if (this.options.useCamelCompat === undefined) {
66
+ this.options.useCamelCompat = false;
67
+ }
68
+ this.name = package_json_1.default.name;
69
+ this.version = package_json_1.default.version;
70
+ this.author = package_json_1.default.author;
71
+ this.license = package_json_1.default.license;
72
+ this.format = this.options.format === undefined ? -1 : this.options.format;
73
+ this.devices = {};
74
+ this.mixedFormat = this.options.mixedFormat || false;
75
+ if (this.options.onPropertyValues) {
76
+ this.options.onPropertyValues('canboat-custom-pgns', (values) => {
77
+ values
78
+ .filter((v) => v != null)
79
+ .forEach((pv) => {
80
+ (0, pgns_1.addCustomPgns)(pv.value, pv.setter);
81
+ });
82
+ });
83
+ }
84
+ }
85
+ _parse(pgn, bs, len, coalesced, cb, sourceString = undefined) {
86
+ if (pgn.src === undefined) {
87
+ throw new Error('invalid pgn, missing src');
88
+ }
89
+ const customPgns = (0, pgns_1.getCustomPgn)(pgn.pgn);
90
+ let pgnList = (0, pgns_1.getPgn)(pgn.pgn);
91
+ if (!pgnList && !customPgns) {
92
+ this.emit('warning', pgn, `no conversion found for pgn ${JSON.stringify(pgn)}`);
93
+ return undefined;
94
+ }
95
+ if (customPgns) {
96
+ pgnList = [...customPgns.definitions, ...(pgnList || [])];
97
+ }
98
+ if (!pgnList || pgnList.length === 0) {
99
+ this.emit('warning', pgn, `no conversion found for pgn ${JSON.stringify(pgn)}`);
100
+ return undefined;
101
+ }
102
+ if (pgnList === undefined) {
103
+ return;
104
+ }
105
+ let pgnData;
106
+ const origPGNList = pgnList;
107
+ if (pgnList.length > 1) {
108
+ pgnData = this.findMatchPgn(pgnList);
109
+ if (pgnData === null) {
110
+ pgnData = pgnList[0];
111
+ }
112
+ }
113
+ else {
114
+ pgnData = pgnList[0];
115
+ }
116
+ if (pgnData === undefined) {
117
+ return;
118
+ }
119
+ let couldBeMulti = false;
120
+ if (pgnList.length > 0 && len == 8) {
121
+ pgnList.forEach((pgnD) => {
122
+ if (pgnD.Length && pgnD.Length > 8) {
123
+ couldBeMulti = true;
124
+ }
125
+ });
126
+ }
127
+ trace(`${pgn.pgn} ${len} ${pgnData.Length} ${couldBeMulti}`);
128
+ if (coalesced ||
129
+ len > 0x8 ||
130
+ (this.format == FORMAT_COALESCED && !this.mixedFormat)) {
131
+ this.format = FORMAT_COALESCED;
132
+ if (sourceString) {
133
+ pgn.input = [sourceString];
134
+ }
135
+ //} else if ( pgnData.Length > 0x8 || (len == 0x8 && (pgnData.RepeatingFields || couldBeMulti))) {
136
+ }
137
+ else if (pgnData.Type === 'Fast') {
138
+ //partial packet
139
+ this.format = FORMAT_PLAIN;
140
+ if (this.devices[pgn.src] === undefined) {
141
+ this.devices[pgn.src] = {};
142
+ }
143
+ let packet = this.devices[pgn.src][pgn.pgn];
144
+ if (!packet) {
145
+ packet = { bufferSize: 0, lastPacket: 0, src: [] };
146
+ this.devices[pgn.src][pgn.pgn] = packet;
147
+ }
148
+ if (sourceString) {
149
+ packet.src.push(sourceString);
150
+ }
151
+ const start = bs.byteIndex;
152
+ const packetIndex = bs.view.buffer.readUInt8(FASTPACKET_INDEX);
153
+ const bucket = packetIndex & FASTPACKET_MAX_INDEX;
154
+ trace(`${pgn.pgn} partial ${packetIndex} ${bucket} ${packet.size}`);
155
+ if (bucket == 0) {
156
+ packet.size = bs.view.buffer.readUInt8(FASTPACKET_SIZE);
157
+ const newSize = packet.size + FASTPACKET_BUCKET_N_SIZE;
158
+ if (newSize > packet.bufferSize) {
159
+ const newBuf = Buffer.alloc(newSize);
160
+ packet.bufferSize = newSize;
161
+ if (packet.buffer) {
162
+ packet.buffer.copy(newBuf);
163
+ }
164
+ packet.buffer = newBuf;
165
+ }
166
+ bs.view.buffer.copy(packet.buffer, 0, FASTPACKET_BUCKET_0_OFFSET, 8);
167
+ trace(`${pgn.pgn} targetStart: 0 sourceStart: ${FASTPACKET_BUCKET_0_OFFSET}`);
168
+ }
169
+ else if (!packet.buffer) {
170
+ //we got a non-zero bucket, but we never got the zero bucket
171
+ debug(`PGN ${pgn.pgn} malformed packet for ${pgn.src} received; got a non-zero bucket first`);
172
+ cb && cb(`Could not parse ${JSON.stringify(pgn)}`, undefined);
173
+ bs.byteIndex = start;
174
+ delete this.devices[pgn.src][pgn.pgn];
175
+ return;
176
+ }
177
+ else {
178
+ if (packet.lastPacket + 1 != packetIndex) {
179
+ debug(`PGN ${pgn.pgn} malformed packet for ${pgn.src} received; expected ${packet.lastPacket + 1} but got ${packetIndex}`);
180
+ cb && cb(`Could not parse ${JSON.stringify(pgn)}`, undefined);
181
+ bs.byteIndex = start;
182
+ delete this.devices[pgn.src][pgn.pgn];
183
+ return;
184
+ }
185
+ else {
186
+ trace(`${pgn.pgn} targetStart: ${FASTPACKET_BUCKET_0_SIZE + FASTPACKET_BUCKET_N_SIZE * (bucket - 1)} sourceStart: ${FASTPACKET_BUCKET_N_OFFSET} sourceEned: ${FASTPACKET_BUCKET_N_SIZE}`);
187
+ bs.view.buffer.copy(packet.buffer, FASTPACKET_BUCKET_0_SIZE + FASTPACKET_BUCKET_N_SIZE * (bucket - 1), FASTPACKET_BUCKET_N_OFFSET, 8);
188
+ }
189
+ }
190
+ packet.lastPacket = packetIndex;
191
+ if (FASTPACKET_BUCKET_0_SIZE + FASTPACKET_BUCKET_N_SIZE * bucket <
192
+ packet.size) {
193
+ // Packet is not complete yet
194
+ trace(`${pgn.pgn} not complete`);
195
+ return;
196
+ }
197
+ const view = new bit_buffer_1.BitView(packet.buffer);
198
+ bs = new bit_buffer_1.BitStream(view);
199
+ trace(`${pgn.pgn} done`);
200
+ pgn.input = packet.src;
201
+ delete this.devices[pgn.src][pgn.pgn];
202
+ }
203
+ else if (sourceString) {
204
+ pgn.input = [sourceString];
205
+ }
206
+ let RepeatingFields = pgnData.RepeatingFieldSet1Size
207
+ ? pgnData.RepeatingFieldSet1Size
208
+ : 0;
209
+ pgn.fields = {};
210
+ try {
211
+ let fields = pgnData.Fields;
212
+ for (let i = 0; i < fields.length - RepeatingFields; i++) {
213
+ const field = fields[i];
214
+ const hasMatch = field.Match !== undefined;
215
+ let value = readField(this.options, !hasMatch, pgn, field, bs, fields);
216
+ if (hasMatch) {
217
+ //console.log(`looking for ${field.Name} == ${value}`)
218
+ //console.log(JSON.stringify(pgnList, null, 2))
219
+ pgnList = pgnList.filter((f) => f.Fields[i].Match == value);
220
+ if (pgnList.length == 0) {
221
+ //this.emit('warning', pgn, `no conversion found for pgn`)
222
+ trace('warning no conversion found for pgn %j', pgn);
223
+ const nonMatch = this.findNonMatchPgn(origPGNList);
224
+ if (nonMatch) {
225
+ pgnList = [nonMatch];
226
+ pgnData = pgnList[0];
227
+ fields = pgnData.Fields;
228
+ const postProcessor = fieldTypePostProcessors[field.FieldType];
229
+ if (postProcessor) {
230
+ value = postProcessor(pgnData.Fields[i], value);
231
+ }
232
+ }
233
+ else {
234
+ const ts = lodash_1.default.get(pgn, 'timestamp', new Date());
235
+ pgn.timestamp = lodash_1.default.isDate(ts) ? ts.toISOString() : ts;
236
+ if (value === undefined &&
237
+ (value != null || this.options.returnNulls)) {
238
+ this.setField(pgn.fields, field, value);
239
+ }
240
+ this.emit('pgn', pgn);
241
+ cb && cb(undefined, pgn);
242
+ return pgn;
243
+ }
244
+ }
245
+ else {
246
+ pgnData = pgnList[0];
247
+ fields = pgnData.Fields;
248
+ //console.log(`using ${JSON.stringify(pgnData, null, 2)}`)
249
+ value = pgnData.Fields[i].Description;
250
+ if (value == null) {
251
+ value = pgnData.Fields[i].Match;
252
+ }
253
+ RepeatingFields = pgnData.RepeatingFieldSet1Size
254
+ ? pgnData.RepeatingFieldSet1Size
255
+ : 0;
256
+ }
257
+ }
258
+ if (value !== undefined &&
259
+ (value != null || this.options.returnNulls)) {
260
+ this.setField(pgn.fields, field, value);
261
+ }
262
+ }
263
+ if (RepeatingFields > 0) {
264
+ const repeating = fields.slice(fields.length - RepeatingFields);
265
+ const fany = pgn.fields;
266
+ fany.list = [];
267
+ let count;
268
+ if (pgnData.RepeatingFieldSet1CountField !== undefined) {
269
+ const rfield = pgnData.Fields[pgnData.RepeatingFieldSet1CountField - 1];
270
+ const dataKey = this.options.useCamel ? rfield.Id : rfield.Name;
271
+ count = pgn.fields[dataKey];
272
+ }
273
+ else {
274
+ count = 2048;
275
+ }
276
+ while (bs.bitsLeft > 0 && --count >= 0) {
277
+ const group = {};
278
+ repeating.forEach((field) => {
279
+ if (bs.bitsLeft > 0) {
280
+ const value = readField(this.options, true, pgn, field, bs, fields);
281
+ if (value !== undefined && value != null) {
282
+ this.setField(group, field, value);
283
+ }
284
+ }
285
+ });
286
+ if (lodash_1.default.keys(group).length > 0) {
287
+ ;
288
+ pgn.fields.list.push(group);
289
+ }
290
+ }
291
+ }
292
+ pgn.description = pgnData.Description;
293
+ //console.log(`pgn: ${JSON.stringify(pgn)}`)
294
+ // Stringify timestamp because SK Server needs it that way.
295
+ const ts = lodash_1.default.get(pgn, 'timestamp', new Date());
296
+ pgn.timestamp = lodash_1.default.isDate(ts) ? ts.toISOString() : ts;
297
+ this.emit('pgn', pgn);
298
+ cb && cb(undefined, pgn);
299
+ /*
300
+ if ( pgnData.callback ) {
301
+ pgnData.callback(pgn)
302
+ }
303
+ */
304
+ return pgn;
305
+ }
306
+ catch (error) {
307
+ this.emit('error', pgn, error);
308
+ cb && cb(error, undefined);
309
+ return;
310
+ }
311
+ }
312
+ setField(res, field, value) {
313
+ if (this.options.useCamelCompat) {
314
+ res[field.Id] = value;
315
+ res[field.Name] = value;
316
+ }
317
+ else if (this.options.useCamel) {
318
+ res[field.Id] = value;
319
+ }
320
+ else {
321
+ res[field.Name] = value;
322
+ }
323
+ }
324
+ findNonMatchPgn(pgnList) {
325
+ return pgnList.find((f) => {
326
+ return !f.Fields.find((f) => f.Match !== undefined);
327
+ });
328
+ }
329
+ findMatchPgn(pgnList) {
330
+ return pgnList.find((f) => {
331
+ return f.Fields.find((f) => f.Match !== undefined);
332
+ });
333
+ }
334
+ parse(data, cb = undefined) {
335
+ if (lodash_1.default.isString(data)) {
336
+ return this.parseString(data, cb);
337
+ }
338
+ else if (lodash_1.default.isBuffer(data)) {
339
+ return this.parseBuffer(data, cb);
340
+ }
341
+ else {
342
+ return this.parsePgnData(data.pgn, data.length, data.data, data.coalesced === true, cb, data.sourceString);
343
+ }
344
+ }
345
+ parsePgnData(pgn, length, data, coalesced, cb, sourceString) {
346
+ try {
347
+ let buffer = data;
348
+ if (!lodash_1.default.isBuffer(data)) {
349
+ const array = new Int16Array(length);
350
+ const strings = data;
351
+ strings.forEach((num, index) => {
352
+ array[index] = parseInt(num, 16);
353
+ });
354
+ buffer = Buffer.from(array);
355
+ }
356
+ const bv = new bit_buffer_1.BitView(buffer);
357
+ const bs = new bit_buffer_1.BitStream(bv);
358
+ const res = this._parse(pgn, bs, length, coalesced, cb, sourceString);
359
+ if (res) {
360
+ debug('parsed pgn %j', pgn);
361
+ }
362
+ return res;
363
+ }
364
+ catch (error) {
365
+ cb && cb(error, undefined);
366
+ this.emit('error', pgn, error);
367
+ }
368
+ }
369
+ isN2KOver0183(sentence) {
370
+ return (0, stringMsg_1.isN2KOver0183)(sentence);
371
+ }
372
+ parseN2KOver0183(sentence, cb) {
373
+ return this.parseString(sentence, cb);
374
+ }
375
+ // Venus MQTT-N2K
376
+ parseVenusMQTT(pgn_data, cb) {
377
+ try {
378
+ const pgn = {
379
+ pgn: pgn_data.pgn,
380
+ timestamp: new Date().toISOString(),
381
+ src: pgn_data.src,
382
+ dst: pgn_data.dst,
383
+ prio: pgn_data.prio,
384
+ fields: {}
385
+ };
386
+ const bs = new bit_buffer_1.BitStream(Buffer.from(pgn_data.data, 'base64'));
387
+ delete pgn_data.data;
388
+ const res = this._parse(pgn, bs, 8, false, cb);
389
+ if (res) {
390
+ debug('parsed pgn %j', pgn);
391
+ }
392
+ return res;
393
+ }
394
+ catch (error) {
395
+ cb && cb(error, undefined);
396
+ this.emit('error', pgn_data, error);
397
+ }
398
+ }
399
+ //Yacht Devices NMEA2000 Wifi gateway
400
+ parseYDGW02(pgn_data, cb) {
401
+ try {
402
+ const { data, direction, error, ...pgn } = (0, stringMsg_1.parseYDRAW)(pgn_data);
403
+ if (!error && direction === 'R') {
404
+ const bs = new bit_buffer_1.BitStream(data);
405
+ delete pgn.format;
406
+ const res = this._parse(pgn, bs, data.length, false, cb, pgn_data);
407
+ if (res) {
408
+ debug('parsed ydgw02 pgn %j', pgn_data);
409
+ return res;
410
+ }
411
+ }
412
+ else if (error) {
413
+ cb && cb(error, undefined);
414
+ this.emit('error', pgn_data, error);
415
+ }
416
+ }
417
+ catch (error) {
418
+ cb && cb(error, undefined);
419
+ this.emit('error', pgn_data, error);
420
+ }
421
+ return undefined;
422
+ }
423
+ //Actisense W2k-1
424
+ parseActisenceN2KAscii(pgn_data, cb) {
425
+ try {
426
+ const { data, error, ...pgn } = (0, stringMsg_1.parseActisenseN2KASCII)(pgn_data);
427
+ if (!error) {
428
+ const bs = new bit_buffer_1.BitStream(data);
429
+ delete pgn.format;
430
+ const res = this._parse(pgn, bs, data.length, false, cb, pgn_data);
431
+ if (res) {
432
+ debug('parsed n2k ascii pgn %j', pgn_data);
433
+ return res;
434
+ }
435
+ }
436
+ else if (error) {
437
+ cb && cb(error, undefined);
438
+ this.emit('error', pgn_data, error);
439
+ }
440
+ }
441
+ catch (error) {
442
+ cb && cb(error, undefined);
443
+ this.emit('error', pgn_data, error);
444
+ }
445
+ return undefined;
446
+ }
447
+ parsePDGY(pgn_data, cb) {
448
+ if (pgn_data[0] != '!') {
449
+ return;
450
+ }
451
+ try {
452
+ const { coalesced, data, error, len, ...pgn } = (0, stringMsg_1.parsePDGY)(pgn_data);
453
+ if (error) {
454
+ cb && cb(error, undefined);
455
+ this.emit('error', pgn, error);
456
+ return;
457
+ }
458
+ const bs = new bit_buffer_1.BitStream(data);
459
+ delete pgn.format;
460
+ delete pgn.type;
461
+ delete pgn.prefix;
462
+ const res = this._parse(pgn, bs, len || data.length, coalesced, cb, pgn_data);
463
+ if (res) {
464
+ debug('parsed pgn %j', pgn);
465
+ }
466
+ return res;
467
+ }
468
+ catch (error) {
469
+ cb && cb(error, undefined);
470
+ this.emit('error', pgn_data, error);
471
+ }
472
+ }
473
+ parseString(pgn_data, cb = undefined) {
474
+ try {
475
+ const { coalesced, data, error, len, ...pgn } = (0, stringMsg_1.parseN2kString)(pgn_data, this.options);
476
+ if (error) {
477
+ cb && cb(error, undefined);
478
+ this.emit('error', pgn, error);
479
+ return;
480
+ }
481
+ const bs = new bit_buffer_1.BitStream(data);
482
+ delete pgn.format;
483
+ delete pgn.type;
484
+ delete pgn.prefix;
485
+ const res = this._parse(pgn, bs, len || data.length, coalesced, cb, pgn_data);
486
+ if (res) {
487
+ debug('parsed pgn %j', pgn);
488
+ }
489
+ return res;
490
+ }
491
+ catch (error) {
492
+ cb && cb(error, undefined);
493
+ this.emit('error', pgn_data, error);
494
+ }
495
+ }
496
+ parseBuffer(pgn_data, cb) {
497
+ try {
498
+ const bv = new bit_buffer_1.BitView(pgn_data);
499
+ const bs = new bit_buffer_1.BitStream(bv);
500
+ const pgn = {};
501
+ // This might be good to move to canId.js ?
502
+ pgn.prio = bs.readUint8();
503
+ pgn.pgn = bs.readUint8() + 256 * (bs.readUint8() + 256 * bs.readUint8());
504
+ pgn.dst = bs.readUint8();
505
+ pgn.src = bs.readUint8();
506
+ pgn.timestamp = new Date().toISOString();
507
+ //const timestamp = FIXME?? use timestamp?
508
+ bs.readUint32();
509
+ const len = bs.readUint8();
510
+ const res = this._parse(pgn, bs, len, true, cb);
511
+ if (res) {
512
+ debug('parsed pgn %j', pgn);
513
+ }
514
+ return res;
515
+ }
516
+ catch (error) {
517
+ const err = new Error(`error reading pgn ${JSON.stringify(pgn_data)} ${error}`);
518
+ cb && cb(err, undefined);
519
+ this.emit('error', pgn_data, error);
520
+ console.error(err);
521
+ return;
522
+ }
523
+ }
524
+ }
525
+ exports.Parser = Parser;
526
+ function getField(pgn_number, index, data) {
527
+ let pgnList = (0, pgns_1.getPgn)(pgn_number);
528
+ if (pgnList) {
529
+ let pgn = pgnList[0];
530
+ const dataList = data.list ? data.list : data.fields.list;
531
+ if (pgnList.length > 1) {
532
+ let idx = 0;
533
+ while (idx < pgn.Fields.length) {
534
+ const field = pgn.Fields[idx];
535
+ const hasMatch = !lodash_1.default.isUndefined(field.Match);
536
+ if (hasMatch && dataList.length > 0) {
537
+ const param = dataList.find((f) => f.Parameter === idx + 1);
538
+ if (param) {
539
+ pgnList = pgnList.filter((f) => f.Fields[idx].Match == param.Value);
540
+ if (pgnList.length == 0) {
541
+ throw new Error('unable to read: ' + JSON.stringify(data));
542
+ return;
543
+ }
544
+ else {
545
+ pgn = pgnList[0];
546
+ }
547
+ }
548
+ }
549
+ idx++;
550
+ }
551
+ }
552
+ if (index >= 0 && index < pgn.Fields.length) {
553
+ return pgn.Fields[index];
554
+ }
555
+ const RepeatingFields = pgn.RepeatingFieldSet1Size
556
+ ? pgn.RepeatingFieldSet1Size
557
+ : 0;
558
+ if (RepeatingFields) {
559
+ const startOfRepeatingFields = pgn.Fields.length - RepeatingFields;
560
+ index =
561
+ startOfRepeatingFields +
562
+ ((index - startOfRepeatingFields) % RepeatingFields);
563
+ return pgn.Fields[index];
564
+ }
565
+ }
566
+ return null;
567
+ }
568
+ function pad2(x) {
569
+ const s = x.toString();
570
+ return s.length === 1 ? '0' + x : x;
571
+ }
572
+ function lookup(field, value) {
573
+ let name;
574
+ if (field.LookupEnumeration) {
575
+ name = (0, pgns_1.lookupEnumerationName)(field.LookupEnumeration, value);
576
+ }
577
+ else {
578
+ name = (0, pgns_1.lookupFieldTypeEnumerationName)(field.LookupFieldTypeEnumeration, value);
579
+ }
580
+ return name ? name : value;
581
+ }
582
+ function readField(options, runPostProcessor, pgn, field, bs, fields = undefined) {
583
+ let value;
584
+ const reader = fieldTypeReaders[field.FieldType];
585
+ if (reader) {
586
+ value = reader(pgn, field, bs);
587
+ }
588
+ else {
589
+ if (field.FieldType !== ts_pgns_1.FieldType.Binary &&
590
+ field.BitLength !== undefined &&
591
+ bs.bitsLeft < field.BitLength) {
592
+ //no more data
593
+ bs.readBits(bs.bitsLeft, false);
594
+ return;
595
+ }
596
+ value = readValue(options, pgn, field, bs, fields);
597
+ }
598
+ //console.log(`${field.Name} ${value} ${field.Resolution}`)
599
+ if (value != null && !lodash_1.default.isUndefined(value)) {
600
+ const type = field.FieldType; //hack, missing type
601
+ const postProcessor = fieldTypePostProcessors[type];
602
+ if (postProcessor) {
603
+ if (runPostProcessor) {
604
+ value = postProcessor(field, value);
605
+ }
606
+ }
607
+ else {
608
+ if (field.Offset) {
609
+ value += field.Offset;
610
+ }
611
+ let max;
612
+ if (typeof field.RangeMax !== 'undefined' && field.Resolution) {
613
+ max = field.RangeMax / field.Resolution;
614
+ }
615
+ if (options.checkForInvalidFields !== false &&
616
+ max !== undefined &&
617
+ field.FieldType !== 'LOOKUP' &&
618
+ field.FieldType !== 'DYNAMIC_FIELD_KEY' &&
619
+ field.FieldType !== 'PGN' &&
620
+ field.BitLength !== undefined &&
621
+ field.BitLength > 1 &&
622
+ max - value < 0) {
623
+ //console.log(`Bad field ${field.Name} ${max - value}`)
624
+ value = null;
625
+ }
626
+ if (field.Resolution && typeof value === 'number') {
627
+ let resolution = field.Resolution;
628
+ if (lodash_1.default.isString(resolution)) {
629
+ resolution = Number.parseFloat(resolution);
630
+ }
631
+ value = value * resolution;
632
+ let precision = 0;
633
+ for (let r = resolution; r > 0.0 && r < 1.0; r = r * 10.0) {
634
+ precision++;
635
+ }
636
+ value = Number.parseFloat(value.toFixed(precision));
637
+ }
638
+ if ((field.FieldType === 'LOOKUP' ||
639
+ field.FieldType === 'DYNAMIC_FIELD_KEY') &&
640
+ runPostProcessor &&
641
+ (lodash_1.default.isUndefined(options.resolveEnums) || options.resolveEnums)) {
642
+ if (field.Id === 'timeStamp' && value < 60) {
643
+ value = value.toString();
644
+ }
645
+ else {
646
+ value = lookup(field, value);
647
+ }
648
+ }
649
+ /*
650
+ if ( field.Name === 'Industry Code' && _.isNumber(value) && runPostProcessor ) {
651
+ const name = getIndustryName(value)
652
+ if ( name ) {
653
+ value = name
654
+ }
655
+ }
656
+ */
657
+ if (field.Unit === 'kWh') {
658
+ value *= 3.6e6; // 1 kWh = 3.6 MJ.
659
+ }
660
+ else if (field.Unit === 'Ah') {
661
+ value *= 3600.0; // 1 Ah = 3600 C.
662
+ }
663
+ }
664
+ }
665
+ return value;
666
+ }
667
+ function readValue(options, pgn, field, bs, fields, bitLength = undefined) {
668
+ if (field.FieldType == 'VARIABLE') {
669
+ return readVariableLengthField(options, pgn, field, bs);
670
+ }
671
+ else {
672
+ let value;
673
+ if (bitLength === undefined) {
674
+ if (field.BitLengthVariable &&
675
+ field.FieldType === 'DYNAMIC_FIELD_VALUE') {
676
+ bitLength = lookupKeyBitLength(pgn.fields, fields);
677
+ }
678
+ else {
679
+ bitLength = field.BitLength;
680
+ }
681
+ if (bitLength === undefined) {
682
+ //FIXME?? error? mesg? should never happen
683
+ return;
684
+ }
685
+ }
686
+ if (bitLength === 8) {
687
+ if (field.Signed) {
688
+ value = bs.readInt8();
689
+ value = value === 0x7f ? null : value;
690
+ }
691
+ else {
692
+ value = bs.readUint8();
693
+ value = value === 0xff ? null : value;
694
+ }
695
+ }
696
+ else if (bitLength == 16) {
697
+ if (field.Signed) {
698
+ value = bs.readInt16();
699
+ value = value === 0x7fff ? null : value;
700
+ }
701
+ else {
702
+ value = bs.readUint16();
703
+ value = value === 0xffff ? null : value;
704
+ }
705
+ }
706
+ else if (bitLength == 24) {
707
+ const b1 = bs.readUint8();
708
+ const b2 = bs.readUint8();
709
+ const b3 = bs.readUint8();
710
+ //debug(`24 bit ${b1.toString(16)} ${b2.toString(16)} ${b3.toString(16)}`)
711
+ value = (b3 << 16) + (b2 << 8) + b1;
712
+ //debug(`value ${value.toString(16)}`)
713
+ }
714
+ else if (bitLength == 32) {
715
+ if (field.Signed) {
716
+ value = bs.readInt32();
717
+ value = value === 0x7fffffff ? null : value;
718
+ }
719
+ else {
720
+ value = bs.readUint32();
721
+ value = value === 0xffffffff ? null : value;
722
+ }
723
+ }
724
+ else if (bitLength == 48) {
725
+ const a = bs.readUint32();
726
+ const b = bs.readUint16();
727
+ if (field.Signed) {
728
+ value = a == 0xffffffff && b == 0x7fff ? null : new int64_buffer_1.Int64LE(b, a);
729
+ }
730
+ else {
731
+ value = a == 0xffffffff && b == 0xffff ? null : new int64_buffer_1.Int64LE(b, a);
732
+ }
733
+ }
734
+ else if (bitLength == 64) {
735
+ const x = bs.readUint32();
736
+ const y = bs.readUint32();
737
+ if (field.Signed) {
738
+ value =
739
+ (x === 0xffffffff || x === 0xfffffffe) && y == 0x7fffffff
740
+ ? null
741
+ : new int64_buffer_1.Int64LE(y, x);
742
+ }
743
+ else {
744
+ value =
745
+ (x === 0xffffffff || x === 0xfffffffe) && y == 0xffffffff
746
+ ? null
747
+ : new int64_buffer_1.Uint64LE(y, x);
748
+ }
749
+ }
750
+ else if (bitLength <= 64) {
751
+ value = bs.readBits(bitLength, field.Signed);
752
+ if (bitLength > 1 && isMax(bitLength, value, field.Signed)) {
753
+ value = null;
754
+ }
755
+ }
756
+ else {
757
+ if (bs.bitsLeft < bitLength) {
758
+ bitLength = bs.bitsLeft;
759
+ if (bitLength === undefined) {
760
+ return null;
761
+ }
762
+ }
763
+ value = bs.readArrayBuffer(bitLength / 8); //, field.Signed)
764
+ const arr = [];
765
+ value = new Uint32Array(value)
766
+ .reduce(function (acc, i) {
767
+ acc.push(i.toString(16));
768
+ return acc;
769
+ }, arr)
770
+ .map((x) => (x.length === 1 ? '0' + x : x))
771
+ .join(' ');
772
+ return value;
773
+ }
774
+ if (value != null &&
775
+ typeof value !== 'undefined' &&
776
+ typeof value !== 'number') {
777
+ value = Number(value);
778
+ }
779
+ return value;
780
+ }
781
+ }
782
+ function isMax(numBits, value, signed) {
783
+ if (signed) {
784
+ numBits--;
785
+ }
786
+ while (numBits--) {
787
+ if ((value & 1) == 0) {
788
+ return false;
789
+ }
790
+ value = value >> 1;
791
+ }
792
+ return signed ? (value & 1) == 0 : true;
793
+ }
794
+ function readVariableLengthField(options, pgn, field, bs) {
795
+ /* PGN 126208 contains variable field length.
796
+ * The field length can be derived from the PGN mentioned earlier in the message,
797
+ * plus the field number.
798
+ */
799
+ /*
800
+ * This is rather hacky. We know that the 'data' pointer points to the n-th variable field
801
+ * length and thus that the field number is exactly one byte earlier.
802
+ */
803
+ try {
804
+ const refField = getField(pgn.fields.PGN, bs.view.buffer[bs.byteIndex - 1] - 1, pgn);
805
+ if (refField) {
806
+ const res = readField(options, false, pgn, refField, bs);
807
+ if (refField.BitLength !== undefined) {
808
+ const bits = (refField.BitLength + 7) & ~7; // Round # of bits in field refField up to complete bytes: 1->8, 7->8, 8->8 etc.
809
+ if (bits > refField.BitLength) {
810
+ bs.readBits(bits - refField.BitLength, false);
811
+ }
812
+ }
813
+ return res;
814
+ }
815
+ }
816
+ catch (error) {
817
+ debug(error);
818
+ }
819
+ }
820
+ fieldTypeReaders['STRING_LAU'
821
+ //'ASCII or UNICODE string starting with length and control byte'
822
+ ] = (pgn, field, bs) => {
823
+ if (bs.bitsLeft >= 16) {
824
+ const len = bs.readUint8() - 2;
825
+ const control = bs.readUint8();
826
+ let nameLen = len;
827
+ if (field.Name === 'AtoN Name' && len > 20) {
828
+ nameLen = 20;
829
+ }
830
+ else if (len <= 0) {
831
+ return null;
832
+ }
833
+ const buf = Buffer.alloc(len);
834
+ let idx = 0;
835
+ for (; idx < len && bs.bitsLeft >= 8; idx++) {
836
+ const c = bs.readUint8();
837
+ buf.writeUInt8(c, idx);
838
+ }
839
+ if (buf[buf.length - 1] === 0) {
840
+ nameLen = nameLen - 1;
841
+ }
842
+ return buf
843
+ .toString(control == 0 ? 'utf8' : 'ascii', 0, idx < nameLen ? idx : nameLen)
844
+ .trim();
845
+ }
846
+ else {
847
+ return null;
848
+ }
849
+ };
850
+ fieldTypeReaders['STRING_LZ'
851
+ //'ASCII string starting with length byte'
852
+ ] = (pgn, field, bs) => {
853
+ const len = bs.readUint8();
854
+ const buf = Buffer.alloc(len);
855
+ let idx = 0;
856
+ for (; idx < len && bs.bitsLeft >= 8; idx++) {
857
+ const c = bs.readUint8();
858
+ buf.writeUInt8(c, idx);
859
+ }
860
+ return buf.toString('utf-8', 0, idx);
861
+ };
862
+ fieldTypeReaders['String with start/stop byte'] = (pgn, field, bs) => {
863
+ const first = bs.readUint8();
864
+ if (first == 0xff) {
865
+ // no name, stop reading
866
+ return '';
867
+ }
868
+ else if (first == 0x02) {
869
+ const buf = Buffer.alloc(255);
870
+ let c;
871
+ let idx = 0;
872
+ while ((c = bs.readUint8()) != 0x01) {
873
+ buf.writeUInt8(c, idx++);
874
+ }
875
+ return buf.toString('ascii', 0, idx);
876
+ }
877
+ else if (first > 0x02) {
878
+ let len = first;
879
+ const second = bs.readUint8();
880
+ const buf = Buffer.alloc(len);
881
+ let idx = 0;
882
+ if (second == 0x01) {
883
+ len -= 2;
884
+ }
885
+ else {
886
+ buf.writeUInt8(second);
887
+ idx = 1;
888
+ }
889
+ for (; idx < len; idx++) {
890
+ const c = bs.readUint8();
891
+ buf.writeUInt8(c, idx);
892
+ }
893
+ return buf.toString('ascii', 0, idx);
894
+ }
895
+ };
896
+ fieldTypeReaders['STRING_FIX'] = (pgn, field, bs) => {
897
+ let len = field.BitLength / 8;
898
+ const buf = Buffer.alloc(len);
899
+ for (let i = 0; i < len && bs.bitsLeft >= 8; i++) {
900
+ buf.writeUInt8(bs.readUint8(), i);
901
+ }
902
+ let lastbyte = buf[len - 1];
903
+ while (len > 0 &&
904
+ (lastbyte == 0xff || lastbyte == 32 || lastbyte == 0 || lastbyte == 64)) {
905
+ len--;
906
+ lastbyte = buf[len - 1];
907
+ }
908
+ //look for a zero byte, some proprietary Raymarine pgns do this
909
+ let zero = 0;
910
+ while (zero < len) {
911
+ if (buf[zero] == 0) {
912
+ len = zero;
913
+ break;
914
+ }
915
+ zero++;
916
+ }
917
+ len = zero;
918
+ return len > 0 ? buf.toString('ascii', 0, len) : undefined;
919
+ };
920
+ fieldTypeReaders['BITLOOKUP'] = (pgn, field, bs) => {
921
+ const value = [];
922
+ for (let i = 0; i < field.BitLength; i++) {
923
+ if (bs.readBits(1, false)) {
924
+ value.push((0, pgns_1.lookupBitEnumerationName)(field.LookupBitEnumeration, i));
925
+ }
926
+ }
927
+ return value;
928
+ };
929
+ function lookupKeyBitLength(data, fields) {
930
+ const field = fields.find((field) => field.Name === 'Key');
931
+ if (field) {
932
+ let val = data['Key'] || data['key'];
933
+ if (typeof val === 'string') {
934
+ val = (0, pgns_1.lookupFieldTypeEnumerationValue)(field.LookupFieldTypeEnumeration, val);
935
+ }
936
+ return (0, pgns_1.lookupFieldTypeEnumerationBits)(field.LookupFieldTypeEnumeration, val);
937
+ }
938
+ }
939
+ fieldTypePostProcessors['DATE'] = (field, value) => {
940
+ if (value >= 0xfffd) {
941
+ value = undefined;
942
+ }
943
+ else {
944
+ const date = new Date(value * 86400 * 1000);
945
+ //const date = moment.unix(0).add(value+1, 'days').utc().toDate()
946
+ value = `${date.getUTCFullYear()}.${pad2(date.getUTCMonth() + 1)}.${pad2(date.getUTCDate())}`;
947
+ }
948
+ return value;
949
+ };
950
+ fieldTypePostProcessors['TIME'] = (field, value) => {
951
+ if (value >= 0xfffffffd) {
952
+ value = undefined;
953
+ }
954
+ else {
955
+ let seconds = value * field.Resolution;
956
+ let minutes = seconds / 60;
957
+ seconds = seconds % 60;
958
+ const hours = Math.floor(minutes / 60);
959
+ minutes = Math.floor(minutes % 60);
960
+ value = `${pad2(hours)}:${pad2(minutes)}:${pad2(Math.floor(seconds))}`;
961
+ if (seconds % 1 > 0) {
962
+ value = value + (seconds % 1).toFixed(5).substring(1);
963
+ }
964
+ }
965
+ return value;
966
+ };
967
+ fieldTypePostProcessors['DURATION'] = fieldTypePostProcessors['TIME'];
968
+ fieldTypePostProcessors['Pressure'] = (field, value) => {
969
+ if (field.Unit) {
970
+ switch (field.Unit[0]) {
971
+ case 'h':
972
+ case 'H':
973
+ value *= 100;
974
+ break;
975
+ case 'k':
976
+ case 'K':
977
+ value *= 1000;
978
+ break;
979
+ case 'd':
980
+ value /= 10;
981
+ break;
982
+ }
983
+ }
984
+ return value;
985
+ };
986
+ fieldTypePostProcessors[RES_BINARY] = (field, value) => {
987
+ return value.toString();
988
+ };
989
+ //# sourceMappingURL=fromPgn.js.map