node-mavlink 1.1.0 → 1.1.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.
@@ -2,17 +2,18 @@
2
2
  "version": "0.2.0",
3
3
  "configurations": [
4
4
  {
5
- "name": "Example",
6
5
  "type": "node",
7
6
  "request": "launch",
8
- "runtimeExecutable": "node",
9
- "runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
10
-
11
- "args": ["send-receive-file.ts", "--example", "hello"],
12
-
13
- "cwd": "${workspaceRoot}/examples",
14
- "internalConsoleOptions": "openOnSessionStart",
15
- "skipFiles": ["<node_internals>/**", "node_modules/**"],
7
+ "name": "Launch Program",
8
+ "runtimeArgs": [
9
+ "-r",
10
+ "ts-node/register"
11
+ ],
12
+ "args": [
13
+ "${workspaceFolder}/tests/main.ts",
14
+ "e2e",
15
+ "--input=tests/data.mavlink"
16
+ ]
16
17
  }
17
- ]
18
+ ],
18
19
  }
package/dist/index.js CHANGED
@@ -1,21 +1 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = 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);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("mavlink-mappings"), exports);
18
- __exportStar(require("./lib/utils"), exports);
19
- __exportStar(require("./lib/logger"), exports);
20
- __exportStar(require("./lib/mavlink"), exports);
21
- __exportStar(require("./lib/mavesp"), exports);
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(i,r,e,t){t===void 0&&(t=e);var n=Object.getOwnPropertyDescriptor(r,e);(!n||("get"in n?!r.__esModule:n.writable||n.configurable))&&(n={enumerable:!0,get:function(){return r[e]}}),Object.defineProperty(i,t,n)}:function(i,r,e,t){t===void 0&&(t=e),i[t]=r[e]}),__exportStar=this&&this.__exportStar||function(i,r){for(var e in i)e!=="default"&&!Object.prototype.hasOwnProperty.call(r,e)&&__createBinding(r,i,e)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("mavlink-mappings"),exports),__exportStar(require("./lib/utils"),exports),__exportStar(require("./lib/logger"),exports),__exportStar(require("./lib/mavlink"),exports),__exportStar(require("./lib/mavesp"),exports);
@@ -1,118 +1 @@
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 = {};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Logger=exports.LogLevel=void 0;const EventEmitter=require("events");var LogLevel;(function(t){t[t.trace=5]="trace",t[t.debug=4]="debug",t[t.info=3]="info",t[t.warn=2]="warn",t[t.error=1]="error",t[t.fatal=0]="fatal"})(LogLevel=exports.LogLevel||(exports.LogLevel={}));class Logger{constructor(e){this.context=e,Logger.events.emit("logger-created",Logger.registry[e])}static getLogger(e){let s="";if(typeof e=="function")s=e.name;else if(typeof e=="object")s=e.constructor.name;else if(typeof e=="string")s=e;else throw new Error(`Do not know how to get logger for ${e} (${typeof e})`);return Logger.registry[s]||(Logger.registry[s]=new Logger(s)),Logger.registry[s]}static on(e,s){this.events.on(e,s)}static off(e,s){this.events.off(e,s)}trace(...e){Logger.events.emit("log",{context:this.context,level:LogLevel.trace,message:e})}debug(...e){Logger.events.emit("log",{context:this.context,level:LogLevel.debug,message:e})}info(...e){Logger.events.emit("log",{context:this.context,level:LogLevel.info,message:e})}warn(...e){Logger.events.emit("log",{context:this.context,level:LogLevel.warn,message:e})}error(...e){Logger.events.emit("log",{context:this.context,level:LogLevel.error,message:e})}fatal(...e){Logger.events.emit("log",{context:this.context,level:LogLevel.fatal,message:e})}}exports.Logger=Logger,Logger.events=new EventEmitter,Logger.registry={};
@@ -1,99 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MavEsp8266 = void 0;
4
- const events_1 = require("events");
5
- const dgram_1 = require("dgram");
6
- const stream_1 = require("stream");
7
- const mavlink_1 = require("./mavlink");
8
- const mavlink_2 = require("./mavlink");
9
- const utils_1 = require("./utils");
10
- /**
11
- * Encapsulation of communication with MavEsp8266
12
- */
13
- class MavEsp8266 extends events_1.EventEmitter {
14
- constructor() {
15
- super();
16
- this.ip = '';
17
- this.sendPort = 14555;
18
- this.seq = 0;
19
- this.input = new stream_1.PassThrough();
20
- this.processIncommingUDPData = this.processIncommingUDPData.bind(this);
21
- this.processIncommingPacket = this.processIncommingPacket.bind(this);
22
- // Create the reader as usual by piping the source stream through the splitter
23
- // and packet parser
24
- const reader = this.input
25
- .pipe(new mavlink_1.MavLinkPacketSplitter())
26
- .pipe(new mavlink_1.MavLinkPacketParser());
27
- reader.on('data', this.processIncommingPacket);
28
- }
29
- /**
30
- * Start communication with the controller via MAVESP2866
31
- *
32
- * @param receivePort port to receive messages on (default: 14550)
33
- * @param sendPort port to send messages to (default: 14555)
34
- */
35
- async start(receivePort = 14550, sendPort = 14555) {
36
- this.sendPort = sendPort;
37
- // Create a UDP socket
38
- this.socket = (0, dgram_1.createSocket)({ type: 'udp4', reuseAddr: true });
39
- this.socket.on('message', this.processIncommingUDPData);
40
- // Start listening on the socket
41
- return new Promise((resolve, reject) => {
42
- this.socket.bind(receivePort, () => {
43
- // Wait for the first package to be returned to read the ip address
44
- // of the controller
45
- (0, utils_1.waitFor)(() => this.ip !== '')
46
- .then(() => { resolve(this.ip); })
47
- .catch(e => { reject(e); });
48
- });
49
- });
50
- }
51
- /**
52
- * Send a packet
53
- *
54
- * @param msg message to send
55
- * @param sysid system id
56
- * @param compid component id
57
- */
58
- send(msg, sysid = mavlink_2.MavLinkProtocol.SYS_ID, compid = mavlink_2.MavLinkProtocol.COMP_ID) {
59
- const protocol = new mavlink_2.MavLinkProtocolV2(sysid, compid);
60
- const buffer = protocol.serialize(msg, this.seq++);
61
- this.seq &= 255;
62
- this.sendBuffer(buffer);
63
- }
64
- /**
65
- * Send a signed packet
66
- *
67
- * @param msg message to send
68
- * @param sysid system id
69
- * @param compid component id
70
- * @param linkId link id for the signature
71
- */
72
- sendSigned(msg, key, linkId = 1, sysid = mavlink_2.MavLinkProtocol.SYS_ID, compid = mavlink_2.MavLinkProtocol.COMP_ID) {
73
- const protocol = new mavlink_2.MavLinkProtocolV2(sysid, compid, mavlink_2.MavLinkProtocolV2.IFLAG_SIGNED);
74
- const b1 = protocol.serialize(msg, this.seq++);
75
- this.seq &= 255;
76
- const b2 = protocol.sign(b1, linkId, key);
77
- this.sendBuffer(b2);
78
- }
79
- /**
80
- * Send raw data over the socket. Useful for custom implementation of data sending
81
- *
82
- * @param buffer buffer to send
83
- */
84
- sendBuffer(buffer) {
85
- this.socket.send(buffer, this.sendPort, this.ip);
86
- }
87
- processIncommingUDPData(buffer, metadata) {
88
- // store the remote ip address
89
- if (this.ip === '')
90
- this.ip = metadata.address;
91
- // pass on the data to the input stream
92
- this.input.write(buffer);
93
- }
94
- processIncommingPacket(packet) {
95
- // let the user know we received the packet
96
- this.emit('data', packet);
97
- }
98
- }
99
- exports.MavEsp8266 = MavEsp8266;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.MavEsp8266=void 0;const events_1=require("events"),dgram_1=require("dgram"),stream_1=require("stream"),mavlink_1=require("./mavlink"),mavlink_2=require("./mavlink"),utils_1=require("./utils");class MavEsp8266 extends events_1.EventEmitter{constructor(){super(),this.ip="",this.sendPort=14555,this.seq=0,this.input=new stream_1.PassThrough,this.processIncommingUDPData=this.processIncommingUDPData.bind(this),this.processIncommingPacket=this.processIncommingPacket.bind(this),this.input.pipe(new mavlink_1.MavLinkPacketSplitter).pipe(new mavlink_1.MavLinkPacketParser).on("data",this.processIncommingPacket)}async start(s=14550,t=14555){return this.sendPort=t,this.socket=(0,dgram_1.createSocket)({type:"udp4",reuseAddr:!0}),this.socket.on("message",this.processIncommingUDPData),new Promise((e,o)=>{this.socket.bind(s,()=>{(0,utils_1.waitFor)(()=>this.ip!=="").then(()=>{e(this.ip)}).catch(i=>{o(i)})})})}send(s,t=mavlink_2.MavLinkProtocol.SYS_ID,e=mavlink_2.MavLinkProtocol.COMP_ID){const i=new mavlink_2.MavLinkProtocolV2(t,e).serialize(s,this.seq++);this.seq&=255,this.sendBuffer(i)}sendSigned(s,t,e=1,o=mavlink_2.MavLinkProtocol.SYS_ID,i=mavlink_2.MavLinkProtocol.COMP_ID){const n=new mavlink_2.MavLinkProtocolV2(o,i,mavlink_2.MavLinkProtocolV2.IFLAG_SIGNED),r=n.serialize(s,this.seq++);this.seq&=255;const c=n.sign(r,e,t);this.sendBuffer(c)}sendBuffer(s){this.socket.send(s,this.sendPort,this.ip)}processIncommingUDPData(s,t){this.ip===""&&(this.ip=t.address),this.input.write(s)}processIncommingPacket(s){this.emit("data",s)}}exports.MavEsp8266=MavEsp8266;
@@ -1,676 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sendSigned = exports.send = exports.createMavLinkStream = exports.MavLinkPacketParser = exports.MavLinkPacketSplitter = exports.MavLinkPacket = exports.MavLinkPacketSignature = exports.MavLinkProtocolV2 = exports.MavLinkProtocolV1 = exports.MavLinkProtocol = exports.MavLinkPacketHeader = void 0;
4
- const stream_1 = require("stream");
5
- const crypto_1 = require("crypto");
6
- const mavlink_mappings_1 = require("mavlink-mappings");
7
- const mavlink_mappings_2 = require("mavlink-mappings");
8
- const utils_1 = require("./utils");
9
- const logger_1 = require("./logger");
10
- const serialization_1 = require("./serialization");
11
- /**
12
- * Header definition of the MavLink packet
13
- */
14
- class MavLinkPacketHeader {
15
- constructor() {
16
- this.magic = 0;
17
- this.payloadLength = 0;
18
- this.incompatibilityFlags = 0;
19
- this.compatibilityFlags = 0;
20
- this.seq = 0;
21
- this.sysid = 0;
22
- this.compid = 0;
23
- this.msgid = 0;
24
- }
25
- }
26
- exports.MavLinkPacketHeader = MavLinkPacketHeader;
27
- /**
28
- * Base class for protocols
29
- *
30
- * Implements common functionality like getting the CRC and deserializing
31
- * data classes from the given payload buffer
32
- */
33
- class MavLinkProtocol {
34
- constructor() {
35
- this.log = logger_1.Logger.getLogger(this);
36
- }
37
- /**
38
- * Deserialize payload into actual data class
39
- */
40
- data(payload, clazz) {
41
- this.log.trace('Deserializing', clazz.MSG_NAME, 'with payload of size', payload.length);
42
- const instance = new clazz();
43
- clazz.FIELDS.forEach(field => {
44
- const deserialize = serialization_1.DESERIALIZERS[field.type];
45
- if (!deserialize) {
46
- throw new Error(`Unknown field type ${field.type}`);
47
- }
48
- instance[field.name] = deserialize(payload, field.offset, field.length);
49
- });
50
- return instance;
51
- }
52
- }
53
- exports.MavLinkProtocol = MavLinkProtocol;
54
- MavLinkProtocol.NAME = 'unknown';
55
- MavLinkProtocol.START_BYTE = 0;
56
- MavLinkProtocol.PAYLOAD_OFFSET = 0;
57
- MavLinkProtocol.CHECKSUM_LENGTH = 2;
58
- MavLinkProtocol.SYS_ID = 254;
59
- MavLinkProtocol.COMP_ID = 1;
60
- /**
61
- * MavLink Protocol V1
62
- */
63
- class MavLinkProtocolV1 extends MavLinkProtocol {
64
- constructor(sysid = MavLinkProtocol.SYS_ID, compid = MavLinkProtocol.COMP_ID) {
65
- super();
66
- this.sysid = sysid;
67
- this.compid = compid;
68
- }
69
- serialize(message, seq) {
70
- this.log.trace('Serializing message (seq:', seq, ')');
71
- const definition = message.constructor;
72
- const buffer = Buffer.from(new Uint8Array(MavLinkProtocolV1.PAYLOAD_OFFSET + definition.PAYLOAD_LENGTH + MavLinkProtocol.CHECKSUM_LENGTH));
73
- // serialize header
74
- buffer.writeUInt8(MavLinkProtocolV1.START_BYTE, 0);
75
- buffer.writeUInt8(definition.PAYLOAD_LENGTH, 1);
76
- buffer.writeUInt8(seq, 2);
77
- buffer.writeUInt8(this.sysid, 3);
78
- buffer.writeUInt8(this.compid, 4);
79
- buffer.writeUInt8(definition.MSG_ID, 5);
80
- // serialize fields
81
- definition.FIELDS.forEach(field => {
82
- const serialize = serialization_1.SERIALIZERS[field.type];
83
- if (!serialize)
84
- throw new Error(`Unknown field type ${field.type}: serializer not found`);
85
- serialize(message[field.name], buffer, field.offset + MavLinkProtocolV1.PAYLOAD_OFFSET, field.length);
86
- });
87
- // serialize checksum
88
- const crc = (0, mavlink_mappings_1.x25crc)(buffer, 1, 2, definition.MAGIC_NUMBER);
89
- buffer.writeUInt16LE(crc, buffer.length - 2);
90
- return buffer;
91
- }
92
- header(buffer) {
93
- this.log.trace('Reading header from buffer (len:', buffer.length, ')');
94
- const startByte = buffer.readUInt8(0);
95
- if (startByte !== MavLinkProtocolV1.START_BYTE) {
96
- throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV1.START_BYTE}, got ${startByte})`);
97
- }
98
- const result = new MavLinkPacketHeader();
99
- result.magic = startByte;
100
- result.payloadLength = buffer.readUInt8(1);
101
- result.seq = buffer.readUInt8(2);
102
- result.sysid = buffer.readUInt8(3);
103
- result.compid = buffer.readUInt8(4);
104
- result.msgid = buffer.readUInt8(5);
105
- return result;
106
- }
107
- /**
108
- * Deserialize packet checksum
109
- */
110
- crc(buffer) {
111
- this.log.trace('Reading crc from buffer (len:', buffer.length, ')');
112
- const plen = buffer.readUInt8(1);
113
- return buffer.readUInt16LE(MavLinkProtocolV1.PAYLOAD_OFFSET + plen);
114
- }
115
- payload(buffer) {
116
- this.log.trace('Reading payload from buffer (len:', buffer.length, ')');
117
- const plen = buffer.readUInt8(1);
118
- const payload = buffer.slice(MavLinkProtocolV1.PAYLOAD_OFFSET, MavLinkProtocolV1.PAYLOAD_OFFSET + plen);
119
- const padding = Buffer.from(new Uint8Array(255 - payload.length));
120
- return Buffer.concat([payload, padding]);
121
- }
122
- }
123
- exports.MavLinkProtocolV1 = MavLinkProtocolV1;
124
- MavLinkProtocolV1.NAME = 'MAV_V1';
125
- MavLinkProtocolV1.START_BYTE = 0xFE;
126
- MavLinkProtocolV1.PAYLOAD_OFFSET = 6;
127
- /**
128
- * MavLink Protocol V2
129
- */
130
- class MavLinkProtocolV2 extends MavLinkProtocol {
131
- constructor(sysid = MavLinkProtocol.SYS_ID, compid = MavLinkProtocol.COMP_ID, incompatibilityFlags = MavLinkProtocolV2.INCOMPATIBILITY_FLAGS, compatibilityFlags = MavLinkProtocolV2.COMPATIBILITY_FLAGS) {
132
- super();
133
- this.sysid = sysid;
134
- this.compid = compid;
135
- this.incompatibilityFlags = incompatibilityFlags;
136
- this.compatibilityFlags = compatibilityFlags;
137
- }
138
- serialize(message, seq) {
139
- this.log.trace('Serializing message (seq:', seq, ')');
140
- const definition = message.constructor;
141
- const buffer = Buffer.from(new Uint8Array(MavLinkProtocolV2.PAYLOAD_OFFSET + definition.PAYLOAD_LENGTH + MavLinkProtocol.CHECKSUM_LENGTH));
142
- buffer.writeUInt8(MavLinkProtocolV2.START_BYTE, 0);
143
- buffer.writeUInt8(this.incompatibilityFlags, 2);
144
- buffer.writeUInt8(this.compatibilityFlags, 3);
145
- buffer.writeUInt8(seq, 4);
146
- buffer.writeUInt8(this.sysid, 5);
147
- buffer.writeUInt8(this.compid, 6);
148
- buffer.writeUIntLE(definition.MSG_ID, 7, 3);
149
- definition.FIELDS.forEach(field => {
150
- const serialize = serialization_1.SERIALIZERS[field.type];
151
- if (!serialize)
152
- throw new Error(`Unknown field type ${field.type}: serializer not found`);
153
- serialize(message[field.name], buffer, field.offset + MavLinkProtocolV2.PAYLOAD_OFFSET, field.length);
154
- });
155
- // calculate actual truncated payload length
156
- const payloadLength = this.calculateTruncatedPayloadLength(buffer);
157
- buffer.writeUInt8(payloadLength, 1);
158
- // slice out the message buffer
159
- const result = buffer.slice(0, MavLinkProtocolV2.PAYLOAD_OFFSET + payloadLength + MavLinkProtocol.CHECKSUM_LENGTH);
160
- const crc = (0, mavlink_mappings_1.x25crc)(result, 1, 2, definition.MAGIC_NUMBER);
161
- result.writeUInt16LE(crc, result.length - MavLinkProtocol.CHECKSUM_LENGTH);
162
- return result;
163
- }
164
- /**
165
- * Create a signed package buffer
166
- *
167
- * @param buffer buffer with the original, unsigned package
168
- * @param linkId id of the link
169
- * @param key key to sign the package with
170
- * @param timestamp optional timestamp for packet signing (default: Date.now())
171
- * @returns signed package
172
- */
173
- sign(buffer, linkId, key, timestamp = Date.now()) {
174
- this.log.trace('Signing message');
175
- const result = Buffer.concat([
176
- buffer,
177
- Buffer.from(new Uint8Array(MavLinkPacketSignature.SIGNATURE_LENGTH))
178
- ]);
179
- const signer = new MavLinkPacketSignature(result);
180
- signer.linkId = linkId;
181
- signer.timestamp = timestamp;
182
- signer.signature = signer.calculate(key);
183
- return result;
184
- }
185
- calculateTruncatedPayloadLength(buffer) {
186
- let result = buffer.length;
187
- for (let i = buffer.length - MavLinkProtocol.CHECKSUM_LENGTH - 1; i >= MavLinkProtocolV2.PAYLOAD_OFFSET; i--) {
188
- result = i;
189
- if (buffer[i] !== 0) {
190
- result++;
191
- break;
192
- }
193
- }
194
- return result - MavLinkProtocolV2.PAYLOAD_OFFSET;
195
- }
196
- header(buffer) {
197
- this.log.trace('Reading header from buffer (len:', buffer.length, ')');
198
- const startByte = buffer.readUInt8(0);
199
- if (startByte !== MavLinkProtocolV2.START_BYTE) {
200
- throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV2.START_BYTE}, got ${startByte})`);
201
- }
202
- const result = new MavLinkPacketHeader();
203
- result.magic = startByte;
204
- result.payloadLength = buffer.readUInt8(1);
205
- result.incompatibilityFlags = buffer.readUInt8(2);
206
- result.compatibilityFlags = buffer.readUInt8(3);
207
- result.seq = buffer.readUInt8(4);
208
- result.sysid = buffer.readUInt8(5);
209
- result.compid = buffer.readUInt8(6);
210
- result.msgid = buffer.readUIntLE(7, 3);
211
- return result;
212
- }
213
- /**
214
- * Deserialize packet checksum
215
- */
216
- crc(buffer) {
217
- this.log.trace('Reading crc from buffer (len:', buffer.length, ')');
218
- const plen = buffer.readUInt8(1);
219
- return buffer.readUInt16LE(MavLinkProtocolV2.PAYLOAD_OFFSET + plen);
220
- }
221
- payload(buffer) {
222
- this.log.trace('Reading payload from buffer (len:', buffer.length, ')');
223
- const plen = buffer.readUInt8(1);
224
- const payload = buffer.slice(MavLinkProtocolV2.PAYLOAD_OFFSET, MavLinkProtocolV2.PAYLOAD_OFFSET + plen);
225
- const padding = Buffer.from(new Uint8Array(255 - payload.length));
226
- return Buffer.concat([payload, padding]);
227
- }
228
- signature(buffer, header) {
229
- this.log.trace('Reading signature from buffer (len:', buffer.length, ')');
230
- if (header.incompatibilityFlags & MavLinkProtocolV2.IFLAG_SIGNED) {
231
- return new MavLinkPacketSignature(buffer);
232
- }
233
- else {
234
- return null;
235
- }
236
- }
237
- }
238
- exports.MavLinkProtocolV2 = MavLinkProtocolV2;
239
- MavLinkProtocolV2.NAME = 'MAV_V2';
240
- MavLinkProtocolV2.START_BYTE = 0xFD;
241
- MavLinkProtocolV2.PAYLOAD_OFFSET = 10;
242
- MavLinkProtocolV2.INCOMPATIBILITY_FLAGS = 0;
243
- MavLinkProtocolV2.COMPATIBILITY_FLAGS = 0;
244
- MavLinkProtocolV2.IFLAG_SIGNED = 0x01;
245
- /**
246
- * Registry of known protocols by STX
247
- */
248
- const KNOWN_PROTOCOLS_BY_STX = {
249
- [MavLinkProtocolV1.START_BYTE]: MavLinkProtocolV1,
250
- [MavLinkProtocolV2.START_BYTE]: MavLinkProtocolV2,
251
- };
252
- /**
253
- * MavLink packet signature definition
254
- */
255
- class MavLinkPacketSignature {
256
- constructor(buffer) {
257
- this.buffer = buffer;
258
- }
259
- /**
260
- * Calculate key based on secret passphrase
261
- *
262
- * @param passphrase secret to generate the key
263
- * @returns key as a buffer
264
- */
265
- static key(passphrase) {
266
- return (0, crypto_1.createHash)('sha256')
267
- .update(passphrase)
268
- .digest();
269
- }
270
- get offset() {
271
- return this.buffer.length - MavLinkPacketSignature.SIGNATURE_LENGTH;
272
- }
273
- /**
274
- * Get the linkId from signature
275
- */
276
- get linkId() {
277
- return this.buffer.readUInt8(this.offset);
278
- }
279
- /**
280
- * Set the linkId in signature
281
- */
282
- set linkId(value) {
283
- this.buffer.writeUInt8(this.offset);
284
- }
285
- /**
286
- * Get the timestamp from signature
287
- */
288
- get timestamp() {
289
- return this.buffer.readUIntLE(this.offset + 1, 6);
290
- }
291
- /**
292
- * Set the linkId in signature
293
- */
294
- set timestamp(value) {
295
- this.buffer.writeUIntLE(value, this.offset + 1, 6);
296
- }
297
- /**
298
- * Get the signature from signature
299
- */
300
- get signature() {
301
- return this.buffer.slice(this.offset + 7, this.offset + 7 + 6).toString('hex');
302
- }
303
- /**
304
- * Set the signature in signature
305
- */
306
- set signature(value) {
307
- this.buffer.write(value, this.offset + 7, 'hex');
308
- }
309
- /**
310
- * Calculates signature of the packet buffer using the provided secret.
311
- * The secret is converted to a hash using the sha256 algorithm which matches
312
- * the way Mission Planner creates keys.
313
- *
314
- * @param key the secret key (Buffer)
315
- * @returns calculated signature value
316
- */
317
- calculate(key) {
318
- const hash = (0, crypto_1.createHash)('sha256')
319
- .update(key)
320
- .update(this.buffer.slice(0, this.buffer.length - 6))
321
- .digest('hex')
322
- .substr(0, 12);
323
- return hash;
324
- }
325
- /**
326
- * Checks the signature of the packet buffer against a given secret
327
- * The secret is converted to a hash using the sha256 algorithm which matches
328
- * the way Mission Planner creates keys.
329
- *
330
- * @param key key
331
- * @returns true if the signature matches, false otherwise
332
- */
333
- matches(key) {
334
- return this.calculate(key) === this.signature;
335
- }
336
- toString() {
337
- return `linkid: ${this.linkId}, timestamp ${this.timestamp}, signature ${this.signature}`;
338
- }
339
- }
340
- exports.MavLinkPacketSignature = MavLinkPacketSignature;
341
- MavLinkPacketSignature.SIGNATURE_LENGTH = 13;
342
- /**
343
- * MavLink packet definition
344
- */
345
- class MavLinkPacket {
346
- constructor(buffer, header = new MavLinkPacketHeader(), payload = Buffer.from(new Uint8Array(255)), crc = 0, protocol = new MavLinkProtocolV1(), signature = null) {
347
- this.buffer = buffer;
348
- this.header = header;
349
- this.payload = payload;
350
- this.crc = crc;
351
- this.protocol = protocol;
352
- this.signature = signature;
353
- }
354
- /**
355
- * Debug information about the packet
356
- *
357
- * @returns string representing debug information about a packet
358
- */
359
- debug() {
360
- return 'Packet ('
361
- + `proto: ${this.protocol.constructor['NAME']}, `
362
- + `sysid: ${this.header.sysid}, `
363
- + `compid: ${this.header.compid}, `
364
- + `msgid: ${this.header.msgid}, `
365
- + `seq: ${this.header.seq}, `
366
- + `plen: ${this.header.payloadLength}, `
367
- + `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])}), `
368
- + `crc: ${(0, utils_1.hex)(this.crc, 4)}`
369
- + this.signatureToString(this.signature)
370
- + ')';
371
- }
372
- signatureToString(signature) {
373
- return signature ? `, ${signature.toString()}` : '';
374
- }
375
- }
376
- exports.MavLinkPacket = MavLinkPacket;
377
- /**
378
- * This enum describes the different ways validation of a buffer can end
379
- */
380
- var PacketValidationResult;
381
- (function (PacketValidationResult) {
382
- PacketValidationResult[PacketValidationResult["VALID"] = 0] = "VALID";
383
- PacketValidationResult[PacketValidationResult["INVALID"] = 1] = "INVALID";
384
- PacketValidationResult[PacketValidationResult["UNKNOWN"] = 2] = "UNKNOWN";
385
- })(PacketValidationResult || (PacketValidationResult = {}));
386
- /**
387
- * A transform stream that splits the incomming data stream into chunks containing full MavLink messages
388
- */
389
- class MavLinkPacketSplitter extends stream_1.Transform {
390
- /**
391
- * @param opts options to pass on to the Transform constructor
392
- * @param verbose print diagnostic information
393
- * @param onCrcError callback executed if there is a CRC error (mostly for debugging)
394
- */
395
- constructor(opts = {}, onCrcError = () => { }) {
396
- super(opts);
397
- this.log = logger_1.Logger.getLogger(this);
398
- this.buffer = Buffer.from([]);
399
- this.onCrcError = null;
400
- this._validPackagesCount = 0;
401
- this._unknownPackagesCount = 0;
402
- this._invalidPackagesCount = 0;
403
- this.onCrcError = onCrcError;
404
- }
405
- _transform(chunk, encoding, callback) {
406
- this.buffer = Buffer.concat([this.buffer, chunk]);
407
- while (this.buffer.byteLength > 0) {
408
- const offset = this.findStartOfPacket(this.buffer);
409
- if (offset === null) {
410
- // start of the package was not found - need more data
411
- break;
412
- }
413
- // fast-forward the buffer to the first start byte
414
- if (offset > 0) {
415
- this.buffer = this.buffer.slice(offset);
416
- }
417
- this.log.debug('Found potential packet start at', offset);
418
- // get protocol this buffer is encoded with
419
- const Protocol = this.getPacketProtocol(this.buffer);
420
- this.log.debug('Packet protocol is', Protocol.NAME);
421
- // check if the buffer contains at least the minumum size of data
422
- if (this.buffer.length < Protocol.PAYLOAD_OFFSET + MavLinkProtocol.CHECKSUM_LENGTH) {
423
- // current buffer shorter than the shortest message - skipping
424
- this.log.debug('Current buffer shorter than the shortest message - skipping');
425
- break;
426
- }
427
- // check if the current buffer contains the entire message
428
- const expectedBufferLength = this.readPacketLength(this.buffer, Protocol);
429
- this.log.debug('Expected buffer length:', expectedBufferLength, `(${(0, utils_1.hex)(expectedBufferLength)})`);
430
- if (this.buffer.length < expectedBufferLength) {
431
- // current buffer is not fully retrieved yet - skipping
432
- this.log.debug('Current buffer is not fully retrieved yet - skipping');
433
- break;
434
- }
435
- else {
436
- this.log.debug('Current buffer length:', this.buffer.length, `(${(0, utils_1.hex)(this.buffer.length, 4)})`);
437
- }
438
- // retrieve the buffer based on payload size
439
- const buffer = this.buffer.slice(0, expectedBufferLength);
440
- this.log.debug('Recognized buffer length:', buffer.length, `(${(0, utils_1.hex)(buffer.length, 2)})`);
441
- switch (this.validatePacket(buffer, Protocol)) {
442
- case PacketValidationResult.VALID:
443
- this.log.debug('Found a valid packet');
444
- this._validPackagesCount++;
445
- this.push(buffer);
446
- // truncate the buffer to remove the current message
447
- this.buffer = this.buffer.slice(expectedBufferLength);
448
- break;
449
- case PacketValidationResult.INVALID:
450
- this.log.debug('Found an invalid packet - skipping');
451
- this._invalidPackagesCount++;
452
- // truncate the buffer to remove the wrongly identified STX
453
- this.buffer = this.buffer.slice(1);
454
- break;
455
- case PacketValidationResult.UNKNOWN:
456
- this.log.debug('Found an unknown packet - skipping');
457
- this._unknownPackagesCount++;
458
- // truncate the buffer to remove the current message
459
- this.buffer = this.buffer.slice(expectedBufferLength);
460
- break;
461
- }
462
- }
463
- callback(null);
464
- }
465
- findStartOfPacket(buffer) {
466
- const stxv1 = buffer.indexOf(MavLinkProtocolV1.START_BYTE);
467
- const stxv2 = buffer.indexOf(MavLinkProtocolV2.START_BYTE);
468
- if (stxv1 >= 0 && stxv2 >= 0) {
469
- // in the current buffer both STX v1 and v2 are found - get the first one
470
- if (stxv1 < stxv2) {
471
- return stxv1;
472
- }
473
- else {
474
- return stxv2;
475
- }
476
- }
477
- else if (stxv1 >= 0) {
478
- // in the current buffer STX v1 is found
479
- return stxv1;
480
- }
481
- else if (stxv2 >= 0) {
482
- // in the current buffer STX v2 is found
483
- return stxv2;
484
- }
485
- else {
486
- // no STX found
487
- return null;
488
- }
489
- }
490
- getPacketProtocol(buffer) {
491
- return KNOWN_PROTOCOLS_BY_STX[buffer.readUInt8(0)] || null;
492
- }
493
- readPacketLength(buffer, Protocol) {
494
- // check if the current buffer contains the entire message
495
- const payloadLength = buffer.readUInt8(1);
496
- return Protocol.PAYLOAD_OFFSET
497
- + payloadLength
498
- + MavLinkProtocol.CHECKSUM_LENGTH
499
- + (this.isV2Signed(buffer) ? MavLinkPacketSignature.SIGNATURE_LENGTH : 0);
500
- }
501
- validatePacket(buffer, Protocol) {
502
- const protocol = new Protocol();
503
- const header = protocol.header(buffer);
504
- const magic = mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[header.msgid];
505
- if (magic) {
506
- const crc = protocol.crc(buffer);
507
- const trim = this.isV2Signed(buffer)
508
- ? MavLinkPacketSignature.SIGNATURE_LENGTH + MavLinkProtocol.CHECKSUM_LENGTH
509
- : MavLinkProtocol.CHECKSUM_LENGTH;
510
- const crc2 = (0, mavlink_mappings_1.x25crc)(buffer, 1, trim, magic);
511
- if (crc === crc2) {
512
- // this is a proper message that is known and has been validated for corrupted data
513
- return PacketValidationResult.VALID;
514
- }
515
- else {
516
- // CRC mismatch
517
- const message = [
518
- `CRC error; expected: ${crc2} (${(0, utils_1.hex)(crc2, 4)}), got ${crc} (${(0, utils_1.hex)(crc, 4)});`,
519
- `msgid: ${header.msgid} (${(0, utils_1.hex)(header.msgid)}),`,
520
- `seq: ${header.seq} (${(0, utils_1.hex)(header.seq)}),`,
521
- `plen: ${header.payloadLength} (${(0, utils_1.hex)(header.payloadLength)}),`,
522
- `magic: ${magic} (${(0, utils_1.hex)(magic)})`,
523
- ];
524
- this.log.warn(message.join(' '));
525
- this.onCrcError(buffer);
526
- return PacketValidationResult.INVALID;
527
- }
528
- }
529
- else {
530
- // unknown message (as in not generated from the XML sources)
531
- this.log.debug(`Unknown message with id ${header.msgid} (magic number not found) - skipping`);
532
- return PacketValidationResult.UNKNOWN;
533
- }
534
- }
535
- /**
536
- * Checks if the buffer contains the entire message with signature
537
- *
538
- * @param buffer buffer with the message
539
- */
540
- isV2Signed(buffer) {
541
- const protocol = buffer.readUInt8(0);
542
- if (protocol === MavLinkProtocolV2.START_BYTE) {
543
- const flags = buffer.readUInt8(2);
544
- return !!(flags & MavLinkProtocolV2.IFLAG_SIGNED);
545
- }
546
- }
547
- /**
548
- * Number of invalid packages
549
- */
550
- get validPackages() {
551
- return this._validPackagesCount;
552
- }
553
- /**
554
- * Reset the number of valid packages
555
- */
556
- resetValidPackagesCount() {
557
- this._validPackagesCount = 0;
558
- }
559
- /**
560
- * Number of invalid packages
561
- */
562
- get invalidPackages() {
563
- return this._invalidPackagesCount;
564
- }
565
- /**
566
- * Reset the number of invalid packages
567
- */
568
- resetInvalidPackagesCount() {
569
- this._invalidPackagesCount = 0;
570
- }
571
- /**
572
- * Number of invalid packages
573
- */
574
- get unknownPackagesCount() {
575
- return this._unknownPackagesCount;
576
- }
577
- /**
578
- * Reset the number of invalid packages
579
- */
580
- resetUnknownPackagesCount() {
581
- this._unknownPackagesCount = 0;
582
- }
583
- }
584
- exports.MavLinkPacketSplitter = MavLinkPacketSplitter;
585
- /**
586
- * A transform stream that takes a buffer with data and converts it to MavLinkPacket object
587
- */
588
- class MavLinkPacketParser extends stream_1.Transform {
589
- constructor(opts = {}) {
590
- super({ ...opts, objectMode: true });
591
- this.log = logger_1.Logger.getLogger(this);
592
- }
593
- getProtocol(buffer) {
594
- const startByte = buffer.readUInt8(0);
595
- switch (startByte) {
596
- case MavLinkProtocolV1.START_BYTE:
597
- return new MavLinkProtocolV1();
598
- case MavLinkProtocolV2.START_BYTE:
599
- return new MavLinkProtocolV2();
600
- default:
601
- throw new Error(`Unknown protocol '${(0, utils_1.hex)(startByte)}'`);
602
- }
603
- }
604
- _transform(chunk, encoding, callback) {
605
- const protocol = this.getProtocol(chunk);
606
- const header = protocol.header(chunk);
607
- const payload = protocol.payload(chunk);
608
- const crc = protocol.crc(chunk);
609
- const signature = protocol instanceof MavLinkProtocolV2
610
- ? protocol.signature(chunk, header)
611
- : null;
612
- const packet = new MavLinkPacket(chunk, header, payload, crc, protocol, signature);
613
- callback(null, packet);
614
- }
615
- }
616
- exports.MavLinkPacketParser = MavLinkPacketParser;
617
- /**
618
- * Creates a MavLink packet stream reader that is reading packets from the given input
619
- *
620
- * @param input input stream to read from
621
- */
622
- function createMavLinkStream(input, onCrcError) {
623
- return input
624
- .pipe(new MavLinkPacketSplitter({}, onCrcError))
625
- .pipe(new MavLinkPacketParser());
626
- }
627
- exports.createMavLinkStream = createMavLinkStream;
628
- let seq = 0;
629
- /**
630
- * Send a packet to the stream
631
- *
632
- * @param stream Stream to send the data to
633
- * @param msg message to serialize and send
634
- * @param protocol protocol to use (default: MavLinkProtocolV1)
635
- * @returns number of bytes sent
636
- */
637
- async function send(stream, msg, protocol = new MavLinkProtocolV1()) {
638
- return new Promise((resolve, reject) => {
639
- const buffer = protocol.serialize(msg, seq++);
640
- seq &= 255;
641
- stream.write(buffer, err => {
642
- if (err)
643
- reject(err);
644
- else
645
- resolve(buffer.length);
646
- });
647
- });
648
- }
649
- exports.send = send;
650
- /**
651
- * Send a signed packet to the stream. Signed packets are always V2 protocol
652
- *
653
- * @param stream Stream to send the data to
654
- * @param msg message to serialize and send
655
- * @param key key to sign the message with
656
- * @param linkId link id for the signature
657
- * @param sysid system id
658
- * @param compid component id
659
- * @param timestamp optional timestamp for packet signing (default: Date.now())
660
- * @returns number of bytes sent
661
- */
662
- async function sendSigned(stream, msg, key, linkId = 1, sysid = MavLinkProtocol.SYS_ID, compid = MavLinkProtocol.COMP_ID, timestamp = Date.now()) {
663
- return new Promise((resolve, reject) => {
664
- const protocol = new MavLinkProtocolV2(sysid, compid, MavLinkProtocolV2.IFLAG_SIGNED);
665
- const b1 = protocol.serialize(msg, seq++);
666
- seq &= 255;
667
- const b2 = protocol.sign(b1, linkId, key, timestamp);
668
- stream.write(b2, err => {
669
- if (err)
670
- reject(err);
671
- else
672
- resolve(b2.length);
673
- });
674
- });
675
- }
676
- exports.sendSigned = sendSigned;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.sendSigned=exports.send=exports.createMavLinkStream=exports.MavLinkPacketParser=exports.MavLinkPacketSplitter=exports.MavLinkPacket=exports.MavLinkPacketSignature=exports.MavLinkProtocolV2=exports.MavLinkProtocolV1=exports.MavLinkProtocol=exports.MavLinkPacketHeader=void 0;const stream_1=require("stream"),crypto_1=require("crypto"),mavlink_mappings_1=require("mavlink-mappings"),mavlink_mappings_2=require("mavlink-mappings"),utils_1=require("./utils"),logger_1=require("./logger"),serialization_1=require("./serialization");class MavLinkPacketHeader{constructor(){this.magic=0,this.payloadLength=0,this.incompatibilityFlags=0,this.compatibilityFlags=0,this.seq=0,this.sysid=0,this.compid=0,this.msgid=0}}exports.MavLinkPacketHeader=MavLinkPacketHeader;class MavLinkProtocol{constructor(){this.log=logger_1.Logger.getLogger(this)}data(t,n){this.log.trace("Deserializing",n.MSG_NAME,"with payload of size",t.length);const e=new n;return n.FIELDS.forEach(s=>{const i=serialization_1.DESERIALIZERS[s.type];if(!i)throw new Error(`Unknown field type ${s.type}`);e[s.name]=i(t,s.offset,s.length)}),e}}exports.MavLinkProtocol=MavLinkProtocol,MavLinkProtocol.NAME="unknown",MavLinkProtocol.START_BYTE=0,MavLinkProtocol.PAYLOAD_OFFSET=0,MavLinkProtocol.CHECKSUM_LENGTH=2,MavLinkProtocol.SYS_ID=254,MavLinkProtocol.COMP_ID=1;class MavLinkProtocolV1 extends MavLinkProtocol{constructor(t=MavLinkProtocol.SYS_ID,n=MavLinkProtocol.COMP_ID){super(),this.sysid=t,this.compid=n}serialize(t,n){this.log.trace("Serializing message (seq:",n,")");const e=t.constructor,s=Buffer.from(new Uint8Array(MavLinkProtocolV1.PAYLOAD_OFFSET+e.PAYLOAD_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH));s.writeUInt8(MavLinkProtocolV1.START_BYTE,0),s.writeUInt8(e.PAYLOAD_LENGTH,1),s.writeUInt8(n,2),s.writeUInt8(this.sysid,3),s.writeUInt8(this.compid,4),s.writeUInt8(e.MSG_ID,5),e.FIELDS.forEach(r=>{const o=serialization_1.SERIALIZERS[r.type];if(!o)throw new Error(`Unknown field type ${r.type}: serializer not found`);o(t[r.name],s,r.offset+MavLinkProtocolV1.PAYLOAD_OFFSET,r.length)});const i=(0,mavlink_mappings_1.x25crc)(s,1,2,e.MAGIC_NUMBER);return s.writeUInt16LE(i,s.length-2),s}header(t){this.log.trace("Reading header from buffer (len:",t.length,")");const n=t.readUInt8(0);if(n!==MavLinkProtocolV1.START_BYTE)throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV1.START_BYTE}, got ${n})`);const e=new MavLinkPacketHeader;return e.magic=n,e.payloadLength=t.readUInt8(1),e.seq=t.readUInt8(2),e.sysid=t.readUInt8(3),e.compid=t.readUInt8(4),e.msgid=t.readUInt8(5),e}crc(t){this.log.trace("Reading crc from buffer (len:",t.length,")");const n=t.readUInt8(1);return t.readUInt16LE(MavLinkProtocolV1.PAYLOAD_OFFSET+n)}payload(t){this.log.trace("Reading payload from buffer (len:",t.length,")");const n=t.readUInt8(1),e=t.slice(MavLinkProtocolV1.PAYLOAD_OFFSET,MavLinkProtocolV1.PAYLOAD_OFFSET+n),s=Buffer.from(new Uint8Array(255-e.length));return Buffer.concat([e,s])}}exports.MavLinkProtocolV1=MavLinkProtocolV1,MavLinkProtocolV1.NAME="MAV_V1",MavLinkProtocolV1.START_BYTE=254,MavLinkProtocolV1.PAYLOAD_OFFSET=6;class MavLinkProtocolV2 extends MavLinkProtocol{constructor(t=MavLinkProtocol.SYS_ID,n=MavLinkProtocol.COMP_ID,e=MavLinkProtocolV2.INCOMPATIBILITY_FLAGS,s=MavLinkProtocolV2.COMPATIBILITY_FLAGS){super(),this.sysid=t,this.compid=n,this.incompatibilityFlags=e,this.compatibilityFlags=s}serialize(t,n){this.log.trace("Serializing message (seq:",n,")");const e=t.constructor,s=Buffer.from(new Uint8Array(MavLinkProtocolV2.PAYLOAD_OFFSET+e.PAYLOAD_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH));s.writeUInt8(MavLinkProtocolV2.START_BYTE,0),s.writeUInt8(this.incompatibilityFlags,2),s.writeUInt8(this.compatibilityFlags,3),s.writeUInt8(n,4),s.writeUInt8(this.sysid,5),s.writeUInt8(this.compid,6),s.writeUIntLE(e.MSG_ID,7,3),e.FIELDS.forEach(c=>{const h=serialization_1.SERIALIZERS[c.type];if(!h)throw new Error(`Unknown field type ${c.type}: serializer not found`);h(t[c.name],s,c.offset+MavLinkProtocolV2.PAYLOAD_OFFSET,c.length)});const i=this.calculateTruncatedPayloadLength(s);s.writeUInt8(i,1);const r=s.slice(0,MavLinkProtocolV2.PAYLOAD_OFFSET+i+MavLinkProtocol.CHECKSUM_LENGTH),o=(0,mavlink_mappings_1.x25crc)(r,1,2,e.MAGIC_NUMBER);return r.writeUInt16LE(o,r.length-MavLinkProtocol.CHECKSUM_LENGTH),r}sign(t,n,e,s=Date.now()){this.log.trace("Signing message");const i=Buffer.concat([t,Buffer.from(new Uint8Array(MavLinkPacketSignature.SIGNATURE_LENGTH))]),r=new MavLinkPacketSignature(i);return r.linkId=n,r.timestamp=s,r.signature=r.calculate(e),i}calculateTruncatedPayloadLength(t){let n=t.length;for(let e=t.length-MavLinkProtocol.CHECKSUM_LENGTH-1;e>=MavLinkProtocolV2.PAYLOAD_OFFSET;e--)if(n=e,t[e]!==0){n++;break}return n-MavLinkProtocolV2.PAYLOAD_OFFSET}header(t){this.log.trace("Reading header from buffer (len:",t.length,")");const n=t.readUInt8(0);if(n!==MavLinkProtocolV2.START_BYTE)throw new Error(`Invalid start byte (expected: ${MavLinkProtocolV2.START_BYTE}, got ${n})`);const e=new MavLinkPacketHeader;return e.magic=n,e.payloadLength=t.readUInt8(1),e.incompatibilityFlags=t.readUInt8(2),e.compatibilityFlags=t.readUInt8(3),e.seq=t.readUInt8(4),e.sysid=t.readUInt8(5),e.compid=t.readUInt8(6),e.msgid=t.readUIntLE(7,3),e}crc(t){this.log.trace("Reading crc from buffer (len:",t.length,")");const n=t.readUInt8(1);return t.readUInt16LE(MavLinkProtocolV2.PAYLOAD_OFFSET+n)}payload(t){this.log.trace("Reading payload from buffer (len:",t.length,")");const n=t.readUInt8(1),e=t.slice(MavLinkProtocolV2.PAYLOAD_OFFSET,MavLinkProtocolV2.PAYLOAD_OFFSET+n),s=Buffer.from(new Uint8Array(255-e.length));return Buffer.concat([e,s])}signature(t,n){return this.log.trace("Reading signature from buffer (len:",t.length,")"),n.incompatibilityFlags&MavLinkProtocolV2.IFLAG_SIGNED?new MavLinkPacketSignature(t):null}}exports.MavLinkProtocolV2=MavLinkProtocolV2,MavLinkProtocolV2.NAME="MAV_V2",MavLinkProtocolV2.START_BYTE=253,MavLinkProtocolV2.PAYLOAD_OFFSET=10,MavLinkProtocolV2.INCOMPATIBILITY_FLAGS=0,MavLinkProtocolV2.COMPATIBILITY_FLAGS=0,MavLinkProtocolV2.IFLAG_SIGNED=1;const KNOWN_PROTOCOLS_BY_STX={[MavLinkProtocolV1.START_BYTE]:MavLinkProtocolV1,[MavLinkProtocolV2.START_BYTE]:MavLinkProtocolV2};class MavLinkPacketSignature{constructor(t){this.buffer=t}static key(t){return(0,crypto_1.createHash)("sha256").update(t).digest()}get offset(){return this.buffer.length-MavLinkPacketSignature.SIGNATURE_LENGTH}get linkId(){return this.buffer.readUInt8(this.offset)}set linkId(t){this.buffer.writeUInt8(this.offset)}get timestamp(){return this.buffer.readUIntLE(this.offset+1,6)}set timestamp(t){this.buffer.writeUIntLE(t,this.offset+1,6)}get signature(){return this.buffer.slice(this.offset+7,this.offset+7+6).toString("hex")}set signature(t){this.buffer.write(t,this.offset+7,"hex")}calculate(t){return(0,crypto_1.createHash)("sha256").update(t).update(this.buffer.slice(0,this.buffer.length-6)).digest("hex").substr(0,12)}matches(t){return this.calculate(t)===this.signature}toString(){return`linkid: ${this.linkId}, timestamp ${this.timestamp}, signature ${this.signature}`}}exports.MavLinkPacketSignature=MavLinkPacketSignature,MavLinkPacketSignature.SIGNATURE_LENGTH=13;class MavLinkPacket{constructor(t,n=new MavLinkPacketHeader,e=Buffer.from(new Uint8Array(255)),s=0,i=new MavLinkProtocolV1,r=null){this.buffer=t,this.header=n,this.payload=e,this.crc=s,this.protocol=i,this.signature=r}debug(){return`Packet (proto: ${this.protocol.constructor.NAME}, sysid: ${this.header.sysid}, compid: ${this.header.compid}, msgid: ${this.header.msgid}, seq: ${this.header.seq}, plen: ${this.header.payloadLength}, 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])}), crc: ${(0,utils_1.hex)(this.crc,4)}`+this.signatureToString(this.signature)+")"}signatureToString(t){return t?`, ${t.toString()}`:""}}exports.MavLinkPacket=MavLinkPacket;var PacketValidationResult;(function(a){a[a.VALID=0]="VALID",a[a.INVALID=1]="INVALID",a[a.UNKNOWN=2]="UNKNOWN"})(PacketValidationResult||(PacketValidationResult={}));class MavLinkPacketSplitter extends stream_1.Transform{constructor(t={},n=()=>{}){super(t),this.log=logger_1.Logger.getLogger(this),this.buffer=Buffer.from([]),this.onCrcError=null,this._validPackagesCount=0,this._unknownPackagesCount=0,this._invalidPackagesCount=0,this.onCrcError=n}_transform(t,n,e){for(this.buffer=Buffer.concat([this.buffer,t]);this.buffer.byteLength>0;){const s=this.findStartOfPacket(this.buffer);if(s===null)break;s>0&&(this.buffer=this.buffer.slice(s)),this.log.debug("Found potential packet start at",s);const i=this.getPacketProtocol(this.buffer);if(this.log.debug("Packet protocol is",i.NAME),this.buffer.length<i.PAYLOAD_OFFSET+MavLinkProtocol.CHECKSUM_LENGTH){this.log.debug("Current buffer shorter than the shortest message - skipping");break}const r=this.readPacketLength(this.buffer,i);if(this.log.debug("Expected buffer length:",r,`(${(0,utils_1.hex)(r)})`),this.buffer.length<r){this.log.debug("Current buffer is not fully retrieved yet - skipping");break}else this.log.debug("Current buffer length:",this.buffer.length,`(${(0,utils_1.hex)(this.buffer.length,4)})`);const o=this.buffer.slice(0,r);switch(this.log.debug("Recognized buffer length:",o.length,`(${(0,utils_1.hex)(o.length,2)})`),this.validatePacket(o,i)){case PacketValidationResult.VALID:this.log.debug("Found a valid packet"),this._validPackagesCount++,this.push(o),this.buffer=this.buffer.slice(r);break;case PacketValidationResult.INVALID:this.log.debug("Found an invalid packet - skipping"),this._invalidPackagesCount++,this.buffer=this.buffer.slice(1);break;case PacketValidationResult.UNKNOWN:this.log.debug("Found an unknown packet - skipping"),this._unknownPackagesCount++,this.buffer=this.buffer.slice(r);break}}e(null)}findStartOfPacket(t){const n=t.indexOf(MavLinkProtocolV1.START_BYTE),e=t.indexOf(MavLinkProtocolV2.START_BYTE);return n>=0&&e>=0?n<e?n:e:n>=0?n:e>=0?e:null}getPacketProtocol(t){return KNOWN_PROTOCOLS_BY_STX[t.readUInt8(0)]||null}readPacketLength(t,n){const e=t.readUInt8(1);return n.PAYLOAD_OFFSET+e+MavLinkProtocol.CHECKSUM_LENGTH+(this.isV2Signed(t)?MavLinkPacketSignature.SIGNATURE_LENGTH:0)}validatePacket(t,n){const e=new n,s=e.header(t),i=mavlink_mappings_2.MSG_ID_MAGIC_NUMBER[s.msgid];if(i){const r=e.crc(t),o=this.isV2Signed(t)?MavLinkPacketSignature.SIGNATURE_LENGTH+MavLinkProtocol.CHECKSUM_LENGTH:MavLinkProtocol.CHECKSUM_LENGTH,c=(0,mavlink_mappings_1.x25crc)(t,1,o,i);if(r===c)return PacketValidationResult.VALID;{const h=[`CRC error; expected: ${c} (${(0,utils_1.hex)(c,4)}), got ${r} (${(0,utils_1.hex)(r,4)});`,`msgid: ${s.msgid} (${(0,utils_1.hex)(s.msgid)}),`,`seq: ${s.seq} (${(0,utils_1.hex)(s.seq)}),`,`plen: ${s.payloadLength} (${(0,utils_1.hex)(s.payloadLength)}),`,`magic: ${i} (${(0,utils_1.hex)(i)})`];return this.log.warn(h.join(" ")),this.onCrcError(t),PacketValidationResult.INVALID}}else return this.log.debug(`Unknown message with id ${s.msgid} (magic number not found) - skipping`),PacketValidationResult.UNKNOWN}isV2Signed(t){if(t.readUInt8(0)===MavLinkProtocolV2.START_BYTE)return!!(t.readUInt8(2)&MavLinkProtocolV2.IFLAG_SIGNED)}get validPackages(){return this._validPackagesCount}resetValidPackagesCount(){this._validPackagesCount=0}get invalidPackages(){return this._invalidPackagesCount}resetInvalidPackagesCount(){this._invalidPackagesCount=0}get unknownPackagesCount(){return this._unknownPackagesCount}resetUnknownPackagesCount(){this._unknownPackagesCount=0}}exports.MavLinkPacketSplitter=MavLinkPacketSplitter;class MavLinkPacketParser extends stream_1.Transform{constructor(t={}){super({...t,objectMode:!0}),this.log=logger_1.Logger.getLogger(this)}getProtocol(t){const n=t.readUInt8(0);switch(n){case MavLinkProtocolV1.START_BYTE:return new MavLinkProtocolV1;case MavLinkProtocolV2.START_BYTE:return new MavLinkProtocolV2;default:throw new Error(`Unknown protocol '${(0,utils_1.hex)(n)}'`)}}_transform(t,n,e){const s=this.getProtocol(t),i=s.header(t),r=s.payload(t),o=s.crc(t),c=s instanceof MavLinkProtocolV2?s.signature(t,i):null,h=new MavLinkPacket(t,i,r,o,s,c);e(null,h)}}exports.MavLinkPacketParser=MavLinkPacketParser;function createMavLinkStream(a,t){return a.pipe(new MavLinkPacketSplitter({},t)).pipe(new MavLinkPacketParser)}exports.createMavLinkStream=createMavLinkStream;let seq=0;async function send(a,t,n=new MavLinkProtocolV1){return new Promise((e,s)=>{const i=n.serialize(t,seq++);seq&=255,a.write(i,r=>{r?s(r):e(i.length)})})}exports.send=send;async function sendSigned(a,t,n,e=1,s=MavLinkProtocol.SYS_ID,i=MavLinkProtocol.COMP_ID,r=Date.now()){return new Promise((o,c)=>{const h=new MavLinkProtocolV2(s,i,MavLinkProtocolV2.IFLAG_SIGNED),d=h.serialize(t,seq++);seq&=255;const g=h.sign(d,e,n,r);a.write(g,l=>{l?c(l):o(g.length)})})}exports.sendSigned=sendSigned;
@@ -1,172 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DESERIALIZERS = exports.SERIALIZERS = void 0;
4
- /**
5
- * A dictionary containing functions that serialize a certain value based on the field type
6
- */
7
- exports.SERIALIZERS = {
8
- // special types
9
- 'uint8_t_mavlink_version': (value, buffer, offset) => buffer.writeUInt8(value, offset),
10
- // singular types
11
- 'char': (value, buffer, offset) => buffer.writeUInt8(value, offset),
12
- 'int8_t': (value, buffer, offset) => buffer.writeInt8(value, offset),
13
- 'uint8_t': (value, buffer, offset) => buffer.writeUInt8(value, offset),
14
- 'int16_t': (value, buffer, offset) => buffer.writeInt16LE(value, offset),
15
- 'uint16_t': (value, buffer, offset) => buffer.writeUInt16LE(value, offset),
16
- 'int32_t': (value, buffer, offset) => buffer.writeInt32LE(value, offset),
17
- 'uint32_t': (value, buffer, offset) => buffer.writeUInt32LE(value, offset),
18
- 'int64_t': (value, buffer, offset) => buffer.writeBigInt64LE(value, offset),
19
- 'uint64_t': (value, buffer, offset) => buffer.writeBigUInt64LE(value, offset),
20
- 'float': (value, buffer, offset) => buffer.writeFloatLE(value, offset),
21
- 'double': (value, buffer, offset) => buffer.writeDoubleLE(value, offset),
22
- // array types
23
- 'char[]': (value, buffer, offset, maxLen) => {
24
- for (let i = 0; i < value.length && i < maxLen; i++) {
25
- const code = value.charCodeAt(i);
26
- buffer.writeUInt8(code, offset + i);
27
- }
28
- },
29
- 'int8_t[]': (value, buffer, offset, maxLen) => {
30
- for (let i = 0; i < value.length && i < maxLen; i++) {
31
- buffer.writeInt8(value[i], offset + i);
32
- }
33
- },
34
- 'uint8_t[]': (value, buffer, offset, maxLen) => {
35
- for (let i = 0; i < value.length && i < maxLen; i++) {
36
- buffer.writeUInt8(value[i], offset + i);
37
- }
38
- },
39
- 'int16_t[]': (value, buffer, offset, maxLen) => {
40
- for (let i = 0; i < value.length && i < maxLen; i++) {
41
- buffer.writeInt16LE(value[i], offset + i * 2);
42
- }
43
- },
44
- 'uint16_t[]': (value, buffer, offset, maxLen) => {
45
- for (let i = 0; i < value.length && i < maxLen; i++) {
46
- buffer.writeUInt16LE(value[i], offset + i * 2);
47
- }
48
- },
49
- 'int32_t[]': (value, buffer, offset, maxLen) => {
50
- for (let i = 0; i < value.length && i < maxLen; i++) {
51
- buffer.writeInt32LE(value[i], offset + i * 4);
52
- }
53
- },
54
- 'uint32_t[]': (value, buffer, offset, maxLen) => {
55
- for (let i = 0; i < value.length && i < maxLen; i++) {
56
- buffer.writeUInt32LE(value[i], offset + i * 4);
57
- }
58
- },
59
- 'int64_t[]': (value, buffer, offset, maxLen) => {
60
- for (let i = 0; i < value.length && i < maxLen; i++) {
61
- buffer.writeBigInt64LE(value[i], offset + i * 8);
62
- }
63
- },
64
- 'uint64_t[]': (value, buffer, offset, maxLen) => {
65
- for (let i = 0; i < value.length && i < maxLen; i++) {
66
- buffer.writeBigUInt64LE(value[i], offset + i * 8);
67
- }
68
- },
69
- 'float[]': (value, buffer, offset, maxLen) => {
70
- for (let i = 0; i < value.length && i < maxLen; i++) {
71
- buffer.writeFloatLE(value[i], offset + i * 4);
72
- }
73
- },
74
- 'double[]': (value, buffer, offset, maxLen) => {
75
- for (let i = 0; i < value.length && i < maxLen; i++) {
76
- buffer.writeDoubleLE(value[i], offset + i * 8);
77
- }
78
- },
79
- };
80
- /**
81
- * A dictionary containing functions that deserialize a certain value based on the field type
82
- */
83
- exports.DESERIALIZERS = {
84
- // special types
85
- 'uint8_t_mavlink_version': (buffer, offset) => buffer.readUInt8(offset),
86
- // singular types
87
- 'char': (buffer, offset) => String.fromCharCode(buffer.readUInt8(offset)),
88
- 'int8_t': (buffer, offset) => buffer.readInt8(offset),
89
- 'uint8_t': (buffer, offset) => buffer.readUInt8(offset),
90
- 'int16_t': (buffer, offset) => buffer.readInt16LE(offset),
91
- 'uint16_t': (buffer, offset) => buffer.readUInt16LE(offset),
92
- 'int32_t': (buffer, offset) => buffer.readInt32LE(offset),
93
- 'uint32_t': (buffer, offset) => buffer.readUInt32LE(offset),
94
- 'int64_t': (buffer, offset) => buffer.readBigInt64LE(offset),
95
- 'uint64_t': (buffer, offset) => buffer.readBigUInt64LE(offset),
96
- 'float': (buffer, offset) => buffer.readFloatLE(offset),
97
- 'double': (buffer, offset) => buffer.readDoubleLE(offset),
98
- // array types
99
- 'char[]': (buffer, offset, length) => {
100
- let result = '';
101
- for (let i = 0; i < length; i++) {
102
- const charCode = buffer.readUInt8(offset + i);
103
- if (charCode !== 0) {
104
- result += String.fromCharCode(charCode);
105
- }
106
- else {
107
- break;
108
- }
109
- }
110
- return result;
111
- },
112
- 'int8_t[]': (buffer, offset, length) => {
113
- const result = new Array(length);
114
- for (let i = 0; i < length; i++)
115
- result[i] = buffer.readInt8(offset + i);
116
- return result;
117
- },
118
- 'uint8_t[]': (buffer, offset, length) => {
119
- const result = new Array(length);
120
- for (let i = 0; i < length; i++)
121
- result[i] = buffer.readUInt8(offset + i);
122
- return result;
123
- },
124
- 'int16_t[]': (buffer, offset, length) => {
125
- const result = new Array(length);
126
- for (let i = 0; i < length; i++)
127
- result[i] = buffer.readInt16LE(offset + i * 2);
128
- return result;
129
- },
130
- 'uint16_t[]': (buffer, offset, length) => {
131
- const result = new Array(length);
132
- for (let i = 0; i < length; i++)
133
- result[i] = buffer.readUInt16LE(offset + i * 2);
134
- return result;
135
- },
136
- 'int32_t[]': (buffer, offset, length) => {
137
- const result = new Array(length);
138
- for (let i = 0; i < length; i++)
139
- result[i] = buffer.readInt32LE(offset + i * 4);
140
- return result;
141
- },
142
- 'uint32_t[]': (buffer, offset, length) => {
143
- const result = new Array(length);
144
- for (let i = 0; i < length; i++)
145
- result[i] = buffer.readUInt32LE(offset + i * 4);
146
- return result;
147
- },
148
- 'int64_t[]': (buffer, offset, length) => {
149
- const result = new Array(length);
150
- for (let i = 0; i < length; i++)
151
- result[i] = buffer.readBigInt64LE(offset + i * 8);
152
- return result;
153
- },
154
- 'uint64_t[]': (buffer, offset, length) => {
155
- const result = new Array(length);
156
- for (let i = 0; i < length; i++)
157
- result[i] = buffer.readBigUInt64LE(offset + i * 8);
158
- return result;
159
- },
160
- 'float[]': (buffer, offset, length) => {
161
- const result = new Array(length);
162
- for (let i = 0; i < length; i++)
163
- result[i] = buffer.readFloatLE(offset + i * 4);
164
- return result;
165
- },
166
- 'double[]': (buffer, offset, length) => {
167
- const result = new Array(length);
168
- for (let i = 0; i < length; i++)
169
- result[i] = buffer.readDoubleLE(offset + i * 8);
170
- return result;
171
- },
172
- };
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.DESERIALIZERS=exports.SERIALIZERS=void 0,exports.SERIALIZERS={uint8_t_mavlink_version:(r,e,n)=>e.writeUInt8(r,n),char:(r,e,n)=>e.writeUInt8(r,n),int8_t:(r,e,n)=>e.writeInt8(r,n),uint8_t:(r,e,n)=>e.writeUInt8(r,n),int16_t:(r,e,n)=>e.writeInt16LE(r,n),uint16_t:(r,e,n)=>e.writeUInt16LE(r,n),int32_t:(r,e,n)=>e.writeInt32LE(r,n),uint32_t:(r,e,n)=>e.writeUInt32LE(r,n),int64_t:(r,e,n)=>e.writeBigInt64LE(r,n),uint64_t:(r,e,n)=>e.writeBigUInt64LE(r,n),float:(r,e,n)=>e.writeFloatLE(r,n),double:(r,e,n)=>e.writeDoubleLE(r,n),"char[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++){const o=r.charCodeAt(t);e.writeUInt8(o,n+t)}},"int8_t[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeInt8(r[t],n+t)},"uint8_t[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeUInt8(r[t],n+t)},"int16_t[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeInt16LE(r[t],n+t*2)},"uint16_t[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeUInt16LE(r[t],n+t*2)},"int32_t[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeInt32LE(r[t],n+t*4)},"uint32_t[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeUInt32LE(r[t],n+t*4)},"int64_t[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeBigInt64LE(r[t],n+t*8)},"uint64_t[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeBigUInt64LE(r[t],n+t*8)},"float[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeFloatLE(r[t],n+t*4)},"double[]":(r,e,n,i)=>{for(let t=0;t<r.length&&t<i;t++)e.writeDoubleLE(r[t],n+t*8)}},exports.DESERIALIZERS={uint8_t_mavlink_version:(r,e)=>r.readUInt8(e),char:(r,e)=>String.fromCharCode(r.readUInt8(e)),int8_t:(r,e)=>r.readInt8(e),uint8_t:(r,e)=>r.readUInt8(e),int16_t:(r,e)=>r.readInt16LE(e),uint16_t:(r,e)=>r.readUInt16LE(e),int32_t:(r,e)=>r.readInt32LE(e),uint32_t:(r,e)=>r.readUInt32LE(e),int64_t:(r,e)=>r.readBigInt64LE(e),uint64_t:(r,e)=>r.readBigUInt64LE(e),float:(r,e)=>r.readFloatLE(e),double:(r,e)=>r.readDoubleLE(e),"char[]":(r,e,n)=>{let i="";for(let t=0;t<n;t++){const o=r.readUInt8(e+t);if(o!==0)i+=String.fromCharCode(o);else break}return i},"int8_t[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readInt8(e+t);return i},"uint8_t[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readUInt8(e+t);return i},"int16_t[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readInt16LE(e+t*2);return i},"uint16_t[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readUInt16LE(e+t*2);return i},"int32_t[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readInt32LE(e+t*4);return i},"uint32_t[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readUInt32LE(e+t*4);return i},"int64_t[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readBigInt64LE(e+t*8);return i},"uint64_t[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readBigUInt64LE(e+t*8);return i},"float[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readFloatLE(e+t*4);return i},"double[]":(r,e,n)=>{const i=new Array(n);for(let t=0;t<n;t++)i[t]=r.readDoubleLE(e+t*8);return i}};
package/dist/lib/utils.js CHANGED
@@ -1,77 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.waitFor = exports.sleep = exports.dump = exports.hex = void 0;
4
- /**
5
- * Convert a number to hexadecimal representation with a minumum
6
- * number of characters and optional prefix (0x by default)
7
- *
8
- * @param n value to convert
9
- * @param len length of the converted string (without prefix)
10
- * @param prefix prefix to prepend the generated string with
11
- */
12
- function hex(n, len = 2, prefix = '0x') {
13
- return `${prefix}${n.toString(16).padStart(len, '0')}`;
14
- }
15
- exports.hex = hex;
16
- /**
17
- * Dump a buffer in a readable form
18
- *
19
- * @param buffer buffer to dump
20
- * @param lineWidth width of the line, in bytes of buffer
21
- */
22
- function dump(buffer, lineWidth = 16) {
23
- const line = [];
24
- let address = 0;
25
- for (let i = 0; i < buffer.length; i++) {
26
- line.push(hex(buffer[i], 2, '0x'));
27
- if (line.length === lineWidth) {
28
- console.log(hex(address, 4), '|', line.join(' '));
29
- address += lineWidth;
30
- line.length = 0;
31
- }
32
- }
33
- if (line.length > 0) {
34
- console.log(hex(address, 4), '|', line.join(' '));
35
- }
36
- }
37
- exports.dump = dump;
38
- /**
39
- * Sleep for a given number of miliseconds
40
- *
41
- * @param ms number of miliseconds to sleep
42
- */
43
- function sleep(ms) {
44
- return new Promise(resolve => setTimeout(resolve, ms));
45
- }
46
- exports.sleep = sleep;
47
- /**
48
- * Execute a callback every <code>interval</code>ms and if it will not return
49
- * a truthy value in the <code>timeout<code>ms then throw a Timeout exception.
50
- * This is a very useful utility that will allow you to specify how often
51
- * a particular expression should be evaluated and how long will it take to end
52
- * the execution without success. Great for time-sensitive operations.
53
- *
54
- * @param cb callback to call every <code>interval</code>ms
55
- * @param timeout number of miliseconds that need to pass before the Timeout exception is thrown
56
- * @param interval number of miliseconds before re-running the callback
57
- */
58
- async function waitFor(cb, timeout = 10000, interval = 100) {
59
- return new Promise((resolve, reject) => {
60
- const timeoutTimer = setTimeout(() => {
61
- cleanup();
62
- reject('Timeout');
63
- }, timeout);
64
- const intervalTimer = setInterval(() => {
65
- const result = cb();
66
- if (result) {
67
- cleanup();
68
- resolve(result);
69
- }
70
- });
71
- const cleanup = () => {
72
- clearTimeout(timeoutTimer);
73
- clearTimeout(intervalTimer);
74
- };
75
- });
76
- }
77
- exports.waitFor = waitFor;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.waitFor=exports.sleep=exports.dump=exports.hex=void 0;function hex(t,o=2,e="0x"){return`${e}${t.toString(16).padStart(o,"0")}`}exports.hex=hex;function dump(t,o=16){const e=[];let r=0;for(let n=0;n<t.length;n++)e.push(hex(t[n],2,"0x")),e.length===o&&(console.log(hex(r,4),"|",e.join(" ")),r+=o,e.length=0);e.length>0&&console.log(hex(r,4),"|",e.join(" "))}exports.dump=dump;function sleep(t){return new Promise(o=>setTimeout(o,t))}exports.sleep=sleep;async function waitFor(t,o=1e4,e=100){return new Promise((r,n)=>{const l=setTimeout(()=>{s(),n("Timeout")},o),u=setInterval(()=>{const i=t();i&&(s(),r(i))}),s=()=>{clearTimeout(l),clearTimeout(u)}})}exports.waitFor=waitFor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mavlink",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "author": "Matthias Hryniszak <padcom@gmail.com>",
5
5
  "license": "LGPL",
6
6
  "description": "MavLink definitions and parsing library",
@@ -25,11 +25,12 @@
25
25
  "mavlink-mappings": "^1.0.9-20220424"
26
26
  },
27
27
  "scripts": {
28
- "build": "tsc",
29
- "test": "jest",
28
+ "build": "tsc && minimize-js dist",
29
+ "test": "jest && npm run test:batch",
30
+ "test:batch": "npx ts-node tests/main.ts e2e --input tests/data.mavlink",
30
31
  "dev": "jest --watch",
31
32
  "test:e2e": "cd tests && ./main.ts e2e --input data.mavlink",
32
- "prepublishOnly": "rm -rf dist && npm install && npm test && npm run test:e2e && npm run build"
33
+ "prepublishOnly": "rm -rf dist && npm install && npm run build && npm test"
33
34
  },
34
35
  "devDependencies": {
35
36
  "@types/jest": "^27.4.1",
@@ -37,6 +38,7 @@
37
38
  "@types/xml2js": "^0.4.8",
38
39
  "@types/yargs": "^17.0.8",
39
40
  "jest": "^27.5.1",
41
+ "minimize-js": "^1.3.0",
40
42
  "serialport": "^10.0.0",
41
43
  "ts-jest": "^27.1.4",
42
44
  "ts-node": "^9.1.1",
package/tests/main.ts CHANGED
@@ -3,8 +3,8 @@
3
3
  import yargs from 'yargs'
4
4
  import { existsSync, createReadStream } from 'fs'
5
5
  import { minimal, common, ardupilotmega } from 'mavlink-mappings'
6
- import { createMavLinkStream, MavLinkPacket, Logger, LogLevel } from '..'
7
- import { hex, dump } from '..'
6
+ import { createMavLinkStream, MavLinkPacket, Logger, LogLevel, MavLinkPacketRegistry } from '..'
7
+ import { dump } from '..'
8
8
 
9
9
  Logger.on('log', ({ context, level, message }) => {
10
10
  if (level <= LogLevel.error) {
@@ -36,7 +36,7 @@ async function main() {
36
36
 
37
37
  const command = config._[0]
38
38
  if (command === 'e2e') {
39
- const REGISTRY = {
39
+ const REGISTRY: MavLinkPacketRegistry = {
40
40
  ...minimal.REGISTRY,
41
41
  ...common.REGISTRY,
42
42
  ...ardupilotmega.REGISTRY,
@@ -48,11 +48,7 @@ async function main() {
48
48
  reader.on('data', (packet: MavLinkPacket) => {
49
49
  const clazz = REGISTRY[packet.header.msgid]
50
50
  if (clazz) {
51
- const message = packet.protocol.data(packet.payload, clazz)
52
- console.log('<', packet.debug())
53
- clazz.FIELDS.forEach(field => {
54
- console.log(clazz.MSG_NAME + '.' + field.source + ' = ' + message[field.name])
55
- })
51
+ packet.protocol.data(packet.payload, clazz)
56
52
  } else {
57
53
  console.log('< (unknown)', packet.debug())
58
54
  }