node-mavlink 1.0.7 → 1.0.10-beta.1

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
@@ -1,3 +1,5 @@
1
+ <sup>If you're looking for the officially supported bindings for JavaScript see the [pymavlink](https://github.com/ArduPilot/pymavlink/tree/master/generator/javascript) project.</sup>
2
+
1
3
  # Node.js MavLink library
2
4
 
3
5
  This package is the implementation of serialization and parsing of MavLink messages for v1 and v2 protocols.
@@ -38,7 +40,9 @@ That's it! That is all it takes to read the raw data. But it doesn't end there -
38
40
  Each message consists of multiple fields that contain specific data. Parsing the data is also very easy.
39
41
 
40
42
  ```javascript
41
- import { minimal, common, ardupilotmega, uavionix, icarous } from 'node-mavlink'
43
+ import {
44
+ minimal, common, ardupilotmega, uavionix, icarous, asluav, ualberta
45
+ } from 'node-mavlink'
42
46
 
43
47
  // create a registry of mappings between a message id and a data class
44
48
  const REGISTRY = {
@@ -47,6 +51,8 @@ const REGISTRY = {
47
51
  ...ardupilotmega.REGISTRY,
48
52
  ...uavionix.REGISTRY,
49
53
  ...icarous.REGISTRY,
54
+ ...asluav.REGISTRY,
55
+ ...ualberta.REGISTRY,
50
56
  }
51
57
 
52
58
  reader.on('data', packet => {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export * from 'mavlink-mappings';
2
+ export * from './lib/utils';
3
+ export * from './lib/logger';
2
4
  export * from './lib/mavlink';
3
5
  export * from './lib/mavesp';
package/dist/index.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -11,5 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
11
15
  };
12
16
  Object.defineProperty(exports, "__esModule", { value: true });
13
17
  __exportStar(require("mavlink-mappings"), exports);
18
+ __exportStar(require("./lib/utils"), exports);
19
+ __exportStar(require("./lib/logger"), exports);
14
20
  __exportStar(require("./lib/mavlink"), exports);
15
21
  __exportStar(require("./lib/mavesp"), exports);
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Level of the log entry
3
+ */
4
+ export declare enum LogLevel {
5
+ trace = 5,
6
+ debug = 4,
7
+ info = 3,
8
+ warn = 2,
9
+ error = 1,
10
+ fatal = 0
11
+ }
12
+ declare type LoggerEvents = 'log';
13
+ declare type LoggerEventHandler = (context: string, level: LogLevel, message: any[]) => void;
14
+ /**
15
+ * Simplified interface for logging facilities
16
+ */
17
+ export declare class Logger {
18
+ private static readonly events;
19
+ private static registry;
20
+ /**
21
+ * Gets a logger by name
22
+ *
23
+ * @param context logger context
24
+ */
25
+ static getLogger(context: any): Logger;
26
+ /**
27
+ * Binds an event handler
28
+ *
29
+ * @param event event to react to
30
+ * @param handler event handler
31
+ */
32
+ static on(event: LoggerEvents, handler: (context: any, level: any, message: any) => void): void;
33
+ /**
34
+ * Removes an event handler
35
+ *
36
+ * @param event event to react to
37
+ * @param handler event handler
38
+ */
39
+ static off(event: LoggerEvents, handler: LoggerEventHandler): void;
40
+ private context;
41
+ /**
42
+ * Constructs a new logger instance
43
+ *
44
+ * @param context logger context
45
+ */
46
+ constructor(context: string);
47
+ /**
48
+ * Sends a log message if the trace level is enabled for this logger
49
+ *
50
+ * @param args parameters for the log entry
51
+ */
52
+ trace(...args: any): void;
53
+ /**
54
+ * Sends a log message if the debug level is enabled for this logger
55
+ *
56
+ * @param args parameters for the log entry
57
+ */
58
+ debug(...args: any): void;
59
+ /**
60
+ * Sends a log message if the info level is enabled for this logger
61
+ *
62
+ * @param args parameters for the log entry
63
+ */
64
+ info(...args: any): void;
65
+ /**
66
+ * Sends a log message if the warn level is enabled for this logger
67
+ *
68
+ * @param args parameters for the log entry
69
+ */
70
+ warn(...args: any): void;
71
+ /**
72
+ * Sends a log message if the error level is enabled for this logger
73
+ *
74
+ * @param args parameters for the log entry
75
+ */
76
+ error(...args: any): void;
77
+ /**
78
+ * Sends a log message if the fatal level is enabled for this logger
79
+ *
80
+ * @param args parameters for the log entry
81
+ */
82
+ fatal(...args: any): void;
83
+ }
84
+ export {};
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Logger = exports.LogLevel = void 0;
4
+ const EventEmitter = require("events");
5
+ /**
6
+ * Level of the log entry
7
+ */
8
+ var LogLevel;
9
+ (function (LogLevel) {
10
+ LogLevel[LogLevel["trace"] = 5] = "trace";
11
+ LogLevel[LogLevel["debug"] = 4] = "debug";
12
+ LogLevel[LogLevel["info"] = 3] = "info";
13
+ LogLevel[LogLevel["warn"] = 2] = "warn";
14
+ LogLevel[LogLevel["error"] = 1] = "error";
15
+ LogLevel[LogLevel["fatal"] = 0] = "fatal";
16
+ })(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
17
+ /**
18
+ * Simplified interface for logging facilities
19
+ */
20
+ class Logger {
21
+ /**
22
+ * Constructs a new logger instance
23
+ *
24
+ * @param context logger context
25
+ */
26
+ constructor(context) {
27
+ this.context = context;
28
+ Logger.events.emit('logger-created', Logger.registry[context]);
29
+ }
30
+ /**
31
+ * Gets a logger by name
32
+ *
33
+ * @param context logger context
34
+ */
35
+ static getLogger(context) {
36
+ let name = '';
37
+ if (typeof context === 'function')
38
+ name = context.name;
39
+ else if (typeof context === 'object')
40
+ name = context.constructor.name;
41
+ else if (typeof context === 'string')
42
+ name = context;
43
+ else
44
+ throw new Error(`Do not know how to get logger for ${context} (${typeof context})`);
45
+ if (!Logger.registry[name])
46
+ Logger.registry[name] = new Logger(name);
47
+ return Logger.registry[name];
48
+ }
49
+ /**
50
+ * Binds an event handler
51
+ *
52
+ * @param event event to react to
53
+ * @param handler event handler
54
+ */
55
+ static on(event, handler) {
56
+ this.events.on(event, handler);
57
+ }
58
+ /**
59
+ * Removes an event handler
60
+ *
61
+ * @param event event to react to
62
+ * @param handler event handler
63
+ */
64
+ static off(event, handler) {
65
+ this.events.off(event, handler);
66
+ }
67
+ /**
68
+ * Sends a log message if the trace level is enabled for this logger
69
+ *
70
+ * @param args parameters for the log entry
71
+ */
72
+ trace(...args) {
73
+ Logger.events.emit('log', { context: this.context, level: LogLevel.trace, message: args });
74
+ }
75
+ /**
76
+ * Sends a log message if the debug level is enabled for this logger
77
+ *
78
+ * @param args parameters for the log entry
79
+ */
80
+ debug(...args) {
81
+ Logger.events.emit('log', { context: this.context, level: LogLevel.debug, message: args });
82
+ }
83
+ /**
84
+ * Sends a log message if the info level is enabled for this logger
85
+ *
86
+ * @param args parameters for the log entry
87
+ */
88
+ info(...args) {
89
+ Logger.events.emit('log', { context: this.context, level: LogLevel.info, message: args });
90
+ }
91
+ /**
92
+ * Sends a log message if the warn level is enabled for this logger
93
+ *
94
+ * @param args parameters for the log entry
95
+ */
96
+ warn(...args) {
97
+ Logger.events.emit('log', { context: this.context, level: LogLevel.warn, message: args });
98
+ }
99
+ /**
100
+ * Sends a log message if the error level is enabled for this logger
101
+ *
102
+ * @param args parameters for the log entry
103
+ */
104
+ error(...args) {
105
+ Logger.events.emit('log', { context: this.context, level: LogLevel.error, message: args });
106
+ }
107
+ /**
108
+ * Sends a log message if the fatal level is enabled for this logger
109
+ *
110
+ * @param args parameters for the log entry
111
+ */
112
+ fatal(...args) {
113
+ Logger.events.emit('log', { context: this.context, level: LogLevel.fatal, message: args });
114
+ }
115
+ }
116
+ exports.Logger = Logger;
117
+ Logger.events = new EventEmitter();
118
+ Logger.registry = {};
@@ -15,7 +15,7 @@ const dgram_1 = require("dgram");
15
15
  const stream_1 = require("stream");
16
16
  const mavlink_1 = require("./mavlink");
17
17
  const mavlink_2 = require("./mavlink");
18
- const mavlink_mappings_1 = require("mavlink-mappings");
18
+ const utils_1 = require("./utils");
19
19
  /**
20
20
  * Encapsulation of communication with MavEsp8266
21
21
  */
@@ -52,7 +52,7 @@ class MavEsp8266 extends events_1.EventEmitter {
52
52
  this.socket.bind(receivePort, () => {
53
53
  // Wait for the first package to be returned to read the ip address
54
54
  // of the controller
55
- (0, mavlink_mappings_1.waitFor)(() => this.ip !== '')
55
+ (0, utils_1.waitFor)(() => this.ip !== '')
56
56
  .then(() => { resolve(this.ip); })
57
57
  .catch(e => { reject(e); });
58
58
  });
@@ -1,7 +1,8 @@
1
1
  /// <reference types="node" />
2
- import { Transform, TransformCallback, Writable } from 'stream';
2
+ import { Transform, TransformCallback, Readable, Writable } from 'stream';
3
3
  import { uint8_t, uint16_t } from 'mavlink-mappings';
4
4
  import { MavLinkData, MavLinkDataConstructor } from 'mavlink-mappings';
5
+ import { Logger } from './logger';
5
6
  /**
6
7
  * Header definition of the MavLink packet
7
8
  */
@@ -22,6 +23,7 @@ export declare class MavLinkPacketHeader {
22
23
  * data classes from the given payload buffer
23
24
  */
24
25
  export declare abstract class MavLinkProtocol {
26
+ protected readonly log: Logger;
25
27
  static NAME: string;
26
28
  static START_BYTE: number;
27
29
  static PAYLOAD_OFFSET: number;
@@ -93,9 +95,10 @@ export declare class MavLinkProtocolV2 extends MavLinkProtocol {
93
95
  * @param buffer buffer with the original, unsigned package
94
96
  * @param linkId id of the link
95
97
  * @param key key to sign the package with
98
+ * @param timestamp optional timestamp for packet signing (default: Date.now())
96
99
  * @returns signed package
97
100
  */
98
- sign(buffer: Buffer, linkId: number, key: Buffer): Buffer;
101
+ sign(buffer: Buffer, linkId: number, key: Buffer, timestamp?: number): Buffer;
99
102
  private calculateTruncatedPayloadLength;
100
103
  header(buffer: Buffer): MavLinkPacketHeader;
101
104
  /**
@@ -183,16 +186,23 @@ export declare class MavLinkPacket {
183
186
  debug(): string;
184
187
  private signatureToString;
185
188
  }
189
+ declare type BufferCallback = (buffer: Buffer) => void;
186
190
  /**
187
191
  * A transform stream that splits the incomming data stream into chunks containing full MavLink messages
188
192
  */
189
193
  export declare class MavLinkPacketSplitter extends Transform {
194
+ protected readonly log: Logger;
190
195
  private buffer;
191
- private verbose;
196
+ private onCrcError;
192
197
  private _validPackagesCount;
193
198
  private _unknownPackagesCount;
194
199
  private _invalidPackagesCount;
195
- constructor(opts?: {}, verbose?: boolean);
200
+ /**
201
+ * @param opts options to pass on to the Transform constructor
202
+ * @param verbose print diagnostic information
203
+ * @param onCrcError callback executed if there is a CRC error (mostly for debugging)
204
+ */
205
+ constructor(opts?: {}, onCrcError?: BufferCallback);
196
206
  _transform(chunk: Buffer, encoding: any, callback: TransformCallback): void;
197
207
  private findStartOfPacket;
198
208
  private getPacketProtocol;
@@ -233,10 +243,17 @@ export declare class MavLinkPacketSplitter extends Transform {
233
243
  * A transform stream that takes a buffer with data and converts it to MavLinkPacket object
234
244
  */
235
245
  export declare class MavLinkPacketParser extends Transform {
246
+ protected readonly log: Logger;
236
247
  constructor(opts?: {});
237
248
  private getProtocol;
238
249
  _transform(chunk: Buffer, encoding: any, callback: TransformCallback): void;
239
250
  }
251
+ /**
252
+ * Creates a MavLink packet stream reader that is reading packets from the given input
253
+ *
254
+ * @param input input stream to read from
255
+ */
256
+ export declare function createMavLinkStream(input: Readable, onCrcError: BufferCallback): MavLinkPacketParser;
240
257
  /**
241
258
  * Send a packet to the stream
242
259
  *
@@ -255,6 +272,8 @@ export declare function send(stream: Writable, msg: MavLinkData, protocol?: MavL
255
272
  * @param linkId link id for the signature
256
273
  * @param sysid system id
257
274
  * @param compid component id
275
+ * @param timestamp optional timestamp for packet signing (default: Date.now())
258
276
  * @returns number of bytes sent
259
277
  */
260
- export declare function sendSigned(stream: Writable, msg: MavLinkData, key: Buffer, linkId?: uint8_t, sysid?: uint8_t, compid?: uint8_t): Promise<unknown>;
278
+ export declare function sendSigned(stream: Writable, msg: MavLinkData, key: Buffer, linkId?: uint8_t, sysid?: uint8_t, compid?: uint8_t, timestamp?: number): Promise<unknown>;
279
+ export {};
@@ -9,11 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.sendSigned = exports.send = exports.MavLinkPacketParser = exports.MavLinkPacketSplitter = exports.MavLinkPacket = exports.MavLinkPacketSignature = exports.MavLinkProtocolV2 = exports.MavLinkProtocolV1 = exports.MavLinkProtocol = exports.MavLinkPacketHeader = void 0;
12
+ exports.sendSigned = exports.send = exports.createMavLinkStream = exports.MavLinkPacketParser = exports.MavLinkPacketSplitter = exports.MavLinkPacket = exports.MavLinkPacketSignature = exports.MavLinkProtocolV2 = exports.MavLinkProtocolV1 = exports.MavLinkProtocol = exports.MavLinkPacketHeader = void 0;
13
13
  const stream_1 = require("stream");
14
14
  const crypto_1 = require("crypto");
15
15
  const mavlink_mappings_1 = require("mavlink-mappings");
16
16
  const mavlink_mappings_2 = require("mavlink-mappings");
17
+ const utils_1 = require("./utils");
18
+ const logger_1 = require("./logger");
17
19
  const serialization_1 = require("./serialization");
18
20
  /**
19
21
  * Header definition of the MavLink packet
@@ -38,10 +40,14 @@ exports.MavLinkPacketHeader = MavLinkPacketHeader;
38
40
  * data classes from the given payload buffer
39
41
  */
40
42
  class MavLinkProtocol {
43
+ constructor() {
44
+ this.log = logger_1.Logger.getLogger(this);
45
+ }
41
46
  /**
42
47
  * Deserialize payload into actual data class
43
48
  */
44
49
  data(payload, clazz) {
50
+ this.log.trace('Deserializing', clazz.MSG_NAME, 'with payload of size', payload.length);
45
51
  const instance = new clazz();
46
52
  clazz.FIELDS.forEach(field => {
47
53
  const deserialize = serialization_1.DESERIALIZERS[field.type];
@@ -70,6 +76,7 @@ class MavLinkProtocolV1 extends MavLinkProtocol {
70
76
  this.compid = compid;
71
77
  }
72
78
  serialize(message, seq) {
79
+ this.log.trace('Serializing message (seq:', seq, ')');
73
80
  const definition = message.constructor;
74
81
  const buffer = Buffer.from(new Uint8Array(MavLinkProtocolV1.PAYLOAD_OFFSET + definition.PAYLOAD_LENGTH + MavLinkProtocol.CHECKSUM_LENGTH));
75
82
  // serialize header
@@ -92,6 +99,7 @@ class MavLinkProtocolV1 extends MavLinkProtocol {
92
99
  return buffer;
93
100
  }
94
101
  header(buffer) {
102
+ this.log.trace('Reading header from buffer (len:', buffer.length, ')');
95
103
  const startByte = buffer.readUInt8(0);
96
104
  if (startByte !== MavLinkProtocolV1.START_BYTE) {
97
105
  throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV1.START_BYTE}, got ${startByte})`);
@@ -109,10 +117,12 @@ class MavLinkProtocolV1 extends MavLinkProtocol {
109
117
  * Deserialize packet checksum
110
118
  */
111
119
  crc(buffer) {
120
+ this.log.trace('Reading crc from buffer (len:', buffer.length, ')');
112
121
  const plen = buffer.readUInt8(1);
113
122
  return buffer.readUInt16LE(MavLinkProtocolV1.PAYLOAD_OFFSET + plen);
114
123
  }
115
124
  payload(buffer) {
125
+ this.log.trace('Reading payload from buffer (len:', buffer.length, ')');
116
126
  const plen = buffer.readUInt8(1);
117
127
  const payload = buffer.slice(MavLinkProtocolV1.PAYLOAD_OFFSET, MavLinkProtocolV1.PAYLOAD_OFFSET + plen);
118
128
  const padding = Buffer.from(new Uint8Array(255 - payload.length));
@@ -135,6 +145,7 @@ class MavLinkProtocolV2 extends MavLinkProtocol {
135
145
  this.compatibilityFlags = compatibilityFlags;
136
146
  }
137
147
  serialize(message, seq) {
148
+ this.log.trace('Serializing message (seq:', seq, ')');
138
149
  const definition = message.constructor;
139
150
  const buffer = Buffer.from(new Uint8Array(MavLinkProtocolV2.PAYLOAD_OFFSET + definition.PAYLOAD_LENGTH + MavLinkProtocol.CHECKSUM_LENGTH));
140
151
  buffer.writeUInt8(MavLinkProtocolV2.START_BYTE, 0);
@@ -165,16 +176,18 @@ class MavLinkProtocolV2 extends MavLinkProtocol {
165
176
  * @param buffer buffer with the original, unsigned package
166
177
  * @param linkId id of the link
167
178
  * @param key key to sign the package with
179
+ * @param timestamp optional timestamp for packet signing (default: Date.now())
168
180
  * @returns signed package
169
181
  */
170
- sign(buffer, linkId, key) {
182
+ sign(buffer, linkId, key, timestamp = Date.now()) {
183
+ this.log.trace('Signing message');
171
184
  const result = Buffer.concat([
172
185
  buffer,
173
186
  Buffer.from(new Uint8Array(MavLinkPacketSignature.SIGNATURE_LENGTH))
174
187
  ]);
175
188
  const signer = new MavLinkPacketSignature(result);
176
189
  signer.linkId = linkId;
177
- signer.timestamp = Date.now();
190
+ signer.timestamp = timestamp;
178
191
  signer.signature = signer.calculate(key);
179
192
  return result;
180
193
  }
@@ -190,6 +203,7 @@ class MavLinkProtocolV2 extends MavLinkProtocol {
190
203
  return result - MavLinkProtocolV2.PAYLOAD_OFFSET;
191
204
  }
192
205
  header(buffer) {
206
+ this.log.trace('Reading header from buffer (len:', buffer.length, ')');
193
207
  const startByte = buffer.readUInt8(0);
194
208
  if (startByte !== MavLinkProtocolV2.START_BYTE) {
195
209
  throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV2.START_BYTE}, got ${startByte})`);
@@ -209,16 +223,19 @@ class MavLinkProtocolV2 extends MavLinkProtocol {
209
223
  * Deserialize packet checksum
210
224
  */
211
225
  crc(buffer) {
226
+ this.log.trace('Reading crc from buffer (len:', buffer.length, ')');
212
227
  const plen = buffer.readUInt8(1);
213
228
  return buffer.readUInt16LE(MavLinkProtocolV2.PAYLOAD_OFFSET + plen);
214
229
  }
215
230
  payload(buffer) {
231
+ this.log.trace('Reading payload from buffer (len:', buffer.length, ')');
216
232
  const plen = buffer.readUInt8(1);
217
233
  const payload = buffer.slice(MavLinkProtocolV2.PAYLOAD_OFFSET, MavLinkProtocolV2.PAYLOAD_OFFSET + plen);
218
234
  const padding = Buffer.from(new Uint8Array(255 - payload.length));
219
235
  return Buffer.concat([payload, padding]);
220
236
  }
221
237
  signature(buffer, header) {
238
+ this.log.trace('Reading signature from buffer (len:', buffer.length, ')');
222
239
  if (header.incompatibilityFlags & MavLinkProtocolV2.IFLAG_SIGNED) {
223
240
  return new MavLinkPacketSignature(buffer);
224
241
  }
@@ -356,7 +373,8 @@ class MavLinkPacket {
356
373
  + `msgid: ${this.header.msgid}, `
357
374
  + `seq: ${this.header.seq}, `
358
375
  + `plen: ${this.header.payloadLength}, `
359
- + `crc: ${this.crc.toString(16).padStart(2, '0')}`
376
+ + `magic: ${mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[this.header.msgid]} (${(0, utils_1.hex)(mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[this.header.msgid])}), `
377
+ + `crc: ${(0, utils_1.hex)(this.crc, 4)}`
360
378
  + this.signatureToString(this.signature)
361
379
  + ')';
362
380
  }
@@ -378,14 +396,20 @@ var PacketValidationResult;
378
396
  * A transform stream that splits the incomming data stream into chunks containing full MavLink messages
379
397
  */
380
398
  class MavLinkPacketSplitter extends stream_1.Transform {
381
- constructor(opts = {}, verbose = false) {
399
+ /**
400
+ * @param opts options to pass on to the Transform constructor
401
+ * @param verbose print diagnostic information
402
+ * @param onCrcError callback executed if there is a CRC error (mostly for debugging)
403
+ */
404
+ constructor(opts = {}, onCrcError = () => { }) {
382
405
  super(opts);
406
+ this.log = logger_1.Logger.getLogger(this);
383
407
  this.buffer = Buffer.from([]);
384
- this.verbose = false;
408
+ this.onCrcError = null;
385
409
  this._validPackagesCount = 0;
386
410
  this._unknownPackagesCount = 0;
387
411
  this._invalidPackagesCount = 0;
388
- this.verbose = verbose;
412
+ this.onCrcError = onCrcError;
389
413
  }
390
414
  _transform(chunk, encoding, callback) {
391
415
  this.buffer = Buffer.concat([this.buffer, chunk]);
@@ -399,34 +423,46 @@ class MavLinkPacketSplitter extends stream_1.Transform {
399
423
  if (offset > 0) {
400
424
  this.buffer = this.buffer.slice(offset);
401
425
  }
426
+ this.log.debug('Found potential packet start at', offset);
402
427
  // get protocol this buffer is encoded with
403
428
  const Protocol = this.getPacketProtocol(this.buffer);
429
+ this.log.debug('Packet protocol is', Protocol.NAME);
404
430
  // check if the buffer contains at least the minumum size of data
405
431
  if (this.buffer.length < Protocol.PAYLOAD_OFFSET + MavLinkProtocol.CHECKSUM_LENGTH) {
406
432
  // current buffer shorter than the shortest message - skipping
433
+ this.log.debug('Current buffer shorter than the shortest message - skipping');
407
434
  break;
408
435
  }
409
436
  // check if the current buffer contains the entire message
410
437
  const expectedBufferLength = this.readPacketLength(this.buffer, Protocol);
438
+ this.log.debug('Expected buffer length:', expectedBufferLength, `(${(0, utils_1.hex)(expectedBufferLength)})`);
411
439
  if (this.buffer.length < expectedBufferLength) {
412
440
  // current buffer is not fully retrieved yet - skipping
441
+ this.log.debug('Current buffer is not fully retrieved yet - skipping');
413
442
  break;
414
443
  }
444
+ else {
445
+ this.log.debug('Current buffer length:', this.buffer.length, `(${(0, utils_1.hex)(this.buffer.length, 4)})`);
446
+ }
415
447
  // retrieve the buffer based on payload size
416
448
  const buffer = this.buffer.slice(0, expectedBufferLength);
449
+ this.log.debug('Recognized buffer length:', buffer.length, `(${(0, utils_1.hex)(buffer.length, 2)})`);
417
450
  switch (this.validatePacket(buffer, Protocol)) {
418
451
  case PacketValidationResult.VALID:
452
+ this.log.debug('Found a valid packet');
419
453
  this._validPackagesCount++;
420
454
  this.push(buffer);
421
455
  // truncate the buffer to remove the current message
422
456
  this.buffer = this.buffer.slice(expectedBufferLength);
423
457
  break;
424
458
  case PacketValidationResult.INVALID:
459
+ this.log.debug('Found an invalid packet - skipping');
425
460
  this._invalidPackagesCount++;
426
461
  // truncate the buffer to remove the wrongly identified STX
427
462
  this.buffer = this.buffer.slice(1);
428
463
  break;
429
464
  case PacketValidationResult.UNKNOWN:
465
+ this.log.debug('Found an unknown packet - skipping');
430
466
  this._unknownPackagesCount++;
431
467
  // truncate the buffer to remove the current message
432
468
  this.buffer = this.buffer.slice(expectedBufferLength);
@@ -487,18 +523,21 @@ class MavLinkPacketSplitter extends stream_1.Transform {
487
523
  }
488
524
  else {
489
525
  // CRC mismatch
490
- if (this.verbose) {
491
- console.error('CRC error; expected', crc2, `(0x${crc2.toString(16).padStart(4, '0')})`, 'got', crc, `(0x${crc.toString(16).padStart(4, '0')})`, '; msgid:', header.msgid, ', magic:', magic);
492
- (0, mavlink_mappings_1.dump)(buffer);
493
- }
526
+ const message = [
527
+ `CRC error; expected: ${crc2} (${(0, utils_1.hex)(crc2, 4)}), got ${crc} (${(0, utils_1.hex)(crc, 4)});`,
528
+ `msgid: ${header.msgid} (${(0, utils_1.hex)(header.msgid)}),`,
529
+ `seq: ${header.seq} (${(0, utils_1.hex)(header.seq)}),`,
530
+ `plen: ${header.payloadLength} (${(0, utils_1.hex)(header.payloadLength)}),`,
531
+ `magic: ${magic} (${(0, utils_1.hex)(magic)})`,
532
+ ];
533
+ this.log.warn(message.join(' '));
534
+ this.onCrcError(buffer);
494
535
  return PacketValidationResult.INVALID;
495
536
  }
496
537
  }
497
538
  else {
498
539
  // unknown message (as in not generated from the XML sources)
499
- if (this.verbose) {
500
- console.error(`Unknown message with id ${header.msgid} (magic number not found) - skipping`);
501
- }
540
+ this.log.debug(`Unknown message with id ${header.msgid} (magic number not found) - skipping`);
502
541
  return PacketValidationResult.UNKNOWN;
503
542
  }
504
543
  }
@@ -524,7 +563,7 @@ class MavLinkPacketSplitter extends stream_1.Transform {
524
563
  * Reset the number of valid packages
525
564
  */
526
565
  resetValidPackagesCount() {
527
- this, this._validPackagesCount = 0;
566
+ this._validPackagesCount = 0;
528
567
  }
529
568
  /**
530
569
  * Number of invalid packages
@@ -536,7 +575,7 @@ class MavLinkPacketSplitter extends stream_1.Transform {
536
575
  * Reset the number of invalid packages
537
576
  */
538
577
  resetInvalidPackagesCount() {
539
- this, this._invalidPackagesCount = 0;
578
+ this._invalidPackagesCount = 0;
540
579
  }
541
580
  /**
542
581
  * Number of invalid packages
@@ -548,7 +587,7 @@ class MavLinkPacketSplitter extends stream_1.Transform {
548
587
  * Reset the number of invalid packages
549
588
  */
550
589
  resetUnknownPackagesCount() {
551
- this, this._unknownPackagesCount = 0;
590
+ this._unknownPackagesCount = 0;
552
591
  }
553
592
  }
554
593
  exports.MavLinkPacketSplitter = MavLinkPacketSplitter;
@@ -558,6 +597,7 @@ exports.MavLinkPacketSplitter = MavLinkPacketSplitter;
558
597
  class MavLinkPacketParser extends stream_1.Transform {
559
598
  constructor(opts = {}) {
560
599
  super(Object.assign(Object.assign({}, opts), { objectMode: true }));
600
+ this.log = logger_1.Logger.getLogger(this);
561
601
  }
562
602
  getProtocol(buffer) {
563
603
  const startByte = buffer.readUInt8(0);
@@ -567,7 +607,7 @@ class MavLinkPacketParser extends stream_1.Transform {
567
607
  case MavLinkProtocolV2.START_BYTE:
568
608
  return new MavLinkProtocolV2();
569
609
  default:
570
- throw new Error(`Unknown protocol '${startByte.toString(16).padStart(2, '0')}'`);
610
+ throw new Error(`Unknown protocol '${(0, utils_1.hex)(startByte)}'`);
571
611
  }
572
612
  }
573
613
  _transform(chunk, encoding, callback) {
@@ -583,6 +623,17 @@ class MavLinkPacketParser extends stream_1.Transform {
583
623
  }
584
624
  }
585
625
  exports.MavLinkPacketParser = MavLinkPacketParser;
626
+ /**
627
+ * Creates a MavLink packet stream reader that is reading packets from the given input
628
+ *
629
+ * @param input input stream to read from
630
+ */
631
+ function createMavLinkStream(input, onCrcError) {
632
+ return input
633
+ .pipe(new MavLinkPacketSplitter({}, onCrcError))
634
+ .pipe(new MavLinkPacketParser());
635
+ }
636
+ exports.createMavLinkStream = createMavLinkStream;
586
637
  let seq = 0;
587
638
  /**
588
639
  * Send a packet to the stream
@@ -616,15 +667,16 @@ exports.send = send;
616
667
  * @param linkId link id for the signature
617
668
  * @param sysid system id
618
669
  * @param compid component id
670
+ * @param timestamp optional timestamp for packet signing (default: Date.now())
619
671
  * @returns number of bytes sent
620
672
  */
621
- function sendSigned(stream, msg, key, linkId = 1, sysid = MavLinkProtocol.SYS_ID, compid = MavLinkProtocol.COMP_ID) {
673
+ function sendSigned(stream, msg, key, linkId = 1, sysid = MavLinkProtocol.SYS_ID, compid = MavLinkProtocol.COMP_ID, timestamp = Date.now()) {
622
674
  return __awaiter(this, void 0, void 0, function* () {
623
675
  return new Promise((resolve, reject) => {
624
676
  const protocol = new MavLinkProtocolV2(sysid, compid, MavLinkProtocolV2.IFLAG_SIGNED);
625
677
  const b1 = protocol.serialize(msg, seq++);
626
678
  seq &= 255;
627
- const b2 = protocol.sign(b1, linkId, key);
679
+ const b2 = protocol.sign(b1, linkId, key, timestamp);
628
680
  stream.write(b2, err => {
629
681
  if (err)
630
682
  reject(err);