node-mavlink 1.0.8 → 1.0.9
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 +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -1
- package/dist/lib/logger.d.ts +84 -0
- package/dist/lib/logger.js +118 -0
- package/dist/lib/mavesp.js +2 -2
- package/dist/lib/mavlink.d.ts +24 -5
- package/dist/lib/mavlink.js +72 -20
- package/dist/lib/serialization.js +1 -1
- package/dist/lib/utils.d.ts +35 -0
- package/dist/lib/utils.js +88 -0
- package/examples/GH-5.bin +0 -0
- package/examples/send-receive-file.ts +3 -3
- package/index.ts +2 -0
- package/lib/logger.ts +128 -0
- package/lib/mavesp.ts +2 -1
- package/lib/mavlink.ts +98 -28
- package/lib/serialization.ts +1 -1
- package/lib/utils.ts +75 -0
- package/package.json +8 -4
- package/tests/data.mavlink +0 -0
- package/tests/main.ts +63 -0
- package/tsconfig.json +2 -1
package/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
### This is a work in progress and above all misses a comprehensive test suite against another set of bindings! If you're looking for the officially supported bindings for JavaScript see the [pymavlink](https://github.com/ArduPilot/pymavlink/tree/master/generator/javascript) project.
|
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.
|
package/dist/index.d.ts
CHANGED
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.
|
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 = {};
|
package/dist/lib/mavesp.js
CHANGED
@@ -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
|
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,
|
55
|
+
(0, utils_1.waitFor)(() => this.ip !== '')
|
56
56
|
.then(() => { resolve(this.ip); })
|
57
57
|
.catch(e => { reject(e); });
|
58
58
|
});
|
package/dist/lib/mavlink.d.ts
CHANGED
@@ -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
|
196
|
+
private onCrcError;
|
192
197
|
private _validPackagesCount;
|
193
198
|
private _unknownPackagesCount;
|
194
199
|
private _invalidPackagesCount;
|
195
|
-
|
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 {};
|
package/dist/lib/mavlink.js
CHANGED
@@ -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 =
|
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
|
-
+ `
|
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
|
-
|
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.
|
408
|
+
this.onCrcError = null;
|
385
409
|
this._validPackagesCount = 0;
|
386
410
|
this._unknownPackagesCount = 0;
|
387
411
|
this._invalidPackagesCount = 0;
|
388
|
-
this.
|
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
|
-
|
491
|
-
|
492
|
-
(0,
|
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
|
-
|
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
|
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
|
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
|
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 '${
|
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);
|
@@ -160,7 +160,7 @@ exports.DESERIALIZERS = {
|
|
160
160
|
'float[]': (buffer, offset, length) => {
|
161
161
|
const result = new Array(length);
|
162
162
|
for (let i = 0; i < length; i++)
|
163
|
-
result[i] = buffer.readFloatLE(offset + i *
|
163
|
+
result[i] = buffer.readFloatLE(offset + i * 4);
|
164
164
|
return result;
|
165
165
|
},
|
166
166
|
'double[]': (buffer, offset, length) => {
|