From 0bd28959278aeb5c6df0b888dcaf5dc84c25ac9b Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 10:27:13 +1100
Subject: [PATCH 01/34] sort javadocs
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 7a1f55e..1b3b305 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
4.0.0io.mapsmessagingmavlink
- 1.0.0
+ 1.0.1-SNAPSHOTjarMavlink parser, message formatter and schema
From ece0418974c39ce42ace5e4d635927cce976b4f6 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 10:29:25 +1100
Subject: [PATCH 02/34] fix read me
---
README.md | 75 ++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 52 insertions(+), 23 deletions(-)
diff --git a/README.md b/README.md
index be7862e..2fb3d62 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,33 @@
# MAVLink Payload Codec (Java)
-This repository provides a lightweight, schema-driven MAVLink payload
+This repository provides a lightweight, schema-driven MAVLink **payload**
encoder and decoder for Java.
-It parses MAVLink XML dialects (including `` handling), compiles
-message definitions, and provides fast, thread-safe encoding and decoding
-of MAVLink message **payloads**.
+It parses MAVLink XML dialects (including `{@code }` handling),
+compiles message definitions, and provides fast, thread-safe encoding and
+decoding of MAVLink message **payloads only**.
-This library is intentionally limited in scope.
+This library is intentionally limited in scope and designed to be composed
+into larger MAVLink-capable systems.
+---
-## Scope (Important)
+## Scope (Read This First)
This library operates **only on MAVLink message payloads**.
-It does **not**:
+It **does**:
+
+- Parse MAVLink XML dialects
+- Compile message definitions into an immutable registry
+- Encode Java field maps into MAVLink payload bytes
+- Decode MAVLink payload bytes into typed field maps
+- Correctly handle MAVLink field ordering, arrays, enums, and extensions
+
+It **does not**:
- Parse or generate MAVLink v1/v2 frames
-- Handle headers, CRCs, signing, or message framing
+- Handle headers, CRCs, signing, or framing
- Manage system IDs, component IDs, or sequence numbers
- Implement any transport (UART, UDP, TCP, etc.)
@@ -25,10 +35,11 @@ If you need a full MAVLink stack, this library is not it.
This library is designed to sit **under** a framing and transport layer.
+---
## Features
-- MAVLink XML dialect parsing with `` support
+- MAVLink XML dialect parsing with `{@code }` support
- Canonical dialect compilation (e.g. `common.xml`)
- Immutable, thread-safe compiled registries
- Correct MAVLink field ordering and packing rules
@@ -38,6 +49,7 @@ This library is designed to sit **under** a framing and transport layer.
- Safe failure on invalid or truncated payloads
- No shared mutable state at runtime
+---
## Getting Started
@@ -51,6 +63,9 @@ MavlinkCodec codec =
loader.getDialectOrThrow("common");
```
+The built-in `common` dialect is loaded eagerly and is always available.
+
+---
## Encoding a Payload
@@ -70,6 +85,7 @@ Map values = Map.of(
byte[] payload = codec.encodePayload(1, values);
```
+---
## Decoding a Payload
@@ -80,6 +96,10 @@ Map decoded =
int load = (int) decoded.get("load");
```
+Field values are returned using standard Java types based on the MAVLink
+message definition.
+
+---
## Loading Custom Dialects
@@ -92,8 +112,11 @@ try (InputStream xml = Files.newInputStream(Path.of("custom.xml"))) {
}
```
-Dialects are compiled once and cached by name.
+- Dialects are compiled once
+- Compiled codecs are cached by name
+- Subsequent lookups are lock-free
+---
## Thread Safety
@@ -107,16 +130,20 @@ A single codec instance may be safely:
- Cached globally
- Used in high-throughput systems
+---
## Error Handling
-- Unknown message IDs result in `IOException`
-- Invalid field types result in `IOException`
-- Invalid enum values result in `IOException`
-- Truncated or malformed payloads result in `IOException`
+All parsing and encoding errors are reported explicitly:
+
+- Unknown message IDs → `IOException`
+- Invalid field types → `IOException`
+- Invalid enum values → `IOException`
+- Truncated or malformed payloads → `IOException`
-No unchecked exceptions escape parsing paths.
+No unchecked exceptions escape payload encode/decode paths.
+---
## Design Philosophy
@@ -126,13 +153,7 @@ No unchecked exceptions escape parsing paths.
- Explicit errors over silent failure
- Practical MAVLink usage, not theoretical completeness
-
-## License
-
-Apache License 2.0
-
-See the `LICENSE` file for details.
-
+---
## Intended Users
@@ -143,5 +164,13 @@ This library is intended for:
- Telemetry ingestion pipelines
- MAVLink-aware tooling that does not want transport coupling
-If you want a full MAVLink stack, use something else.
+If you want a full MAVLink stack, use something else.
If you want a clean, deterministic payload codec, this is it.
+
+---
+
+## License
+
+Apache License 2.0
+
+See the `LICENSE` file for details.
From 1997aae6b56027b88c13f9ca06b8f8dac659089f Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 14:38:45 +1100
Subject: [PATCH 03/34] simply unpack the framing
---
README.md | 6 +--
.../mavlink/MavlinkFrameCodec.java | 31 ++++++++++++++
.../mavlink/MavlinkFrameEnvelope.java | 40 +++++++++++++++++++
3 files changed, 74 insertions(+), 3 deletions(-)
create mode 100644 src/main/java/io/mapsmessaging/mavlink/MavlinkFrameEnvelope.java
diff --git a/README.md b/README.md
index 2fb3d62..fcae0d7 100644
--- a/README.md
+++ b/README.md
@@ -26,12 +26,11 @@ It **does**:
It **does not**:
-- Parse or generate MAVLink v1/v2 frames
-- Handle headers, CRCs, signing, or framing
- Manage system IDs, component IDs, or sequence numbers
- Implement any transport (UART, UDP, TCP, etc.)
-If you need a full MAVLink stack, this library is not it.
+Frame parsing, CRC handling, and framing are provided by the framework layer
+built on top of this codec.
This library is designed to sit **under** a framing and transport layer.
@@ -174,3 +173,4 @@ If you want a clean, deterministic payload codec, this is it.
Apache License 2.0
See the `LICENSE` file for details.
+
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
index ba7b761..b189a42 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
@@ -103,6 +103,37 @@ public Optional tryUnpackFrame(ByteBuffer networkOwnedBuffer) {
return framer.tryDecode(networkOwnedBuffer);
}
+ /**
+ * Attempts to decode a single MAVLink frame and returns header + raw payload bytes only.
+ *
+ *
This does NOT decode payload fields. It is intended for routing decisions based on header metadata.
+ *
+ * @param networkOwnedBuffer network buffer in write-mode (may be flipped/compacted internally)
+ * @return envelope containing header fields + raw payload bytes if a complete valid frame is available
+ */
+ public Optional tryUnpackHeaderAndPayload(ByteBuffer networkOwnedBuffer) {
+ Optional decoded = framer.tryDecode(networkOwnedBuffer);
+ if (decoded.isEmpty()) {
+ return Optional.empty();
+ }
+
+ MavlinkFrame frame = decoded.get();
+ byte[] payload = Objects.requireNonNull(frame.getPayload(), "frame.payload");
+
+ MavlinkFrameEnvelope envelope = new MavlinkFrameEnvelope(
+ frame.getVersion(),
+ frame.getMessageId(),
+ frame.getSystemId(),
+ frame.getComponentId(),
+ frame.getSequence(),
+ frame.getPayloadLength(),
+ payload,
+ frame.isSigned()
+ );
+
+ return Optional.of(envelope);
+ }
+
/**
* Packs a MAVLink frame into the provided output buffer at its current position.
*
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameEnvelope.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameEnvelope.java
new file mode 100644
index 0000000..7ce1fa6
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameEnvelope.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package io.mapsmessaging.mavlink;
+
+import io.mapsmessaging.mavlink.message.MavlinkVersion;
+import lombok.Value;
+
+@Value
+public class MavlinkFrameEnvelope {
+
+ MavlinkVersion version;
+ int messageId;
+
+ int systemId;
+ int componentId;
+ int sequence;
+
+ int payloadLength;
+ byte[] payload;
+
+ boolean signed;
+}
From dc98e972a533e6ff9f10aa5e54c949292ea200aa Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 14:41:28 +1100
Subject: [PATCH 04/34] clean code
---
.../java/io/mapsmessaging/mavlink/MavlinkCodec.java | 3 ++-
.../io/mapsmessaging/mavlink/MavlinkFrameCodec.java | 2 +-
.../mavlink/MavlinkMessageFormatLoader.java | 11 ++++-------
.../mavlink/framing/MavlinkFramePacker.java | 6 ++----
.../mavlink/message/MavlinkMessageRegistry.java | 1 -
.../mavlink/message/fields/ArrayFieldCodec.java | 1 -
.../parser/ClasspathMavlinkIncludeResolver.java | 3 ++-
7 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkCodec.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkCodec.java
index b34d154..41737b3 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkCodec.java
@@ -3,10 +3,11 @@
import io.mapsmessaging.mavlink.codec.MavlinkPayloadPacker;
import io.mapsmessaging.mavlink.codec.MavlinkPayloadParser;
import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
+import lombok.Getter;
+
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
-import lombok.Getter;
/**
* MAVLink payload codec for a specific dialect.
*
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
index b189a42..6a8be74 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
@@ -23,9 +23,9 @@
import io.mapsmessaging.mavlink.framing.MavlinkDialectRegistry;
import io.mapsmessaging.mavlink.framing.MavlinkFrameFramer;
import io.mapsmessaging.mavlink.framing.MavlinkFramePacker;
+import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
import io.mapsmessaging.mavlink.message.MavlinkFrame;
import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
import io.mapsmessaging.mavlink.message.MavlinkVersion;
import java.io.IOException;
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkMessageFormatLoader.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkMessageFormatLoader.java
index cf278a5..2d10e22 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkMessageFormatLoader.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkMessageFormatLoader.java
@@ -23,19 +23,16 @@
import io.mapsmessaging.mavlink.codec.MavlinkPayloadPacker;
import io.mapsmessaging.mavlink.codec.MavlinkPayloadParser;
import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.parser.ClasspathMavlinkIncludeResolver;
-import io.mapsmessaging.mavlink.parser.MavlinkDialectDefinition;
-import io.mapsmessaging.mavlink.parser.MavlinkDialectLoader;
-import io.mapsmessaging.mavlink.parser.MavlinkIncludeResolver;
-import io.mapsmessaging.mavlink.parser.MavlinkXmlParser;
+import io.mapsmessaging.mavlink.parser.*;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
-import javax.xml.parsers.ParserConfigurationException;
-import org.xml.sax.SAXException;
/**
* Loads and caches MAVLink dialect definitions and builds {@link MavlinkCodec} instances for them.
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
index 403e42d..06f6ea4 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
@@ -122,10 +122,8 @@ private void packV2(ByteBuffer out, MavlinkFrame frame) {
boolean signed = frame.isSigned();
byte[] signature = frame.getSignature();
- if (signed) {
- if (signature == null || signature.length != V2_SIGNATURE_LENGTH) {
- throw new IllegalArgumentException("Signed v2 frame must have signature[13]");
- }
+ if (signed && signature == null || signature.length != V2_SIGNATURE_LENGTH) {
+ throw new IllegalArgumentException("Signed v2 frame must have signature[13]");
}
int required = 1 + MAVLINK_V2_HEADER_LENGTH + payloadLength + CRC_LENGTH + (signed ? V2_SIGNATURE_LENGTH : 0);
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
index f5176f9..79ae94c 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
@@ -22,7 +22,6 @@
import io.mapsmessaging.mavlink.message.fields.MavlinkFieldCodecFactory;
import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
import io.mapsmessaging.mavlink.parser.MavlinkDialectDefinition;
-import lombok.Data;
import lombok.Getter;
import lombok.Setter;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
index bbd53f9..4ce6507 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
@@ -19,7 +19,6 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.ArrayList;
import java.util.List;
public class ArrayFieldCodec extends AbstractMavlinkFieldCodec {
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java b/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
index 676784c..2356447 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
@@ -17,6 +17,7 @@
package io.mapsmessaging.mavlink.parser;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
@@ -33,7 +34,7 @@ public ClasspathMavlinkIncludeResolver(ClassLoader classLoader, String basePath)
@Override
public InputStream open(String includeName) throws IOException {
- String path = basePath.endsWith("/") ? (basePath + includeName) : (basePath + "/" + includeName);
+ String path = basePath.endsWith("/") ? (basePath + includeName) : (basePath + File.separator + includeName);
return classLoader.getResourceAsStream(path);
}
}
From ba5eb2ba724410592dd9407fd267f2eeceebd9b1 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 14:53:04 +1100
Subject: [PATCH 05/34] fix issue in cleanup
---
.../io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
index 06f6ea4..ebfc106 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
@@ -122,7 +122,7 @@ private void packV2(ByteBuffer out, MavlinkFrame frame) {
boolean signed = frame.isSigned();
byte[] signature = frame.getSignature();
- if (signed && signature == null || signature.length != V2_SIGNATURE_LENGTH) {
+ if (signed && (signature == null || signature.length != V2_SIGNATURE_LENGTH)) {
throw new IllegalArgumentException("Signed v2 frame must have signature[13]");
}
From e1b44a7e8c2fae79881fc7138b7186b3aafb8cd4 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 20:08:13 +1100
Subject: [PATCH 06/34] align the flip() with maps
---
.../io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java | 2 --
.../mavlink/MavlinkFrameRoundTripAllMessagesTest.java | 2 +-
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java
index 48f9946..701f984 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java
@@ -45,8 +45,6 @@ public MavlinkFrameFramer(MavlinkDialectRegistry dialectRegistry) {
}
public Optional tryDecode(ByteBuffer networkOwnedBuffer) {
- networkOwnedBuffer.flip();
-
try {
if (!networkOwnedBuffer.hasRemaining()) {
return Optional.empty();
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
index dc9c32a..d420c47 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
@@ -64,7 +64,7 @@ private static void frameRoundTripForMessageV2(
ByteBuffer networkOwned = ByteBuffer.allocate(out.remaining() + 16);
networkOwned.put(out);
-
+ networkOwned.flip();
Optional decodedOpt = frameCodec.tryUnpackFrame(networkOwned);
assertTrue(decodedOpt.isPresent(), "Expected to decode a frame");
From 8f8aae313827eaeb730b487e20c2c4fd4e6b4851 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 20:29:16 +1100
Subject: [PATCH 07/34] fix crc
---
.../mapsmessaging/mavlink/message/X25Crc.java | 30 +++++++++----------
.../io/mapsmessaging/mavlink/X25CrcTest.java | 2 +-
2 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/X25Crc.java b/src/main/java/io/mapsmessaging/mavlink/message/X25Crc.java
index a3bee19..31384e5 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/X25Crc.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/X25Crc.java
@@ -18,17 +18,14 @@
package io.mapsmessaging.mavlink.message;
/**
- * CRC-16/X.25 implementation.
- *
- * This matches the CRC used by MAVLink v1 and v2.
+ * XorOut : 0x0000 (IMPORTANT: MAVLink does NOT apply final XOR)
*/
public final class X25Crc {
@@ -41,9 +38,6 @@ public X25Crc() {
reset();
}
- /**
- * Convenience one-shot calculation.
- */
public static int calculate(byte[] buffer, int offset, int length) {
X25Crc crc = new X25Crc();
crc.update(buffer, offset, length);
@@ -52,7 +46,7 @@ public static int calculate(byte[] buffer, int offset, int length) {
public static int calculate(byte[] buffer) {
if (buffer == null) {
- return INITIAL_CRC ^ 0xFFFF;
+ return INITIAL_CRC;
}
return calculate(buffer, 0, buffer.length);
}
@@ -68,6 +62,7 @@ public void update(byte value) {
public void update(int value) {
int data = value & 0xFF;
currentCrc ^= data;
+
for (int bitIndex = 0; bitIndex < 8; bitIndex++) {
if ((currentCrc & 0x0001) != 0) {
currentCrc = (currentCrc >>> 1) ^ POLYNOMIAL;
@@ -75,6 +70,8 @@ public void update(int value) {
currentCrc = currentCrc >>> 1;
}
}
+
+ currentCrc = currentCrc & 0xFFFF;
}
public void update(byte[] buffer) {
@@ -88,6 +85,7 @@ public void update(byte[] buffer, int offset, int length) {
if (buffer == null) {
return;
}
+
int endIndex = offset + length;
for (int index = offset; index < endIndex; index++) {
update(buffer[index] & 0xFF);
@@ -95,19 +93,19 @@ public void update(byte[] buffer, int offset, int length) {
}
/**
- * Returns the final CRC value (after applying XorOut).
+ * MAVLink final CRC (no xor-out).
*/
public int getCrc() {
- return currentCrc ^ 0xFFFF;
+ return currentCrc & 0xFFFF;
}
- /**
- * Returns the final CRC as a 16-bit value (lower 16 bits).
- */
public short getCrcAsShort() {
- return (short) (getCrc() & 0xFFFF);
+ return (short) (currentCrc & 0xFFFF);
}
+ /**
+ * Same as getCrc(); kept for compatibility if callers used it.
+ */
public int getRawCrc() {
return currentCrc & 0xFFFF;
}
diff --git a/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java b/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
index 33e5e87..f126feb 100644
--- a/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
@@ -38,7 +38,7 @@ void testKnownVector_123456789() {
crc.update(data);
int crcValue = crc.getCrc() & 0xFFFF;
- assertEquals(0x906E, crcValue, "CRC-16/X.25 of '123456789' must be 0x906E");
+ assertEquals(0x6F91, crcValue, "CRC-16/X.25 of '123456789' must be 0x906E");
}
@Test
From 5e81a26aafcac3448e27a2a5d64fab238a85a699 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 21:03:28 +1100
Subject: [PATCH 08/34] compute the extra crc
---
.../parser/MavlinkExtraCrcCalculator.java | 49 +++++++++++++++++++
.../mavlink/parser/MavlinkXmlParser.java | 2 +
.../io/mapsmessaging/mavlink/X25CrcTest.java | 34 +++++++++++++
3 files changed, 85 insertions(+)
create mode 100644 src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java
new file mode 100644
index 0000000..219eb10
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java
@@ -0,0 +1,49 @@
+package io.mapsmessaging.mavlink.parser;
+
+import io.mapsmessaging.mavlink.message.MavlinkMessageDefinition;
+import io.mapsmessaging.mavlink.message.X25Crc;
+import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+public final class MavlinkExtraCrcCalculator {
+
+ private MavlinkExtraCrcCalculator() {
+ }
+
+ public static int computeExtraCrc(MavlinkMessageDefinition messageDefinition) {
+ X25Crc crc = new X25Crc();
+ String messageName = messageDefinition.getName();
+ List wireOrderedFields = messageDefinition.getFields();
+ accumulateTokenWithSpace(crc, messageName);
+
+ for (MavlinkFieldDefinition field : wireOrderedFields) {
+ if (field.isExtension()) {
+ continue;
+ }
+
+ accumulateTokenWithSpace(crc, field.getType());
+ accumulateTokenWithSpace(crc, field.getName());
+
+ if (field.isArray()) {
+ crc.update(field.getArrayLength() & 0xFF);
+ }
+ }
+
+ int crc16 = crc.getCrc() & 0xFFFF;
+ return ((crc16 & 0xFF) ^ (crc16 >>> 8)) & 0xFF;
+ }
+
+ private static void accumulateTokenWithSpace(X25Crc crc, String token) {
+ if (token == null) {
+ return;
+ }
+
+ byte[] bytes = token.getBytes(StandardCharsets.US_ASCII);
+ for (byte value : bytes) {
+ crc.update(value);
+ }
+ crc.update((byte) ' ');
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
index b7c88cb..c251b16 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
@@ -199,6 +199,8 @@ private MavlinkMessageDefinition parseMessage(Element messageElement) {
List fields = parseMessageFields(messageElement);
messageDefinition.setXmlOrderedFields(fields);
+ int extraCrc = MavlinkExtraCrcCalculator.computeExtraCrc(messageDefinition);
+ messageDefinition.setExtraCrc(extraCrc);
return messageDefinition;
}
diff --git a/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java b/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
index f126feb..de4254f 100644
--- a/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
@@ -23,6 +23,7 @@
import io.mapsmessaging.mavlink.message.X25Crc;
import org.junit.jupiter.api.Test;
+import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -41,6 +42,39 @@ void testKnownVector_123456789() {
assertEquals(0x6F91, crcValue, "CRC-16/X.25 of '123456789' must be 0x906E");
}
+ @Test
+ void testMavlink2FrameCrc_attitudeQuaternion_31() {
+ int[] signed = new int[] {
+ -3, 32, 0, 0, -56, 1, 1, 31, 0, 0,
+ 24, 35, 27, 0, 126, 45, 42, 63, -11, -55, 33, 56, -13, 23, -48, -72, 83, 63, 63, 63, -58, 54, 67, -70, 122, 57, 32, -71, 77, -44, 43, -71,
+ 75, -68
+ };
+
+
+
+ byte[] frame = new byte[signed.length];
+
+ for (int index = 0; index < signed.length; index++) {
+ frame[index] = (byte) signed[index];
+ }
+ int payloadLength = frame[1] & 0xFF;
+ assertEquals(32, payloadLength);
+ int receivedCrc = (frame[42] & 0xFF) | ((frame[43] & 0xFF) << 8);
+ assertEquals(0xBC4B, receivedCrc);
+
+ // MAVLink2 CRC input = bytes from LEN (index 1) through payload end (index 41), then CRC_EXTRA
+ int crcInputOffset = 1;
+ int crcInputLength = 9 + payloadLength; // LEN..MSGID(3) is 9 bytes, then payload
+ X25Crc crc = new X25Crc();
+ crc.update(frame, crcInputOffset, crcInputLength);
+
+ int crcExtra = 246; // MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC :contentReference[oaicite:1]{index=1}
+ crc.update(crcExtra);
+
+ int computed = crc.getCrc();
+ assertEquals(receivedCrc, computed, "Computed CRC must match the frame CRC");
+ }
+
@Test
void testHeartbeatExtraCrc() {
// HEARTBEAT extra CRC is 50 (0x32) according to MAVLink tables.
From cacd50660f0854f7bc681267b376159ccc693847 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Sun, 4 Jan 2026 21:12:21 +1100
Subject: [PATCH 09/34] compute the extra crc
---
.../mavlink/message/MavlinkCompiledMessage.java | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java
index 347b78f..18e013f 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java
@@ -31,7 +31,10 @@ public class MavlinkCompiledMessage {
private List compiledFields;
private int payloadSizeBytes;
private int minimumPayloadSizeBytes;
- private int crcExtra;
+
+ public int getCrcExtra(){
+ return messageDefinition.getExtraCrc();
+ }
@Override
public String toString() {
@@ -45,7 +48,7 @@ public String toString() {
.append(", minPayloadSize=")
.append(minimumPayloadSizeBytes)
.append(", crcExtra=")
- .append(crcExtra)
+ .append(messageDefinition.getExtraCrc())
.append("]\n");
for (MavlinkCompiledField compiledField : compiledFields) {
From e994a6c25a3105774648025bddb3e06ae4649ec1 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Mon, 5 Jan 2026 09:33:06 +1100
Subject: [PATCH 10/34] windows fails to load from the jar
---
.../mavlink/parser/ClasspathMavlinkIncludeResolver.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java b/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
index 2356447..a35d47b 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
@@ -34,7 +34,7 @@ public ClasspathMavlinkIncludeResolver(ClassLoader classLoader, String basePath)
@Override
public InputStream open(String includeName) throws IOException {
- String path = basePath.endsWith("/") ? (basePath + includeName) : (basePath + File.separator + includeName);
+ String path = basePath.endsWith("/") ? (basePath + includeName) : (basePath + "/" + includeName);
return classLoader.getResourceAsStream(path);
}
}
From 010a59097ce4ffb6e3396929fbb0d86f7421d7b0 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Mon, 5 Jan 2026 11:32:51 +1100
Subject: [PATCH 11/34] parse V1 correctly
---
.../framing/MavlinkV1FrameHandler.java | 8 +++----
.../mavlink/parser/MavlinkXmlParser.java | 3 ---
.../mapsmessaging/mavlink/HeartbeatTest.java | 22 +++++++++++++++++++
3 files changed, 26 insertions(+), 7 deletions(-)
create mode 100644 src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java
index fe2cd98..f98e0b8 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java
@@ -39,7 +39,7 @@ public MavlinkV1FrameHandler(MavlinkDialectRegistry dialectRegistry) {
@Override
public int minimumBytesRequiredForHeader() {
- return 1 + HEADER_LENGTH;
+ return HEADER_LENGTH;
}
@Override
@@ -49,7 +49,7 @@ public int peekPayloadLength(ByteBuffer buffer, int frameStartIndex) {
@Override
public int computeTotalFrameLength(ByteBuffer buffer, int frameStartIndex, int payloadLength) {
- return 1 + HEADER_LENGTH + payloadLength + CRC_LENGTH;
+ return HEADER_LENGTH + payloadLength + CRC_LENGTH;
}
@Override
@@ -72,13 +72,13 @@ public Optional tryDecode(ByteBuffer candidateFrame) {
return Optional.empty();
}
- int payloadStartIndex = frameStartIndex + 1 + HEADER_LENGTH;
+ int payloadStartIndex = frameStartIndex + HEADER_LENGTH;
int crcStartIndex = payloadStartIndex + payloadLength;
int receivedChecksum = ByteBufferUtils.readUnsignedLittleEndianShort(candidateFrame, crcStartIndex);
int crcExtra = dialectRegistry.crcExtra(MavlinkVersion.V1, messageId);
- int computedChecksum = CrcHelper.computeChecksumFromWritten(candidateFrame, frameStartIndex + 1, (HEADER_LENGTH-1) + payloadLength, crcExtra);
+ int computedChecksum = CrcHelper.computeChecksumFromWritten(candidateFrame, frameStartIndex + 1, (HEADER_LENGTH) + payloadLength-1, crcExtra);
if (computedChecksum != receivedChecksum) {
return Optional.empty();
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
index c251b16..27813bd 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
@@ -198,9 +198,6 @@ private MavlinkMessageDefinition parseMessage(Element messageElement) {
List fields = parseMessageFields(messageElement);
messageDefinition.setXmlOrderedFields(fields);
-
- int extraCrc = MavlinkExtraCrcCalculator.computeExtraCrc(messageDefinition);
- messageDefinition.setExtraCrc(extraCrc);
return messageDefinition;
}
diff --git a/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java b/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
new file mode 100644
index 0000000..bbb8948
--- /dev/null
+++ b/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
@@ -0,0 +1,22 @@
+package io.mapsmessaging.mavlink;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.nio.ByteBuffer;
+
+class HeartbeatTest {
+
+ @Test
+ void validateV1Heartbeat() throws Exception {
+ int[] load = new int[]{0xfe,0x09,0x81,0xff,0xbe,0x00,0x00,0x00,0x00,0x00,0x06,0x08,0xc0,0x04,0x03,0xa4,0xe2};
+ byte[] buffer = new byte[load.length];
+ for(int x=0;x
Date: Mon, 5 Jan 2026 13:45:51 +1100
Subject: [PATCH 12/34] generate json schemas
---
README.md | 1 +
pom.xml | 8 +
.../message/MavlinkMessageRegistry.java | 12 ++
.../message/fields/MavlinkWireType.java | 11 ++
.../schema/MavlinkJsonSchemaBuilder.java | 138 ++++++++++++++++++
...avlinkPayloadJsonSchemaValidationTest.java | 78 ++++++++++
6 files changed, 248 insertions(+)
create mode 100644 src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java
create mode 100644 src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
diff --git a/README.md b/README.md
index fcae0d7..952de07 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ It **does**:
- Encode Java field maps into MAVLink payload bytes
- Decode MAVLink payload bytes into typed field maps
- Correctly handle MAVLink field ordering, arrays, enums, and extensions
+- Creates JsonSchemas to match the fields that it parses to and from
It **does not**:
diff --git a/pom.xml b/pom.xml
index 1b3b305..4b4585b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -378,6 +378,14 @@
6.0.1
+
+ com.networknt
+ json-schema-validator
+ 1.5.1
+ test
+
+
+
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
index 79ae94c..7b3db45 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
@@ -17,11 +17,13 @@
package io.mapsmessaging.mavlink.message;
+import com.google.gson.JsonObject;
import io.mapsmessaging.mavlink.message.fields.AbstractMavlinkFieldCodec;
import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
import io.mapsmessaging.mavlink.message.fields.MavlinkFieldCodecFactory;
import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
import io.mapsmessaging.mavlink.parser.MavlinkDialectDefinition;
+import io.mapsmessaging.mavlink.schema.MavlinkJsonSchemaBuilder;
import lombok.Getter;
import lombok.Setter;
@@ -39,22 +41,29 @@ public class MavlinkMessageRegistry {
private Map enumsByName;
+ private Map jsonSchema;
+
+
+
public static MavlinkMessageRegistry fromDialectDefinition(MavlinkDialectDefinition dialectDefinition) {
MavlinkMessageRegistry registry = new MavlinkMessageRegistry();
registry.setDialectName(dialectDefinition.getName());
List compiledMessageList = new ArrayList<>();
Map compiledByIdMap = new HashMap<>();
+ Map schemaMap = new HashMap<>();
for (MavlinkMessageDefinition messageDefinition : dialectDefinition.getMessages()) {
MavlinkCompiledMessage compiledMessage = compileMessage(messageDefinition);
compiledMessageList.add(compiledMessage);
compiledByIdMap.put(compiledMessage.getMessageId(), compiledMessage);
+ schemaMap.put(compiledMessage.getMessageId(), MavlinkJsonSchemaBuilder.buildSchema(compiledMessage, dialectDefinition.getEnumsByName()));
}
registry.setCompiledMessages(compiledMessageList);
registry.setCompiledMessagesById(compiledByIdMap);
registry.setEnumsByName(new HashMap<>(dialectDefinition.getEnumsByName()));
+ registry.setJsonSchema(schemaMap);
return registry;
}
@@ -71,6 +80,9 @@ private void setCompiledMessages(List compiledMessageLis
this.compiledMessages = Collections.unmodifiableList(new ArrayList<>(compiledMessageList));
}
+ private void setJsonSchema(Map jsonSchemaMap ){
+ this.jsonSchema = Collections.unmodifiableMap(new HashMap<>(jsonSchemaMap));
+ }
private static MavlinkCompiledMessage compileMessage(MavlinkMessageDefinition messageDefinition) {
MavlinkCompiledMessage compiledMessage = new MavlinkCompiledMessage();
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java
index 4bd830a..b7d5c18 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java
@@ -75,4 +75,15 @@ public static MavlinkWireType fromXmlType(String xmlType) {
};
}
+ public boolean isChar(){
+ return wireName.equals("char");
+ }
+
+ public boolean isFloat(){
+ return wireName.equals("float");
+ }
+
+ public boolean isDouble(){
+ return wireName.equals("double");
+ }
}
\ No newline at end of file
diff --git a/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java b/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java
new file mode 100644
index 0000000..8f73a5d
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java
@@ -0,0 +1,138 @@
+package io.mapsmessaging.mavlink.schema;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
+import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
+import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
+import io.mapsmessaging.mavlink.message.fields.MavlinkEnumEntry;
+import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.MavlinkWireType;
+
+import java.util.Map;
+
+public final class MavlinkJsonSchemaBuilder {
+
+ private MavlinkJsonSchemaBuilder() {
+ }
+
+ public static JsonObject buildSchema(
+ MavlinkCompiledMessage message,
+ Map enumsByName) {
+
+ JsonObject schema = new JsonObject();
+ schema.addProperty("$schema", "https://json-schema.org/draft/2020-12/schema");
+ schema.addProperty("title", message.getName());
+ schema.addProperty("type", "object");
+ schema.addProperty("description",
+ message.getMessageDefinition().getDescription());
+
+ JsonObject properties = new JsonObject();
+ JsonArray required = new JsonArray();
+
+ for (MavlinkCompiledField compiledField : message.getCompiledFields()) {
+ MavlinkFieldDefinition field = compiledField.getFieldDefinition();
+
+ JsonObject fieldSchema = buildFieldSchema(field, enumsByName);
+ properties.add(field.getName(), fieldSchema);
+
+ if (!field.isExtension()) {
+ required.add(field.getName());
+ }
+ }
+
+ schema.add("properties", properties);
+ if (!required.isEmpty()) {
+ schema.add("required", required);
+ }
+
+ schema.addProperty("additionalProperties", false);
+ schema.addProperty("x-message-id", message.getMessageId());
+ schema.addProperty("x-crc-extra", message.getCrcExtra());
+
+ return schema;
+ }
+
+ private static JsonObject buildFieldSchema(
+ MavlinkFieldDefinition field,
+ Map enumsByName) {
+
+ JsonObject schema = new JsonObject();
+
+ if (field.getDescription() != null) {
+ schema.addProperty("description", field.getDescription());
+ }
+
+ MavlinkWireType wireType = field.getWireType();
+
+ // char[N] → string
+ if (field.isArray() && wireType.isChar()) {
+ schema.addProperty("type", "string");
+ schema.addProperty("maxLength", field.getArrayLength());
+ return schema;
+ }
+
+ // Arrays
+ if (field.isArray()) {
+ schema.addProperty("type", "array");
+ schema.addProperty("minItems", field.getArrayLength());
+ schema.addProperty("maxItems", field.getArrayLength());
+
+ JsonObject itemSchema = scalarSchema(field, enumsByName);
+ schema.add("items", itemSchema);
+ return schema;
+ }
+
+ // Scalar
+ return scalarSchema(field, enumsByName);
+ }
+
+ private static JsonObject scalarSchema(
+ MavlinkFieldDefinition field,
+ Map enumsByName) {
+
+ JsonObject schema = new JsonObject();
+ MavlinkWireType wireType = field.getWireType();
+
+ if (wireType.isFloat() || wireType.isDouble()) {
+ schema.addProperty("type", "number");
+ } else {
+ schema.addProperty("type", "integer");
+ }
+
+ if (field.getEnumName() != null) {
+ MavlinkEnumDefinition enumDef = enumsByName.get(field.getEnumName());
+ if (enumDef != null) {
+ applyEnum(schema, enumDef);
+ }
+ }
+
+ return schema;
+ }
+
+ private static void applyEnum(
+ JsonObject schema,
+ MavlinkEnumDefinition enumDef) {
+
+ schema.addProperty("x-enum-name", enumDef.getName());
+
+ if (enumDef.isBitmask()) {
+ schema.addProperty("description",
+ "Bitmask enum: " + enumDef.getName());
+ return;
+ }
+
+ JsonArray oneOf = new JsonArray();
+ for (MavlinkEnumEntry entry : enumDef.getEntries()) {
+ JsonObject option = new JsonObject();
+ option.addProperty("const", entry.getValue());
+ option.addProperty("title", entry.getName());
+ if (entry.getDescription() != null) {
+ option.addProperty("description", entry.getDescription());
+ }
+ oneOf.add(option);
+ }
+
+ schema.add("oneOf", oneOf);
+ }
+}
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
new file mode 100644
index 0000000..bca06dc
--- /dev/null
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
@@ -0,0 +1,78 @@
+package io.mapsmessaging.mavlink;
+
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.networknt.schema.JsonSchema;
+import com.networknt.schema.JsonSchemaFactory;
+import com.networknt.schema.SpecVersion;
+import com.networknt.schema.ValidationMessage;
+import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
+import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.TestFactory;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MavlinkPayloadJsonSchemaValidationTest extends BaseRoudTripTest {
+
+ private static final Gson GSON = new Gson();
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ @TestFactory
+ Stream allMessages_payload_toJson_validatesAgainstSchema() throws Exception {
+ MavlinkCodec payloadCodec = MavlinkTestSupport.codec();
+ MavlinkMessageRegistry registry = payloadCodec.getRegistry();
+
+ return registry.getCompiledMessages().stream()
+ .map(msg -> DynamicTest.dynamicTest(
+ msg.getMessageId() + " " + msg.getName(),
+ () -> payloadToJsonValidates(payloadCodec, registry, msg)
+ ));
+ }
+
+ private static void payloadToJsonValidates(
+ MavlinkCodec payloadCodec,
+ MavlinkMessageRegistry registry,
+ MavlinkCompiledMessage msg
+ ) throws Exception {
+
+ Map values =
+ RandomValueFactory.buildValues(registry, msg, MavlinkRoundTripAllMessagesTest.ExtensionMode.SOME_PRESENT, BASE_SEED);
+
+ byte[] payload = payloadCodec.encodePayload(msg.getMessageId(), values);
+ assertNotNull(payload);
+
+ Map parsed = payloadCodec.parsePayload(msg.getMessageId(), payload);
+ assertNotNull(parsed);
+
+ JsonObject jsonObject = GSON.toJsonTree(parsed).getAsJsonObject();
+
+ // Build schema for this message
+ JsonObject schemaObject =
+ io.mapsmessaging.mavlink.schema.MavlinkJsonSchemaBuilder.buildSchema(msg, registry.getEnumsByName());
+
+ JsonSchema schema = compileSchema(schemaObject);
+ Set errors = schema.validate(toJsonNode(jsonObject));
+
+ assertTrue(errors.isEmpty(),
+ () -> "Schema validation failed for msgId=" + msg.getMessageId() + " " + msg.getName() + "\n" +
+ String.join("\n", errors.stream().map(ValidationMessage::getMessage).toList()));
+ }
+
+ private static JsonSchema compileSchema(JsonObject schemaObject) throws Exception {
+ JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
+ JsonNode schemaNode = toJsonNode(schemaObject);
+ return factory.getSchema(schemaNode);
+ }
+
+ private static JsonNode toJsonNode(JsonObject gsonObject) throws Exception {
+ return OBJECT_MAPPER.readTree(GSON.toJson(gsonObject));
+ }
+}
From 0f984a2a2f09a1497cef9065f6c93c91cf20b313 Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Mon, 5 Jan 2026 16:19:33 +1100
Subject: [PATCH 13/34] update copyright
---
.../mapsmessaging/mavlink/MavlinkCodec.java | 19 ++++++++++++++++
.../mavlink/MavlinkFrameCodec.java | 1 -
.../mavlink/MavlinkFrameEnvelope.java | 1 -
.../mavlink/MavlinkMessageFormatLoader.java | 1 -
.../mavlink/codec/MavlinkFrameEncoder.java | 22 ++++++++++---------
.../mavlink/codec/MavlinkFrameFactory.java | 22 ++++++++++---------
.../mavlink/codec/MavlinkJsonCodec.java | 22 ++++++++++---------
.../codec/MavlinkJsonValuesExtractor.java | 22 ++++++++++---------
.../mavlink/codec/MavlinkMapConverter.java | 22 ++++++++++---------
.../mavlink/codec/MavlinkPayloadPacker.java | 19 ++++++++++++++++
.../mavlink/codec/MavlinkPayloadParser.java | 3 +--
.../mavlink/framing/ByteBufferUtils.java | 22 ++++++++++---------
.../mavlink/framing/CrcHelper.java | 19 ++++++++++++++++
.../framing/MavlinkDialectRegistry.java | 22 ++++++++++---------
.../mavlink/framing/MavlinkFrameDecoder.java | 19 ++++++++++++++++
.../mavlink/framing/MavlinkFrameFramer.java | 22 ++++++++++---------
.../mavlink/framing/MavlinkFrameHandler.java | 22 ++++++++++---------
.../mavlink/framing/MavlinkFramePacker.java | 22 ++++++++++---------
.../framing/MavlinkV1FrameHandler.java | 22 ++++++++++---------
.../framing/MavlinkV2FrameHandler.java | 22 ++++++++++---------
.../mavlink/message/MavlinkCompiledField.java | 22 ++++++++++---------
.../message/MavlinkCompiledMessage.java | 22 ++++++++++---------
.../mavlink/message/MavlinkEnumResolver.java | 22 ++++++++++---------
.../mavlink/message/MavlinkFrame.java | 22 ++++++++++---------
.../mavlink/message/MavlinkFrameParser.java | 22 ++++++++++---------
.../message/MavlinkMessageDefinition.java | 22 ++++++++++---------
.../message/MavlinkMessageRegistry.java | 22 ++++++++++---------
.../mavlink/message/MavlinkVersion.java | 22 ++++++++++---------
.../mapsmessaging/mavlink/message/X25Crc.java | 22 ++++++++++---------
.../fields/AbstractMavlinkFieldCodec.java | 22 ++++++++++---------
.../message/fields/ArrayFieldCodec.java | 22 ++++++++++---------
.../message/fields/CharFieldCodec.java | 22 ++++++++++---------
.../message/fields/DoubleFieldCodec.java | 22 ++++++++++---------
.../message/fields/FloatFieldCodec.java | 22 ++++++++++---------
.../message/fields/Int16FieldCodec.java | 22 ++++++++++---------
.../message/fields/Int32FieldCodec.java | 22 ++++++++++---------
.../message/fields/Int64FieldCodec.java | 22 ++++++++++---------
.../message/fields/Int8FieldCodec.java | 22 ++++++++++---------
.../message/fields/MavlinkEnumDefinition.java | 22 ++++++++++---------
.../message/fields/MavlinkEnumEntry.java | 22 ++++++++++---------
.../fields/MavlinkFieldCodecFactory.java | 22 ++++++++++---------
.../fields/MavlinkFieldDefinition.java | 22 ++++++++++---------
.../message/fields/MavlinkWireType.java | 22 ++++++++++---------
.../message/fields/UInt16FieldCodec.java | 22 ++++++++++---------
.../message/fields/UInt32FieldCodec.java | 22 ++++++++++---------
.../message/fields/UInt64FieldCodec.java | 22 ++++++++++---------
.../message/fields/UInt8FieldCodec.java | 22 ++++++++++---------
.../ClasspathMavlinkIncludeResolver.java | 22 ++++++++++---------
.../parser/MavlinkDialectDefinition.java | 3 +--
.../mavlink/parser/MavlinkDialectLoader.java | 22 ++++++++++---------
.../parser/MavlinkExtraCrcCalculator.java | 19 ++++++++++++++++
.../parser/MavlinkIncludeResolver.java | 22 ++++++++++---------
.../mavlink/parser/MavlinkXmlParser.java | 3 +--
.../schema/MavlinkJsonSchemaBuilder.java | 19 ++++++++++++++++
.../mavlink/BaseRoudTripTest.java | 19 ++++++++++++++++
.../mapsmessaging/mavlink/HeartbeatTest.java | 19 ++++++++++++++++
.../MavlinkFrameRoundTripAllMessagesTest.java | 19 ++++++++++++++++
...avlinkPayloadJsonSchemaValidationTest.java | 19 ++++++++++++++++
.../MavlinkRoundTripAllMessagesTest.java | 19 ++++++++++++++++
.../mavlink/MavlinkTestSupport.java | 19 ++++++++++++++++
.../mavlink/TestMavlinkCharArrays.java | 19 ++++++++++++++++
.../mavlink/TestMavlinkConcurrency.java | 19 ++++++++++++++++
.../mavlink/TestMavlinkExtensions.java | 19 ++++++++++++++++
.../mavlink/TestMavlinkNumericArrays.java | 19 ++++++++++++++++
.../TestMavlinkRegistryInvariants.java | 19 ++++++++++++++++
.../mavlink/TestMavlinkRobustness.java | 19 ++++++++++++++++
.../mavlink/TestMavlinkXmlParserIncludes.java | 19 ++++++++++++++++
.../io/mapsmessaging/mavlink/X25CrcTest.java | 3 +--
68 files changed, 869 insertions(+), 431 deletions(-)
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkCodec.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkCodec.java
index 41737b3..b3b5521 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkCodec.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.codec.MavlinkPayloadPacker;
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
index 6a8be74..29198d6 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
@@ -15,7 +15,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package io.mapsmessaging.mavlink;
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameEnvelope.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameEnvelope.java
index 7ce1fa6..e96fbaa 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameEnvelope.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameEnvelope.java
@@ -15,7 +15,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package io.mapsmessaging.mavlink;
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkMessageFormatLoader.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkMessageFormatLoader.java
index 2d10e22..1a8743e 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkMessageFormatLoader.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkMessageFormatLoader.java
@@ -15,7 +15,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package io.mapsmessaging.mavlink;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameEncoder.java b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameEncoder.java
index b25cb14..8969fa5 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameEncoder.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameEncoder.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.codec;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameFactory.java b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameFactory.java
index cc41ccd..9a2bd6a 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameFactory.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameFactory.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.codec;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonCodec.java b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonCodec.java
index b2d84bf..4ad7ea2 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.codec;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonValuesExtractor.java b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonValuesExtractor.java
index 79ad817..ae5f2ab 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonValuesExtractor.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonValuesExtractor.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.codec;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkMapConverter.java b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkMapConverter.java
index 0d00fe8..a8ce233 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkMapConverter.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkMapConverter.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.codec;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadPacker.java b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadPacker.java
index d224fb6..349f7c2 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadPacker.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadPacker.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink.codec;
import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java
index dfee1df..40c97e2 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java
@@ -1,7 +1,7 @@
/*
*
* Copyright [ 2020 - 2024 ] Matthew Buckton
- * Copyright [ 2024 - 2025 ] MapsMessaging B.V.
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
* Licensed under the Apache License, Version 2.0 with the Commons Clause
* (the "License"); you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package io.mapsmessaging.mavlink.codec;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/ByteBufferUtils.java b/src/main/java/io/mapsmessaging/mavlink/framing/ByteBufferUtils.java
index 48b0915..b9ea22f 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/ByteBufferUtils.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/ByteBufferUtils.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.framing;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/CrcHelper.java b/src/main/java/io/mapsmessaging/mavlink/framing/CrcHelper.java
index eddc483..d3b3e36 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/CrcHelper.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/CrcHelper.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink.framing;
import io.mapsmessaging.mavlink.message.X25Crc;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkDialectRegistry.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkDialectRegistry.java
index 10c7df1..b3539e0 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkDialectRegistry.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkDialectRegistry.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.framing;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameDecoder.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameDecoder.java
index 6132d1e..2bba84c 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameDecoder.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameDecoder.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink.framing;
import io.mapsmessaging.mavlink.message.MavlinkFrame;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java
index 701f984..4ca0880 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.framing;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameHandler.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameHandler.java
index 040f4f6..c22c656 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameHandler.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameHandler.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.framing;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
index ebfc106..91fecbf 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.framing;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java
index f98e0b8..2003f23 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.framing;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV2FrameHandler.java b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV2FrameHandler.java
index 3715745..b9deea0 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV2FrameHandler.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV2FrameHandler.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.framing;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledField.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledField.java
index 2a035da..24b6741 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledField.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledField.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java
index 18e013f..268de60 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkEnumResolver.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkEnumResolver.java
index 1c3f8cb..6c368d9 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkEnumResolver.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkEnumResolver.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrame.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrame.java
index 6e129ee..871ab2c 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrame.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrame.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrameParser.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrameParser.java
index a01113a..eb0b953 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrameParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrameParser.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageDefinition.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageDefinition.java
index 7362e21..7d6f600 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageDefinition.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageDefinition.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
index 7b3db45..bb51cb5 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkVersion.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkVersion.java
index 3876e73..cbde5bb 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkVersion.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkVersion.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/X25Crc.java b/src/main/java/io/mapsmessaging/mavlink/message/X25Crc.java
index 31384e5..a92b2af 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/X25Crc.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/X25Crc.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/AbstractMavlinkFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/AbstractMavlinkFieldCodec.java
index 23d3bfc..c0738ee 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/AbstractMavlinkFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/AbstractMavlinkFieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
index 4ce6507..c32ffb6 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/CharFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/CharFieldCodec.java
index 8e40507..85ec564 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/CharFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/CharFieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/DoubleFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/DoubleFieldCodec.java
index 1a84568..3c617ed 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/DoubleFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/DoubleFieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/FloatFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/FloatFieldCodec.java
index 4b8242e..58af855 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/FloatFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/FloatFieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int16FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int16FieldCodec.java
index 921de5d..8d4e9d2 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int16FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int16FieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int32FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int32FieldCodec.java
index deeea11..afdf39a 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int32FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int32FieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int64FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int64FieldCodec.java
index 7488a15..59e91df 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int64FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int64FieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int8FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int8FieldCodec.java
index c6da4f4..e7e4e50 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int8FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int8FieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumDefinition.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumDefinition.java
index 8ca3f80..bdf3c29 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumDefinition.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumDefinition.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumEntry.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumEntry.java
index 328f125..c7ee10d 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumEntry.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumEntry.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldCodecFactory.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldCodecFactory.java
index 49e3f09..4e8cfe5 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldCodecFactory.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldCodecFactory.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldDefinition.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldDefinition.java
index 56ebde3..986fac3 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldDefinition.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldDefinition.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java
index b7d5c18..5d1c02f 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt16FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt16FieldCodec.java
index 845f357..a8193ff 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt16FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt16FieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt32FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt32FieldCodec.java
index 64c2bdf..e8d0662 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt32FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt32FieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt64FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt64FieldCodec.java
index 93dccf7..000206f 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt64FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt64FieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt8FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt8FieldCodec.java
index 7660301..90dae5e 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt8FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt8FieldCodec.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.message.fields;
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java b/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
index a35d47b..98f5af0 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.parser;
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectDefinition.java b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectDefinition.java
index f4b7662..19c19c1 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectDefinition.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectDefinition.java
@@ -1,7 +1,7 @@
/*
*
* Copyright [ 2020 - 2024 ] Matthew Buckton
- * Copyright [ 2024 - 2025 ] MapsMessaging B.V.
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
* Licensed under the Apache License, Version 2.0 with the Commons Clause
* (the "License"); you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package io.mapsmessaging.mavlink.parser;
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectLoader.java b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectLoader.java
index 6e87494..5630270 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectLoader.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectLoader.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.parser;
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java
index 219eb10..c213134 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink.parser;
import io.mapsmessaging.mavlink.message.MavlinkMessageDefinition;
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkIncludeResolver.java b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkIncludeResolver.java
index 3999eed..1bc0acf 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkIncludeResolver.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkIncludeResolver.java
@@ -1,18 +1,20 @@
/*
*
- * Copyright [ 2020 - 2026 ] [Matthew Buckton]
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package io.mapsmessaging.mavlink.parser;
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
index 27813bd..519b3b7 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
@@ -1,7 +1,7 @@
/*
*
* Copyright [ 2020 - 2024 ] Matthew Buckton
- * Copyright [ 2024 - 2025 ] MapsMessaging B.V.
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
* Licensed under the Apache License, Version 2.0 with the Commons Clause
* (the "License"); you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package io.mapsmessaging.mavlink.parser;
diff --git a/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java b/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java
index 8f73a5d..3379311 100644
--- a/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java
+++ b/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink.schema;
import com.google.gson.JsonArray;
diff --git a/src/test/java/io/mapsmessaging/mavlink/BaseRoudTripTest.java b/src/test/java/io/mapsmessaging/mavlink/BaseRoudTripTest.java
index 6eef298..b544bed 100644
--- a/src/test/java/io/mapsmessaging/mavlink/BaseRoudTripTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/BaseRoudTripTest.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
diff --git a/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java b/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
index bbb8948..9943007 100644
--- a/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import org.junit.jupiter.api.Assertions;
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
index d420c47..9963b40 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
index bca06dc..a3cfad9 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkRoundTripAllMessagesTest.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkRoundTripAllMessagesTest.java
index 090b204..9fc0f20 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkRoundTripAllMessagesTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkRoundTripAllMessagesTest.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkTestSupport.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkTestSupport.java
index 310237f..6093702 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkTestSupport.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkTestSupport.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkCharArrays.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkCharArrays.java
index aedfdf3..c0b1d74 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkCharArrays.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkCharArrays.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkConcurrency.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkConcurrency.java
index 392f6a7..9eb2f99 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkConcurrency.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkConcurrency.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkExtensions.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkExtensions.java
index ea315e5..962d0ff 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkExtensions.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkExtensions.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkNumericArrays.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkNumericArrays.java
index 8a0eede..35f76bc 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkNumericArrays.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkNumericArrays.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRegistryInvariants.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRegistryInvariants.java
index 717ff7c..a7ce7a0 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRegistryInvariants.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRegistryInvariants.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRobustness.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRobustness.java
index 5f7dc27..0407489 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRobustness.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRobustness.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkXmlParserIncludes.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkXmlParserIncludes.java
index d27d1cd..90b3104 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkXmlParserIncludes.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkXmlParserIncludes.java
@@ -1,3 +1,22 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package io.mapsmessaging.mavlink;
import io.mapsmessaging.mavlink.parser.*;
diff --git a/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java b/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
index de4254f..317fa73 100644
--- a/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/X25CrcTest.java
@@ -1,7 +1,7 @@
/*
*
* Copyright [ 2020 - 2024 ] Matthew Buckton
- * Copyright [ 2024 - 2025 ] MapsMessaging B.V.
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
*
* Licensed under the Apache License, Version 2.0 with the Commons Clause
* (the "License"); you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package io.mapsmessaging.mavlink;
From f6b117d66abfc0d77a8c84ae2f76b7362ae65faf Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Tue, 6 Jan 2026 15:39:59 +1100
Subject: [PATCH 14/34] fix(parsing): truncated packets
MavLink allows truncated packets IF the framing is correct
---
.../mavlink/codec/MavlinkPayloadParser.java | 70 +++--
.../mapsmessaging/mavlink/HeartbeatTest.java | 264 ++++++++++++++++++
.../mavlink/TestMavlinkRobustness.java | 22 --
3 files changed, 310 insertions(+), 46 deletions(-)
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java
index 40c97e2..74c7fd1 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java
@@ -56,51 +56,44 @@ public Map parsePayload(int messageId, byte[] payload) throws IO
ByteBuffer buffer = ByteBuffer.wrap(payload);
buffer.order(ByteOrder.LITTLE_ENDIAN);
+ boolean truncated = false;
+
for (MavlinkCompiledField compiledField : compiledMessage.getCompiledFields()) {
MavlinkFieldDefinition fieldDefinition = compiledField.getFieldDefinition();
AbstractMavlinkFieldCodec fieldCodec = compiledField.getFieldCodec();
String fieldName = fieldDefinition.getName();
-
int fieldSize = compiledField.getSizeInBytes();
- // Base fields MUST be present
if (!fieldDefinition.isExtension()) {
- if (buffer.remaining() < fieldSize) {
- throw new IOException(
- "Payload too short for base field '" + fieldName +
- "' in message " + compiledMessage.getName() +
- " remaining=" + buffer.remaining() +
- " required=" + fieldSize
- );
+ if (truncated || buffer.remaining() < fieldSize) {
+ truncated = true;
+ result.put(fieldName, zeroValue(fieldDefinition));
+ continue;
}
} else {
- // Extension fields are optional: if not enough bytes left, treat as absent
- if (buffer.remaining() < fieldSize) {
- // you can either omit it or explicitly put null; your choice
+ // Extension fields: absent if not enough bytes (or if we've already truncated)
+ if (truncated || buffer.remaining() < fieldSize) {
result.put(fieldName, null);
continue;
}
}
+ // Normal decode path (enough bytes available)
if (!fieldDefinition.isArray()) {
- Object value = fieldCodec.decode(buffer);
- result.put(fieldName, value);
+ result.put(fieldName, fieldCodec.decode(buffer));
continue;
}
int len = fieldDefinition.getArrayLength();
-
if (fieldDefinition.getWireType() == MavlinkWireType.CHAR) {
- // MAVLink strings: fixed-size, null-terminated, null-padded
- byte[] bytes;
- String v = (String) fieldCodec.decode(buffer); // codec returns Byte
- bytes = v.getBytes(StandardCharsets.UTF_8);
- int end = bytes.length;
- while (end > 0 && bytes[end - 1] == 0) {
- end--;
+ // read fixed-size char[N] bytes; codec may or may not do this correctly
+ byte[] raw = new byte[len];
+ buffer.get(raw);
+ int end = 0;
+ while (end < raw.length && raw[end] != 0) {
+ end++;
}
- String value = new String(bytes, 0, end, StandardCharsets.UTF_8);
- result.put(fieldName, value);
+ result.put(fieldName, new String(raw, 0, end, StandardCharsets.UTF_8));
} else {
List
*
*
Each instance is bound to a single dialect via its
- * {@link MavlinkMessageRegistry}.
+ * {@link MessageRegistry}.
*/
public final class MavlinkCodec {
@@ -52,10 +52,10 @@ public final class MavlinkCodec {
* Compiled message registry for the dialect.
*/
@Getter
- private final MavlinkMessageRegistry registry;
+ private final MessageRegistry registry;
- private final MavlinkPayloadPacker payloadPacker;
- private final MavlinkPayloadParser payloadParser;
+ private final PayloadPacker payloadPacker;
+ private final PayloadParser payloadParser;
/**
* Creates a payload codec for a specific MAVLink dialect.
@@ -68,9 +68,9 @@ public final class MavlinkCodec {
*/
public MavlinkCodec(
String name,
- MavlinkMessageRegistry registry,
- MavlinkPayloadPacker payloadPacker,
- MavlinkPayloadParser payloadParser
+ MessageRegistry registry,
+ PayloadPacker payloadPacker,
+ PayloadParser payloadParser
) {
this.name = Objects.requireNonNull(name, "name");
this.registry = Objects.requireNonNull(registry, "registry");
diff --git a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
index 29198d6..f511695 100644
--- a/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/MavlinkFrameCodec.java
@@ -19,13 +19,12 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.framing.MavlinkDialectRegistry;
-import io.mapsmessaging.mavlink.framing.MavlinkFrameFramer;
-import io.mapsmessaging.mavlink.framing.MavlinkFramePacker;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.MavlinkVersion;
+import io.mapsmessaging.mavlink.framing.*;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.Frame;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.Version;
+import io.mapsmessaging.mavlink.signing.NoSigningKeyProvider;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -38,8 +37,8 @@
*
*
This codec combines:
*
- *
Frame decoding from a streaming network buffer via {@link MavlinkFrameFramer}
- *
Frame packing (including CRC) via {@link MavlinkFramePacker}
+ *
Frame decoding from a streaming network buffer via {@link FrameFramer}
+ *
Frame packing (including CRC) via {@link FramePacker}
*
Payload field encoding/decoding via {@link MavlinkCodec}
*
*
@@ -47,29 +46,33 @@
*
*
{@link #tryUnpackFrame(ByteBuffer)} consumes a network-owned {@link ByteBuffer} in write-mode and
* may {@code flip}/{@code compact} internally.
- *
{@link #packFrame(ByteBuffer, MavlinkFrame)} writes a complete MAVLink frame into the provided output
+ *
{@link #packFrame(ByteBuffer, Frame)} writes a complete MAVLink frame into the provided output
* buffer at its current position.
*
*/
public final class MavlinkFrameCodec {
private final MavlinkCodec payloadCodec;
- private final MavlinkFrameFramer framer;
- private final MavlinkFramePacker packer;
+ private final FrameFramer framer;
+ private final FramePacker packer;
+
+ public MavlinkFrameCodec(MavlinkCodec payloadCodec) {
+ this(payloadCodec, new NoSigningKeyProvider());
+ }
/**
* Creates a frame codec for the dialect contained in the provided payload codec.
*
* @param payloadCodec codec providing the dialect name, message registry, and payload encode/decode
* @throws NullPointerException if {@code payloadCodec} is {@code null}
*/
- public MavlinkFrameCodec(MavlinkCodec payloadCodec) {
+ public MavlinkFrameCodec(MavlinkCodec payloadCodec, SigningKeyProvider signingKeyProvider) {
this.payloadCodec = Objects.requireNonNull(payloadCodec, "payloadCodec");
- MavlinkDialectRegistry dialectRegistry = new RegistryAdapter(payloadCodec.getRegistry());
+ DialectRegistry dialectRegistry = new RegistryAdapter(payloadCodec.getRegistry());
- this.framer = new MavlinkFrameFramer(dialectRegistry);
- this.packer = new MavlinkFramePacker(dialectRegistry);
+ this.framer = new FrameFramer(dialectRegistry, signingKeyProvider);
+ this.packer = new FramePacker(dialectRegistry, signingKeyProvider);
}
/**
@@ -86,7 +89,7 @@ public String getDialectName() {
*
* @return message registry
*/
- public MavlinkMessageRegistry getRegistry() {
+ public MessageRegistry getRegistry() {
return payloadCodec.getRegistry();
}
@@ -98,7 +101,7 @@ public MavlinkMessageRegistry getRegistry() {
* @param networkOwnedBuffer network buffer in write-mode (may be flipped/compacted internally)
* @return decoded frame if available and valid
*/
- public Optional tryUnpackFrame(ByteBuffer networkOwnedBuffer) {
+ public Optional tryUnpackFrame(ByteBuffer networkOwnedBuffer) {
return framer.tryDecode(networkOwnedBuffer);
}
@@ -111,12 +114,12 @@ public Optional tryUnpackFrame(ByteBuffer networkOwnedBuffer) {
* @return envelope containing header fields + raw payload bytes if a complete valid frame is available
*/
public Optional tryUnpackHeaderAndPayload(ByteBuffer networkOwnedBuffer) {
- Optional decoded = framer.tryDecode(networkOwnedBuffer);
+ Optional decoded = framer.tryDecode(networkOwnedBuffer);
if (decoded.isEmpty()) {
return Optional.empty();
}
- MavlinkFrame frame = decoded.get();
+ Frame frame = decoded.get();
byte[] payload = Objects.requireNonNull(frame.getPayload(), "frame.payload");
MavlinkFrameEnvelope envelope = new MavlinkFrameEnvelope(
@@ -141,7 +144,7 @@ public Optional tryUnpackHeaderAndPayload(ByteBuffer netwo
* @param out output buffer to write into (at current position)
* @param frame frame to pack
*/
- public void packFrame(ByteBuffer out, MavlinkFrame frame) {
+ public void packFrame(ByteBuffer out, Frame frame) {
packer.pack(out, frame);
}
@@ -153,7 +156,7 @@ public void packFrame(ByteBuffer out, MavlinkFrame frame) {
* @throws IOException if payload decoding fails for the message type
* @throws NullPointerException if {@code frame} or its payload is {@code null}
*/
- public Map parsePayload(MavlinkFrame frame) throws IOException {
+ public Map parsePayload(Frame frame) throws IOException {
Objects.requireNonNull(frame, "frame");
byte[] payload = Objects.requireNonNull(frame.getPayload(), "frame.payload");
@@ -182,7 +185,7 @@ public byte[] encodePayload(int messageId, Map values) throws IO
* @throws IOException if payload encoding fails
* @throws NullPointerException if {@code frame} or {@code values} is {@code null}
*/
- public void encodePayloadIntoFrame(MavlinkFrame frame, int messageId, Map values) throws IOException {
+ public void encodePayloadIntoFrame(Frame frame, int messageId, Map values) throws IOException {
Objects.requireNonNull(frame, "frame");
Objects.requireNonNull(values, "values");
@@ -196,11 +199,11 @@ public void encodePayloadIntoFrame(MavlinkFrame frame, int messageId, MapThe loader provides a built-in {@code "common"} dialect that is loaded eagerly at startup
* (fail-fast). Additional dialects may be loaded at runtime from an {@link InputStream} with a
- * caller-supplied {@link MavlinkIncludeResolver} for resolving {@code } directives.
+ * caller-supplied {@link IncludeResolver} for resolving {@code } directives.
*
*
Dialects are cached by name and can be retrieved via {@link #getDialect(String)} or
* {@link #getDialectOrThrow(String)}.
This method is not public by design. Public callers should either use built-ins via
* {@link #getDialectOrThrow(String)}, or load custom dialects via
- * {@link #loadDialect(String, InputStream, MavlinkIncludeResolver)}.
+ * {@link #loadDialect(String, InputStream, IncludeResolver)}.
*
* @param dialectName dialect name used for caching and lookup
* @param classpathXml classpath resource path for the dialect XML
@@ -137,14 +137,14 @@ protected MavlinkCodec loadDialectFromClasspath(String dialectName, String class
throw new IOException("Unable to load MAVLink dialect resource: " + classpathXml);
}
- MavlinkXmlParser mavlinkXmlParser = new MavlinkXmlParser();
- MavlinkDialectLoader mavlinkDialectLoader = new MavlinkDialectLoader(mavlinkXmlParser);
+ XmlParser mavlinkXmlParser = new XmlParser();
+ DialectLoader dialectLoader = new DialectLoader(mavlinkXmlParser);
- MavlinkIncludeResolver includeResolver =
- new ClasspathMavlinkIncludeResolver(classLoader, "mavlink");
+ IncludeResolver includeResolver =
+ new ClasspathIncludeResolver(classLoader, "mavlink");
- MavlinkDialectDefinition dialectDefinition =
- mavlinkDialectLoader.load(normalizedDialectName, inputStream, includeResolver);
+ DialectDefinition dialectDefinition =
+ dialectLoader.load(normalizedDialectName, inputStream, includeResolver);
return buildCodec(normalizedDialectName, dialectDefinition);
}
@@ -153,7 +153,7 @@ protected MavlinkCodec loadDialectFromClasspath(String dialectName, String class
/**
* Loads a dialect from an arbitrary stream and caches the resulting codec under the dialect name.
*
- *
{@code } directives are resolved using the provided {@link MavlinkIncludeResolver}.
+ *
{@code } directives are resolved using the provided {@link IncludeResolver}.
*
* @param dialectName dialect name used for caching and lookup
* @param inputStream dialect XML stream (not closed by this method)
@@ -163,7 +163,7 @@ protected MavlinkCodec loadDialectFromClasspath(String dialectName, String class
* @throws ParserConfigurationException if the XML parser cannot be configured
* @throws SAXException if the dialect XML is invalid
*/
- public MavlinkCodec loadDialect(String dialectName, InputStream inputStream, MavlinkIncludeResolver includeResolver)
+ public MavlinkCodec loadDialect(String dialectName, InputStream inputStream, IncludeResolver includeResolver)
throws IOException, ParserConfigurationException, SAXException {
String normalizedDialectName = normalizeDialectName(dialectName);
@@ -171,11 +171,11 @@ public MavlinkCodec loadDialect(String dialectName, InputStream inputStream, Mav
Objects.requireNonNull(inputStream, "inputStream");
Objects.requireNonNull(includeResolver, "includeResolver");
- MavlinkXmlParser mavlinkXmlParser = new MavlinkXmlParser();
- MavlinkDialectLoader mavlinkDialectLoader = new MavlinkDialectLoader(mavlinkXmlParser);
+ XmlParser mavlinkXmlParser = new XmlParser();
+ DialectLoader dialectLoader = new DialectLoader(mavlinkXmlParser);
- MavlinkDialectDefinition dialectDefinition =
- mavlinkDialectLoader.load(normalizedDialectName, inputStream, includeResolver);
+ DialectDefinition dialectDefinition =
+ dialectLoader.load(normalizedDialectName, inputStream, includeResolver);
MavlinkCodec codec = buildCodec(normalizedDialectName, dialectDefinition);
dialects.put(normalizedDialectName, codec);
@@ -183,11 +183,11 @@ public MavlinkCodec loadDialect(String dialectName, InputStream inputStream, Mav
return codec;
}
- private MavlinkCodec buildCodec(String dialectName, MavlinkDialectDefinition dialectDefinition) {
- MavlinkMessageRegistry registry = MavlinkMessageRegistry.fromDialectDefinition(dialectDefinition);
+ private MavlinkCodec buildCodec(String dialectName, DialectDefinition dialectDefinition) {
+ MessageRegistry registry = MessageRegistry.fromDialectDefinition(dialectDefinition);
- MavlinkPayloadPacker payloadPacker = new MavlinkPayloadPacker(registry);
- MavlinkPayloadParser payloadParser = new MavlinkPayloadParser(registry);
+ PayloadPacker payloadPacker = new PayloadPacker(registry);
+ PayloadParser payloadParser = new PayloadParser(registry);
return new MavlinkCodec(dialectName, registry, payloadPacker, payloadParser);
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameEncoder.java b/src/main/java/io/mapsmessaging/mavlink/codec/FrameEncoder.java
similarity index 92%
rename from src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameEncoder.java
rename to src/main/java/io/mapsmessaging/mavlink/codec/FrameEncoder.java
index 8969fa5..174dab7 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameEncoder.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/FrameEncoder.java
@@ -19,13 +19,13 @@
package io.mapsmessaging.mavlink.codec;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
import io.mapsmessaging.mavlink.message.X25Crc;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-public class MavlinkFrameEncoder {
+public class FrameEncoder {
private static final byte MAVLINK2_STX = (byte) 0xFD;
private static final int MAVLINK2_HEADER_LENGTH = 10;
@@ -37,7 +37,7 @@ public byte[] encodeV2Frame(
int componentId,
int messageId,
byte[] payload,
- MavlinkCompiledMessage compiledMessage
+ CompiledMessage compiledMessage
) {
int payloadLength = payload.length;
int frameLength = MAVLINK2_HEADER_LENGTH + payloadLength + MAVLINK2_CHECKSUM_LENGTH;
@@ -77,7 +77,7 @@ private void writeHeader(
buffer.put((byte) ((messageId >> 16) & 0xFF));
}
- private short computeCrc(byte[] frameBytesWithoutCrc, MavlinkCompiledMessage compiledMessage) {
+ private short computeCrc(byte[] frameBytesWithoutCrc, CompiledMessage compiledMessage) {
int start = 1;
int lengthForCrc = frameBytesWithoutCrc.length - 1;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameFactory.java b/src/main/java/io/mapsmessaging/mavlink/codec/FrameFactory.java
similarity index 71%
rename from src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameFactory.java
rename to src/main/java/io/mapsmessaging/mavlink/codec/FrameFactory.java
index 9a2bd6a..7db07fa 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkFrameFactory.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/FrameFactory.java
@@ -19,18 +19,18 @@
package io.mapsmessaging.mavlink.codec;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
-import io.mapsmessaging.mavlink.message.MavlinkFrameParser;
+import io.mapsmessaging.mavlink.message.Frame;
+import io.mapsmessaging.mavlink.message.FrameParser;
-public class MavlinkFrameFactory {
+public class FrameFactory {
- private final MavlinkFrameParser frameParser;
+ private final FrameParser frameParser;
- public MavlinkFrameFactory() {
- this.frameParser = new MavlinkFrameParser();
+ public FrameFactory() {
+ this.frameParser = new FrameParser();
}
- public MavlinkFrame parse(byte[] payload) {
+ public Frame parse(byte[] payload) {
return frameParser.parse(payload);
}
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonCodec.java b/src/main/java/io/mapsmessaging/mavlink/codec/JsonCodec.java
similarity index 73%
rename from src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonCodec.java
rename to src/main/java/io/mapsmessaging/mavlink/codec/JsonCodec.java
index 4ad7ea2..cc4ad33 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/JsonCodec.java
@@ -22,36 +22,36 @@
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.Frame;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
-public class MavlinkJsonCodec {
+public class JsonCodec {
private static final Gson GSON = new Gson();
private final String dialectName;
- private final MavlinkPayloadPacker packer;
- private final MavlinkMapConverter mapConverter;
- private final MavlinkJsonValuesExtractor valuesExtractor;
- private final MavlinkFrameEncoder frameEncoder;
+ private final PayloadPacker packer;
+ private final MapConverter mapConverter;
+ private final JsonValuesExtractor valuesExtractor;
+ private final FrameEncoder frameEncoder;
- public MavlinkJsonCodec(String dialectName, MavlinkPayloadPacker packer, MavlinkMapConverter mapConverter) {
+ public JsonCodec(String dialectName, PayloadPacker packer, MapConverter mapConverter) {
this.dialectName = Objects.requireNonNull(dialectName, "dialectName");
this.packer = Objects.requireNonNull(packer, "packer");
this.mapConverter = Objects.requireNonNull(mapConverter, "mapConverter");
- this.valuesExtractor = new MavlinkJsonValuesExtractor();
- this.frameEncoder = new MavlinkFrameEncoder();
+ this.valuesExtractor = new JsonValuesExtractor();
+ this.frameEncoder = new FrameEncoder();
}
- public JsonObject toJson(MavlinkFrame frame) throws IOException {
+ public JsonObject toJson(Frame frame) throws IOException {
Map map = mapConverter.convert(frame);
String json = GSON.toJson(map);
return JsonParser.parseString(json).getAsJsonObject();
@@ -70,8 +70,8 @@ public byte[] fromJson(JsonObject jsonObject) throws IOException {
int componentId = jsonObject.has("componentId") ? jsonObject.get("componentId").getAsInt() : 1;
int sequence = jsonObject.has("sequence") ? jsonObject.get("sequence").getAsInt() : 0;
- MavlinkMessageRegistry registry = packer.getMessageRegistry();
- MavlinkCompiledMessage compiledMessage = registry.getCompiledMessagesById().get(messageId);
+ MessageRegistry registry = packer.getMessageRegistry();
+ CompiledMessage compiledMessage = registry.getCompiledMessagesById().get(messageId);
if (compiledMessage == null) {
throw new IOException("Unknown MAVLink message id: " + messageId + " for dialect " + dialectName);
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonValuesExtractor.java b/src/main/java/io/mapsmessaging/mavlink/codec/JsonValuesExtractor.java
similarity index 89%
rename from src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonValuesExtractor.java
rename to src/main/java/io/mapsmessaging/mavlink/codec/JsonValuesExtractor.java
index ae5f2ab..2944da9 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkJsonValuesExtractor.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/JsonValuesExtractor.java
@@ -23,20 +23,20 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-public class MavlinkJsonValuesExtractor {
+public class JsonValuesExtractor {
- public Map extractValues(JsonObject jsonObject, MavlinkCompiledMessage compiledMessage) {
+ public Map extractValues(JsonObject jsonObject, CompiledMessage compiledMessage) {
Map values = new HashMap<>();
- for (MavlinkCompiledField compiledField : compiledMessage.getCompiledFields()) {
+ for (CompiledField compiledField : compiledMessage.getCompiledFields()) {
String fieldName = compiledField.getFieldDefinition().getName();
if (!jsonObject.has(fieldName)) {
continue;
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkMapConverter.java b/src/main/java/io/mapsmessaging/mavlink/codec/MapConverter.java
similarity index 78%
rename from src/main/java/io/mapsmessaging/mavlink/codec/MavlinkMapConverter.java
rename to src/main/java/io/mapsmessaging/mavlink/codec/MapConverter.java
index a8ce233..5dd6b52 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkMapConverter.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/MapConverter.java
@@ -19,21 +19,21 @@
package io.mapsmessaging.mavlink.codec;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
+import io.mapsmessaging.mavlink.message.Frame;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
-public class MavlinkMapConverter {
+public class MapConverter {
- private final MavlinkPayloadParser payloadParser;
+ private final PayloadParser payloadParser;
- public MavlinkMapConverter(MavlinkPayloadParser payloadParser) {
+ public MapConverter(PayloadParser payloadParser) {
this.payloadParser = Objects.requireNonNull(payloadParser, "payloadParser");
}
- public Map convert(MavlinkFrame frame) throws IOException {
+ public Map convert(Frame frame) throws IOException {
return payloadParser.parsePayload(frame.getMessageId(), frame.getPayload());
}
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadPacker.java b/src/main/java/io/mapsmessaging/mavlink/codec/PayloadPacker.java
similarity index 69%
rename from src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadPacker.java
rename to src/main/java/io/mapsmessaging/mavlink/codec/PayloadPacker.java
index 349f7c2..5106de4 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadPacker.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/PayloadPacker.java
@@ -19,13 +19,13 @@
package io.mapsmessaging.mavlink.codec;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkEnumResolver;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.EnumResolver;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
import io.mapsmessaging.mavlink.message.fields.AbstractMavlinkFieldCodec;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkWireType;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.WireType;
import lombok.Getter;
import java.io.IOException;
@@ -36,18 +36,18 @@
import java.util.List;
import java.util.Map;
-public class MavlinkPayloadPacker {
+public class PayloadPacker {
@Getter
- private final MavlinkMessageRegistry messageRegistry;
+ private final MessageRegistry messageRegistry;
- public MavlinkPayloadPacker(MavlinkMessageRegistry messageRegistry) {
+ public PayloadPacker(MessageRegistry messageRegistry) {
this.messageRegistry = messageRegistry;
}
public byte[] packPayload(int messageId, Map values) throws IOException {
- MavlinkCompiledMessage compiledMessage = getCompiledMessage(messageId);
- List compiledFields = compiledMessage.getCompiledFields();
+ CompiledMessage compiledMessage = getCompiledMessage(messageId);
+ List compiledFields = compiledMessage.getCompiledFields();
int lastExtensionIndex = findLastIncludedExtensionIndex(compiledFields, values);
int payloadSize = computeTotalPotentialPayloadSize(compiledFields);
@@ -66,18 +66,18 @@ public byte[] packPayload(int messageId, Map values) throws IOEx
return out;
}
- private MavlinkCompiledMessage getCompiledMessage(int messageId) throws IOException {
- MavlinkCompiledMessage compiledMessage = messageRegistry.getCompiledMessagesById().get(messageId);
+ private CompiledMessage getCompiledMessage(int messageId) throws IOException {
+ CompiledMessage compiledMessage = messageRegistry.getCompiledMessagesById().get(messageId);
if (compiledMessage == null) {
throw new IOException("Unknown MAVLink message id: " + messageId);
}
return compiledMessage;
}
- private int findLastIncludedExtensionIndex(List compiledFields, Map values) {
+ private int findLastIncludedExtensionIndex(List compiledFields, Map values) {
int lastExtensionIndex = -1;
for (int i = 0; i < compiledFields.size(); i++) {
- MavlinkFieldDefinition field = compiledFields.get(i).getFieldDefinition();
+ FieldDefinition field = compiledFields.get(i).getFieldDefinition();
if (!field.isExtension()) {
continue;
}
@@ -89,11 +89,11 @@ private int findLastIncludedExtensionIndex(List compiledFi
return lastExtensionIndex;
}
- private int computePayloadSize(List compiledFields, int lastExtensionIndex) {
+ private int computePayloadSize(List compiledFields, int lastExtensionIndex) {
int size = 0;
for (int i = 0; i < compiledFields.size(); i++) {
- MavlinkCompiledField compiledField = compiledFields.get(i);
- MavlinkFieldDefinition field = compiledField.getFieldDefinition();
+ CompiledField compiledField = compiledFields.get(i);
+ FieldDefinition field = compiledField.getFieldDefinition();
if (!field.isExtension()) {
size += compiledField.getSizeInBytes();
@@ -110,9 +110,9 @@ private int computePayloadSize(List compiledFields, int la
return size;
}
- private int computeTotalPotentialPayloadSize(List compiledFields) {
+ private int computeTotalPotentialPayloadSize(List compiledFields) {
int size = 0;
- for (MavlinkCompiledField compiledField : compiledFields) {
+ for (CompiledField compiledField : compiledFields) {
size += compiledField.getSizeInBytes();
}
return size;
@@ -125,14 +125,14 @@ private ByteBuffer allocate(int payloadSize) {
}
private void encodePayload(
- List compiledFields,
+ List compiledFields,
int lastExtensionIndex,
Map values,
ByteBuffer buffer) throws IOException {
for (int i = 0; i < compiledFields.size(); i++) {
- MavlinkCompiledField compiledField = compiledFields.get(i);
- MavlinkFieldDefinition field = compiledField.getFieldDefinition();
+ CompiledField compiledField = compiledFields.get(i);
+ FieldDefinition field = compiledField.getFieldDefinition();
if (field.isExtension() && i > lastExtensionIndex) {
break;
@@ -145,7 +145,7 @@ private void encodePayload(
continue;
}
- value = MavlinkEnumResolver.resolveEnumValue(messageRegistry, field, value);
+ value = EnumResolver.resolveEnumValue(messageRegistry, field, value);
if (!field.isArray()) {
encodeScalar(compiledField, buffer, value);
@@ -157,7 +157,7 @@ private void encodePayload(
}
}
- private void encodeScalar(MavlinkCompiledField compiledField, ByteBuffer buffer, Object value) throws IOException {
+ private void encodeScalar(CompiledField compiledField, ByteBuffer buffer, Object value) throws IOException {
try {
compiledField.getFieldCodec().encode(buffer, value);
} catch (Exception e) {
@@ -167,10 +167,10 @@ private void encodeScalar(MavlinkCompiledField compiledField, ByteBuffer buffer,
}
}
- private void encodeArray(MavlinkCompiledField compiledField, ByteBuffer buffer, Object value) throws IOException {
- MavlinkFieldDefinition field = compiledField.getFieldDefinition();
+ private void encodeArray(CompiledField compiledField, ByteBuffer buffer, Object value) throws IOException {
+ FieldDefinition field = compiledField.getFieldDefinition();
- if (field.getWireType() == MavlinkWireType.CHAR) {
+ if (field.getWireType() == WireType.CHAR) {
encodeCharArray(compiledField, buffer, value);
return;
}
@@ -179,8 +179,8 @@ private void encodeArray(MavlinkCompiledField compiledField, ByteBuffer buffer,
encodeTypedArray(compiledField, buffer, elements);
}
- private void encodeCharArray(MavlinkCompiledField compiledField, ByteBuffer buffer, Object value) throws IOException {
- MavlinkFieldDefinition field = compiledField.getFieldDefinition();
+ private void encodeCharArray(CompiledField compiledField, ByteBuffer buffer, Object value) throws IOException {
+ FieldDefinition field = compiledField.getFieldDefinition();
int len = field.getArrayLength();
byte[] src;
@@ -198,8 +198,8 @@ private void encodeCharArray(MavlinkCompiledField compiledField, ByteBuffer buff
zeroBytes(buffer, len - copyLen);
}
- private void encodeTypedArray(MavlinkCompiledField compiledField, ByteBuffer buffer, List> elements) throws IOException {
- MavlinkFieldDefinition field = compiledField.getFieldDefinition();
+ private void encodeTypedArray(CompiledField compiledField, ByteBuffer buffer, List> elements) throws IOException {
+ FieldDefinition field = compiledField.getFieldDefinition();
AbstractMavlinkFieldCodec codec = compiledField.getFieldCodec();
int len = field.getArrayLength();
@@ -236,7 +236,7 @@ private List> toElements(Object value, String fieldName) throws IOException {
(value == null ? "null" : value.getClass().getName()));
}
- private void zeroFill(MavlinkCompiledField compiledField, ByteBuffer buffer) {
+ private void zeroFill(CompiledField compiledField, ByteBuffer buffer) {
zeroBytes(buffer, compiledField.getSizeInBytes());
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java b/src/main/java/io/mapsmessaging/mavlink/codec/PayloadParser.java
similarity index 80%
rename from src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java
rename to src/main/java/io/mapsmessaging/mavlink/codec/PayloadParser.java
index 74c7fd1..48457ce 100644
--- a/src/main/java/io/mapsmessaging/mavlink/codec/MavlinkPayloadParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/codec/PayloadParser.java
@@ -20,12 +20,12 @@
package io.mapsmessaging.mavlink.codec;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
import io.mapsmessaging.mavlink.message.fields.AbstractMavlinkFieldCodec;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkWireType;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.WireType;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -36,16 +36,16 @@
import java.util.List;
import java.util.Map;
-public class MavlinkPayloadParser {
+public class PayloadParser {
- private final MavlinkMessageRegistry messageRegistry;
+ private final MessageRegistry messageRegistry;
- public MavlinkPayloadParser(MavlinkMessageRegistry messageRegistry) {
+ public PayloadParser(MessageRegistry messageRegistry) {
this.messageRegistry = messageRegistry;
}
public Map parsePayload(int messageId, byte[] payload) throws IOException {
- MavlinkCompiledMessage compiledMessage =
+ CompiledMessage compiledMessage =
messageRegistry.getCompiledMessagesById().get(messageId);
if (compiledMessage == null) {
throw new IllegalArgumentException("Unknown MAVLink message id: " + messageId);
@@ -58,8 +58,8 @@ public Map parsePayload(int messageId, byte[] payload) throws IO
boolean truncated = false;
- for (MavlinkCompiledField compiledField : compiledMessage.getCompiledFields()) {
- MavlinkFieldDefinition fieldDefinition = compiledField.getFieldDefinition();
+ for (CompiledField compiledField : compiledMessage.getCompiledFields()) {
+ FieldDefinition fieldDefinition = compiledField.getFieldDefinition();
AbstractMavlinkFieldCodec fieldCodec = compiledField.getFieldCodec();
String fieldName = fieldDefinition.getName();
int fieldSize = compiledField.getSizeInBytes();
@@ -85,7 +85,7 @@ public Map parsePayload(int messageId, byte[] payload) throws IO
}
int len = fieldDefinition.getArrayLength();
- if (fieldDefinition.getWireType() == MavlinkWireType.CHAR) {
+ if (fieldDefinition.getWireType() == WireType.CHAR) {
// read fixed-size char[N] bytes; codec may or may not do this correctly
byte[] raw = new byte[len];
buffer.get(raw);
@@ -106,7 +106,7 @@ public Map parsePayload(int messageId, byte[] payload) throws IO
return result;
}
- private Object zeroValue(MavlinkFieldDefinition fieldDefinition) {
+ private Object zeroValue(FieldDefinition fieldDefinition) {
if (!fieldDefinition.isArray()) {
// Scalars: 0 / 0.0 / false, etc.
return switch (fieldDefinition.getWireType()) {
@@ -118,7 +118,7 @@ private Object zeroValue(MavlinkFieldDefinition fieldDefinition) {
int len = fieldDefinition.getArrayLength();
- if (fieldDefinition.getWireType() == MavlinkWireType.CHAR) {
+ if (fieldDefinition.getWireType() == WireType.CHAR) {
return "";
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkDialectRegistry.java b/src/main/java/io/mapsmessaging/mavlink/framing/DialectRegistry.java
similarity index 78%
rename from src/main/java/io/mapsmessaging/mavlink/framing/MavlinkDialectRegistry.java
rename to src/main/java/io/mapsmessaging/mavlink/framing/DialectRegistry.java
index b3539e0..199e5a7 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkDialectRegistry.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/DialectRegistry.java
@@ -19,11 +19,11 @@
package io.mapsmessaging.mavlink.framing;
-import io.mapsmessaging.mavlink.message.MavlinkVersion;
+import io.mapsmessaging.mavlink.message.Version;
-public interface MavlinkDialectRegistry {
+public interface DialectRegistry {
- int crcExtra(MavlinkVersion version, int messageId);
+ int crcExtra(Version version, int messageId);
- int minimumPayloadLength(MavlinkVersion version, int messageId);
+ int minimumPayloadLength(Version version, int messageId);
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameDecoder.java b/src/main/java/io/mapsmessaging/mavlink/framing/FrameDecoder.java
similarity index 84%
rename from src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameDecoder.java
rename to src/main/java/io/mapsmessaging/mavlink/framing/FrameDecoder.java
index 2bba84c..29ff010 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameDecoder.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/FrameDecoder.java
@@ -19,11 +19,11 @@
package io.mapsmessaging.mavlink.framing;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
+import io.mapsmessaging.mavlink.message.Frame;
import java.nio.ByteBuffer;
import java.util.Optional;
-public interface MavlinkFrameDecoder {
- Optional decode(ByteBuffer candidateFrame);
+public interface FrameDecoder {
+ Optional decode(ByteBuffer candidateFrame);
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java b/src/main/java/io/mapsmessaging/mavlink/framing/FrameFramer.java
similarity index 83%
rename from src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java
rename to src/main/java/io/mapsmessaging/mavlink/framing/FrameFramer.java
index 4ca0880..baf80bf 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameFramer.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/FrameFramer.java
@@ -19,7 +19,7 @@
package io.mapsmessaging.mavlink.framing;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
+import io.mapsmessaging.mavlink.message.Frame;
import java.nio.ByteBuffer;
import java.util.Optional;
@@ -32,21 +32,21 @@
* - This method flips to read-mode, consumes at most one valid frame, then compacts.
* - Leftover (partial) bytes are moved to index 0 by compact().
*/
-public final class MavlinkFrameFramer {
+public final class FrameFramer {
private static final int MAVLINK_V1_STX = 0xFE;
private static final int MAVLINK_V2_STX = 0xFD;
private static final int MAVLINK_MAX_PAYLOAD_LENGTH = 255;
- private final MavlinkFrameHandler mavlinkV1FrameHandler;
- private final MavlinkFrameHandler mavlinkV2FrameHandler;
+ private final FrameHandler mavlinkV1FrameHandler;
+ private final FrameHandler mavlinkV2FrameHandler;
- public MavlinkFrameFramer(MavlinkDialectRegistry dialectRegistry) {
- this.mavlinkV1FrameHandler = new MavlinkV1FrameHandler(dialectRegistry);
- this.mavlinkV2FrameHandler = new MavlinkV2FrameHandler(dialectRegistry);
+ public FrameFramer(DialectRegistry dialectRegistry, SigningKeyProvider signingKeyProvider) {
+ this.mavlinkV1FrameHandler = new V1FrameHandler(dialectRegistry);
+ this.mavlinkV2FrameHandler = new V2FrameHandler(dialectRegistry, signingKeyProvider);
}
- public Optional tryDecode(ByteBuffer networkOwnedBuffer) {
+ public Optional tryDecode(ByteBuffer networkOwnedBuffer) {
try {
if (!networkOwnedBuffer.hasRemaining()) {
return Optional.empty();
@@ -58,7 +58,7 @@ public Optional tryDecode(ByteBuffer networkOwnedBuffer) {
while (scanIndex < bufferLimit) {
int startByte = networkOwnedBuffer.get(scanIndex) & 0xFF;
- MavlinkFrameHandler handler = null;
+ FrameHandler handler = null;
if (startByte == MAVLINK_V1_STX) {
handler = mavlinkV1FrameHandler;
} else if (startByte == MAVLINK_V2_STX) {
@@ -95,7 +95,7 @@ public Optional tryDecode(ByteBuffer networkOwnedBuffer) {
candidateFrame.position(scanIndex);
candidateFrame.limit(scanIndex + totalFrameLength);
- Optional decodedFrame = handler.tryDecode(candidateFrame);
+ Optional decodedFrame = handler.tryDecode(candidateFrame);
if (decodedFrame.isPresent()) {
networkOwnedBuffer.position(scanIndex + totalFrameLength);
return decodedFrame;
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameHandler.java b/src/main/java/io/mapsmessaging/mavlink/framing/FrameHandler.java
similarity index 86%
rename from src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameHandler.java
rename to src/main/java/io/mapsmessaging/mavlink/framing/FrameHandler.java
index c22c656..9e8a8f3 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFrameHandler.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/FrameHandler.java
@@ -19,12 +19,12 @@
package io.mapsmessaging.mavlink.framing;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
+import io.mapsmessaging.mavlink.message.Frame;
import java.nio.ByteBuffer;
import java.util.Optional;
-public interface MavlinkFrameHandler {
+public interface FrameHandler {
int minimumBytesRequiredForHeader();
@@ -32,5 +32,5 @@ public interface MavlinkFrameHandler {
int computeTotalFrameLength(ByteBuffer buffer, int frameStartIndex, int payloadLength);
- Optional tryDecode(ByteBuffer candidateFrame);
+ Optional tryDecode(ByteBuffer candidateFrame);
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java b/src/main/java/io/mapsmessaging/mavlink/framing/FramePacker.java
similarity index 77%
rename from src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
rename to src/main/java/io/mapsmessaging/mavlink/framing/FramePacker.java
index 91fecbf..3dcb0de 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkFramePacker.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/FramePacker.java
@@ -19,12 +19,12 @@
package io.mapsmessaging.mavlink.framing;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
-import io.mapsmessaging.mavlink.message.MavlinkVersion;
+import io.mapsmessaging.mavlink.message.Frame;
+import io.mapsmessaging.mavlink.message.Version;
import java.nio.ByteBuffer;
-public final class MavlinkFramePacker {
+public final class FramePacker {
private static final int MAVLINK_V1_STX = 0xFE;
private static final int MAVLINK_V2_STX = 0xFD;
@@ -39,17 +39,20 @@ public final class MavlinkFramePacker {
private static final int V2_SIGNATURE_LENGTH = 13;
private static final int V2_INCOMPAT_FLAG_SIGNED = 0x01;
- private final MavlinkDialectRegistry dialectRegistry;
+ private final DialectRegistry dialectRegistry;
+ private final SigningKeyProvider signingKeyProvider;
- public MavlinkFramePacker(MavlinkDialectRegistry dialectRegistry) {
+
+ public FramePacker(DialectRegistry dialectRegistry, SigningKeyProvider signingKeyProvider) {
this.dialectRegistry = dialectRegistry;
+ this.signingKeyProvider = signingKeyProvider;
}
/**
* Packs the supplied MAVLink frame into the provided buffer at the current position.
* The buffer must be in write-mode and have sufficient remaining space.
*/
- public void pack(ByteBuffer out, MavlinkFrame frame) {
+ public void pack(ByteBuffer out, Frame frame) {
if (out == null) {
throw new IllegalArgumentException("out must not be null");
}
@@ -78,7 +81,7 @@ public void pack(ByteBuffer out, MavlinkFrame frame) {
}
}
- private void packV1(ByteBuffer out, MavlinkFrame frame) {
+ private void packV1(ByteBuffer out, Frame frame) {
int payloadLength = frame.getPayloadLength();
byte[] payload = frame.getPayload() == null ? new byte[0] : frame.getPayload();
@@ -100,7 +103,7 @@ private void packV1(ByteBuffer out, MavlinkFrame frame) {
out.put(payload, 0, payloadLength);
- int crcExtra = dialectRegistry.crcExtra(MavlinkVersion.V1, frame.getMessageId());
+ int crcExtra = dialectRegistry.crcExtra(Version.V1, frame.getMessageId());
int checksum = CrcHelper.computeChecksumFromWritten(out, startPosition + 1, MAVLINK_V1_HEADER_LENGTH + payloadLength, crcExtra);
out.put((byte) (checksum & 0xFF));
@@ -113,7 +116,7 @@ private void packV1(ByteBuffer out, MavlinkFrame frame) {
frame.setSignature(null);
}
- private void packV2(ByteBuffer out, MavlinkFrame frame) {
+ private void packV2(ByteBuffer out, Frame frame) {
int payloadLength = frame.getPayloadLength();
byte[] payload = frame.getPayload() == null ? new byte[0] : frame.getPayload();
@@ -122,11 +125,6 @@ private void packV2(ByteBuffer out, MavlinkFrame frame) {
}
boolean signed = frame.isSigned();
- byte[] signature = frame.getSignature();
-
- if (signed && (signature == null || signature.length != V2_SIGNATURE_LENGTH)) {
- throw new IllegalArgumentException("Signed v2 frame must have signature[13]");
- }
int required = 1 + MAVLINK_V2_HEADER_LENGTH + payloadLength + CRC_LENGTH + (signed ? V2_SIGNATURE_LENGTH : 0);
requireRemaining(out, required);
@@ -154,20 +152,46 @@ private void packV2(ByteBuffer out, MavlinkFrame frame) {
out.put(payload, 0, payloadLength);
- int crcExtra = dialectRegistry.crcExtra(MavlinkVersion.V2, frame.getMessageId());
- int checksum = CrcHelper.computeChecksumFromWritten(out, startPosition + 1, (MAVLINK_V2_HEADER_LENGTH-1) + payloadLength, crcExtra);
+ int crcExtra = dialectRegistry.crcExtra(Version.V2, frame.getMessageId());
+ int checksum = CrcHelper.computeChecksumFromWritten(
+ out,
+ startPosition + 1,
+ (MAVLINK_V2_HEADER_LENGTH - 1) + payloadLength,
+ crcExtra
+ );
out.put((byte) (checksum & 0xFF));
out.put((byte) ((checksum >>> 8) & 0xFF));
+ byte[] signature = null;
if (signed) {
+ int linkId = 0;
+ long timestampMicros = System.currentTimeMillis() * 1000L;
+
+ byte[] signingKey = signingKeyProvider.getSigningKey(frame.getSystemId(), frame.getComponentId(), linkId);
+ if (signingKey == null || signingKey.length != 32) {
+ throw new IllegalArgumentException("Signed v2 frame requires 32-byte signing key");
+ }
+
+ int crcStartIndex = out.position() - CRC_LENGTH;
+
+ signature = V2SignatureGenerator.buildSignature(
+ out,
+ startPosition,
+ crcStartIndex,
+ linkId,
+ timestampMicros,
+ signingKey
+ );
+
out.put(signature, 0, V2_SIGNATURE_LENGTH);
}
frame.setChecksum(checksum);
frame.setIncompatibilityFlags(incompatibilityFlags);
+ frame.setSignature(signature);
+ frame.setValidated(signed);
}
-
private static void requireRemaining(ByteBuffer out, int required) {
if (out.remaining() < required) {
throw new IllegalArgumentException("Insufficient space in output buffer. required=" + required + " remaining=" + out.remaining());
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/SigningKeyProvider.java b/src/main/java/io/mapsmessaging/mavlink/framing/SigningKeyProvider.java
new file mode 100644
index 0000000..3accbd3
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/SigningKeyProvider.java
@@ -0,0 +1,25 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.mapsmessaging.mavlink.framing;
+
+public interface SigningKeyProvider {
+ boolean canValidate();
+ byte[] getSigningKey(int systemId, int componentId, int linkId);
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java b/src/main/java/io/mapsmessaging/mavlink/framing/V1FrameHandler.java
similarity index 85%
rename from src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java
rename to src/main/java/io/mapsmessaging/mavlink/framing/V1FrameHandler.java
index 2003f23..d2436bc 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV1FrameHandler.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/V1FrameHandler.java
@@ -19,23 +19,23 @@
package io.mapsmessaging.mavlink.framing;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
-import io.mapsmessaging.mavlink.message.MavlinkVersion;
+import io.mapsmessaging.mavlink.message.Frame;
+import io.mapsmessaging.mavlink.message.Version;
import io.mapsmessaging.mavlink.message.X25Crc;
import java.nio.ByteBuffer;
import java.util.Optional;
-public final class MavlinkV1FrameHandler implements MavlinkFrameHandler {
+public final class V1FrameHandler implements FrameHandler {
private static final int STX = 0xFE;
private static final int HEADER_LENGTH = 6; // LEN, SEQ, SYSID, COMPID, MSGID
private static final int CRC_LENGTH = 2;
- private final MavlinkDialectRegistry dialectRegistry;
+ private final DialectRegistry dialectRegistry;
- public MavlinkV1FrameHandler(MavlinkDialectRegistry dialectRegistry) {
+ public V1FrameHandler(DialectRegistry dialectRegistry) {
this.dialectRegistry = dialectRegistry;
}
@@ -55,7 +55,7 @@ public int computeTotalFrameLength(ByteBuffer buffer, int frameStartIndex, int p
}
@Override
- public Optional tryDecode(ByteBuffer candidateFrame) {
+ public Optional tryDecode(ByteBuffer candidateFrame) {
int frameStartIndex = candidateFrame.position();
int stx = candidateFrame.get(frameStartIndex) & 0xFF;
@@ -69,7 +69,7 @@ public Optional tryDecode(ByteBuffer candidateFrame) {
int componentId = candidateFrame.get(frameStartIndex + 4) & 0xFF;
int messageId = candidateFrame.get(frameStartIndex + 5) & 0xFF;
- int minimumPayloadLength = dialectRegistry.minimumPayloadLength(MavlinkVersion.V1, messageId);
+ int minimumPayloadLength = dialectRegistry.minimumPayloadLength(Version.V1, messageId);
if (payloadLength < minimumPayloadLength) {
return Optional.empty();
}
@@ -79,7 +79,7 @@ public Optional tryDecode(ByteBuffer candidateFrame) {
int receivedChecksum = ByteBufferUtils.readUnsignedLittleEndianShort(candidateFrame, crcStartIndex);
- int crcExtra = dialectRegistry.crcExtra(MavlinkVersion.V1, messageId);
+ int crcExtra = dialectRegistry.crcExtra(Version.V1, messageId);
int computedChecksum = CrcHelper.computeChecksumFromWritten(candidateFrame, frameStartIndex + 1, (HEADER_LENGTH) + payloadLength-1, crcExtra);
if (computedChecksum != receivedChecksum) {
return Optional.empty();
@@ -87,8 +87,8 @@ public Optional tryDecode(ByteBuffer candidateFrame) {
byte[] payload = ByteBufferUtils.copyBytes(candidateFrame, payloadStartIndex, payloadLength);
- MavlinkFrame frame = new MavlinkFrame();
- frame.setVersion(MavlinkVersion.V1);
+ Frame frame = new Frame();
+ frame.setVersion(Version.V1);
frame.setSequence(sequence);
frame.setSystemId(systemId);
frame.setComponentId(componentId);
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV2FrameHandler.java b/src/main/java/io/mapsmessaging/mavlink/framing/V2FrameHandler.java
similarity index 60%
rename from src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV2FrameHandler.java
rename to src/main/java/io/mapsmessaging/mavlink/framing/V2FrameHandler.java
index b9deea0..920ea74 100644
--- a/src/main/java/io/mapsmessaging/mavlink/framing/MavlinkV2FrameHandler.java
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/V2FrameHandler.java
@@ -19,27 +19,31 @@
package io.mapsmessaging.mavlink.framing;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
-import io.mapsmessaging.mavlink.message.MavlinkVersion;
-import io.mapsmessaging.mavlink.message.X25Crc;
+import io.mapsmessaging.mavlink.message.Frame;
+import io.mapsmessaging.mavlink.message.Version;
import java.nio.ByteBuffer;
+import java.util.Arrays;
import java.util.Optional;
-public final class MavlinkV2FrameHandler implements MavlinkFrameHandler {
+public final class V2FrameHandler implements FrameHandler {
private static final int STX = 0xFD;
public static final int INCOMPAT_FLAG_SIGNED = 0x01;
private static final int HEADER_LENGTH = 10; // LEN, INC, COMP, SEQ, SYSID, COMPID, MSGID(3)
- private static final int CRC_LENGTH = 2;
- private static final int SIGNATURE_LENGTH = 13;
- private final MavlinkDialectRegistry dialectRegistry;
+ static final int CRC_LENGTH = 2;
+ static final int SIGNATURE_LENGTH = 13;
- public MavlinkV2FrameHandler(MavlinkDialectRegistry dialectRegistry) {
+ private final DialectRegistry dialectRegistry;
+ private final SigningKeyProvider signingKeyProvider;
+
+ public V2FrameHandler(DialectRegistry dialectRegistry,
+ SigningKeyProvider signingKeyProvider) {
this.dialectRegistry = dialectRegistry;
+ this.signingKeyProvider = signingKeyProvider;
}
@Override
@@ -61,7 +65,7 @@ public int computeTotalFrameLength(ByteBuffer buffer, int frameStartIndex, int p
}
@Override
- public Optional tryDecode(ByteBuffer candidateFrame) {
+ public Optional tryDecode(ByteBuffer candidateFrame) {
int frameStartIndex = candidateFrame.position();
int stx = candidateFrame.get(frameStartIndex) & 0xFF;
@@ -80,7 +84,7 @@ public Optional tryDecode(ByteBuffer candidateFrame) {
int messageId = ByteBufferUtils.readUnsigned24BitLittleEndian(candidateFrame, frameStartIndex + 7);
- int minimumPayloadLength = dialectRegistry.minimumPayloadLength(MavlinkVersion.V2, messageId);
+ int minimumPayloadLength = dialectRegistry.minimumPayloadLength(Version.V2, messageId);
if (payloadLength < minimumPayloadLength) {
return Optional.empty();
}
@@ -91,7 +95,7 @@ public Optional tryDecode(ByteBuffer candidateFrame) {
int receivedChecksum = ByteBufferUtils.readUnsignedLittleEndianShort(candidateFrame, crcStartIndex);
- int crcExtra = dialectRegistry.crcExtra(MavlinkVersion.V2, messageId);
+ int crcExtra = dialectRegistry.crcExtra(Version.V2, messageId);
int checksum = CrcHelper.computeChecksumFromWritten(candidateFrame, frameStartIndex+1, (HEADER_LENGTH-1) + payloadLength, crcExtra);
if (checksum != receivedChecksum) {
@@ -101,13 +105,21 @@ public Optional tryDecode(ByteBuffer candidateFrame) {
byte[] payload = ByteBufferUtils.copyBytes(candidateFrame, payloadStartIndex, payloadLength);
byte[] signature = null;
+ boolean validated = false;
if (signed) {
int signatureStartIndex = crcStartIndex + CRC_LENGTH;
signature = ByteBufferUtils.copyBytes(candidateFrame, signatureStartIndex, SIGNATURE_LENGTH);
+ if (signingKeyProvider.canValidate()) {
+ if (!validateSignature(candidateFrame, frameStartIndex, crcStartIndex, systemId, componentId, signature)) {
+ return Optional.empty();
+ } else {
+ validated = true;
+ }
+ }
}
- MavlinkFrame frame = new MavlinkFrame();
- frame.setVersion(MavlinkVersion.V2);
+ Frame frame = new Frame();
+ frame.setVersion(Version.V2);
frame.setSequence(sequence);
frame.setSystemId(systemId);
frame.setComponentId(componentId);
@@ -119,14 +131,50 @@ public Optional tryDecode(ByteBuffer candidateFrame) {
frame.setIncompatibilityFlags(incompatibilityFlags);
frame.setCompatibilityFlags(compatibilityFlags);
frame.setSignature(signature);
+ frame.setValidated(validated);
return Optional.of(frame);
}
- private static void updateCrcFromCandidate(X25Crc crc, ByteBuffer candidateFrame, int index, int length) {
- int endIndex = index + length;
- for (int currentIndex = index; currentIndex < endIndex; currentIndex++) {
- crc.update(candidateFrame.get(currentIndex));
+ private boolean validateSignature(ByteBuffer candidateFrame,
+ int frameStartIndex,
+ int crcStartIndex,
+ int systemId,
+ int componentId,
+ byte[] receivedSignatureBlock) {
+
+ if (receivedSignatureBlock == null || receivedSignatureBlock.length != SIGNATURE_LENGTH) {
+ return false;
+ }
+
+ int linkId = receivedSignatureBlock[0] & 0xFF;
+ long timestamp = readUnsigned48BitLittleEndian(receivedSignatureBlock, 1);
+
+ byte[] signingKey = signingKeyProvider.getSigningKey(systemId, componentId, linkId);
+ if (signingKey == null || signingKey.length == 0) {
+ return false;
}
+
+ byte[] expectedSignatureBlock = V2SignatureGenerator.buildSignature(
+ candidateFrame,
+ frameStartIndex,
+ crcStartIndex,
+ linkId,
+ timestamp,
+ signingKey
+ );
+
+ return Arrays.equals(expectedSignatureBlock, receivedSignatureBlock);
+ }
+
+ private static long readUnsigned48BitLittleEndian(byte[] source, int offset) {
+ long value = 0;
+ value |= (source[offset] & 0xFFL);
+ value |= ((source[offset + 1] & 0xFFL) << 8);
+ value |= ((source[offset + 2] & 0xFFL) << 16);
+ value |= ((source[offset + 3] & 0xFFL) << 24);
+ value |= ((source[offset + 4] & 0xFFL) << 32);
+ value |= ((source[offset + 5] & 0xFFL) << 40);
+ return value;
}
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/V2FrameSigning.java b/src/main/java/io/mapsmessaging/mavlink/framing/V2FrameSigning.java
new file mode 100644
index 0000000..bfcbae5
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/V2FrameSigning.java
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.mapsmessaging.mavlink.framing;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import static io.mapsmessaging.mavlink.framing.V2FrameHandler.CRC_LENGTH;
+import static io.mapsmessaging.mavlink.framing.V2FrameHandler.SIGNATURE_LENGTH;
+
+public final class V2FrameSigning {
+
+ private V2FrameSigning() {
+ }
+
+ public static ByteBuffer appendSignature(ByteBuffer unsignedFrame,
+ int linkId,
+ long timestamp,
+ byte[] signingKey) {
+ if (unsignedFrame == null) {
+ throw new IllegalArgumentException("unsignedFrame must not be null");
+ }
+ if (signingKey == null || signingKey.length != 32) {
+ throw new IllegalArgumentException("signingKey must be 32 bytes");
+ }
+
+ ByteBuffer readOnly = unsignedFrame.duplicate();
+
+ int frameStartIndex = readOnly.position();
+ int frameLimit = readOnly.limit();
+
+ if (frameLimit - frameStartIndex < 1 + 10 + CRC_LENGTH) {
+ throw new IllegalArgumentException("Frame too short");
+ }
+
+ int crcStartIndex = frameLimit - CRC_LENGTH;
+
+ byte[] signatureBlock = V2SignatureGenerator.buildSignature(
+ readOnly,
+ frameStartIndex,
+ crcStartIndex,
+ linkId,
+ timestamp,
+ signingKey
+ );
+
+ ByteBuffer signedFrame = ByteBuffer.allocate((frameLimit - frameStartIndex) + SIGNATURE_LENGTH);
+ signedFrame.put(readOnly.duplicate());
+ signedFrame.put(signatureBlock);
+ signedFrame.flip();
+ return signedFrame;
+ }
+
+ public static boolean validateSignature(ByteBuffer signedFrame,
+ int frameStartIndex,
+ int crcStartIndex,
+ int systemId,
+ int componentId,
+ SigningKeyProvider signingKeyProvider) {
+ int signatureStartIndex = crcStartIndex + CRC_LENGTH;
+
+ byte[] receivedSignatureBlock = ByteBufferUtils.copyBytes(signedFrame, signatureStartIndex, SIGNATURE_LENGTH);
+
+ int linkId = receivedSignatureBlock[0] & 0xFF;
+ long timestamp = readUnsigned48BitLittleEndian(receivedSignatureBlock, 1);
+
+ byte[] signingKey = signingKeyProvider.getSigningKey(systemId, componentId, linkId);
+ if (signingKey == null || signingKey.length != 32) {
+ return false;
+ }
+
+ byte[] expectedSignatureBlock = V2SignatureGenerator.buildSignature(
+ signedFrame,
+ frameStartIndex,
+ crcStartIndex,
+ linkId,
+ timestamp,
+ signingKey
+ );
+
+ return Arrays.equals(expectedSignatureBlock, receivedSignatureBlock);
+ }
+
+ private static long readUnsigned48BitLittleEndian(byte[] source, int offset) {
+ long value = 0;
+ value |= (source[offset] & 0xFFL);
+ value |= ((source[offset + 1] & 0xFFL) << 8);
+ value |= ((source[offset + 2] & 0xFFL) << 16);
+ value |= ((source[offset + 3] & 0xFFL) << 24);
+ value |= ((source[offset + 4] & 0xFFL) << 32);
+ value |= ((source[offset + 5] & 0xFFL) << 40);
+ return value;
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/framing/V2SignatureGenerator.java b/src/main/java/io/mapsmessaging/mavlink/framing/V2SignatureGenerator.java
new file mode 100644
index 0000000..dc4aa84
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/framing/V2SignatureGenerator.java
@@ -0,0 +1,92 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mapsmessaging.mavlink.framing;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import static io.mapsmessaging.mavlink.framing.V2FrameHandler.CRC_LENGTH;
+import static io.mapsmessaging.mavlink.framing.V2FrameHandler.SIGNATURE_LENGTH;
+
+public final class V2SignatureGenerator {
+
+ public static byte[] buildSignature(ByteBuffer candidateFrame,
+ int frameStartIndex,
+ int crcStartIndex,
+ int linkId,
+ long timestamp,
+ byte[] signingKey) {
+
+ if (signingKey == null || signingKey.length == 0) {
+ throw new IllegalArgumentException("signingKey must be provided");
+ }
+
+ int packetEndExclusive = crcStartIndex + CRC_LENGTH;
+ int packetLength = packetEndExclusive - frameStartIndex;
+
+ if (packetLength <= 0) {
+ throw new IllegalArgumentException("Invalid frameStartIndex or crcStartIndex");
+ }
+
+ byte[] packetBytes = new byte[packetLength];
+ ByteBuffer readOnly = candidateFrame.duplicate();
+ readOnly.position(frameStartIndex);
+ readOnly.get(packetBytes);
+
+ byte[] digest = sha256(packetBytes, signingKey);
+ byte[] signatureBytes = Arrays.copyOf(digest, 6);
+
+ byte[] signatureBlock = new byte[SIGNATURE_LENGTH];
+ signatureBlock[0] = (byte) linkId;
+
+ writeUnsigned48BitLittleEndian(signatureBlock, 1, timestamp);
+
+ System.arraycopy(signatureBytes, 0, signatureBlock, 7, 6);
+ return signatureBlock;
+ }
+
+ private static void writeUnsigned48BitLittleEndian(byte[] target, int offset, long value) {
+ long masked = value & 0xFFFFFFFFFFFFL;
+
+ target[offset] = (byte) (masked);
+ target[offset + 1] = (byte) (masked >>> 8);
+ target[offset + 2] = (byte) (masked >>> 16);
+ target[offset + 3] = (byte) (masked >>> 24);
+ target[offset + 4] = (byte) (masked >>> 32);
+ target[offset + 5] = (byte) (masked >>> 40);
+ }
+
+ private static byte[] sha256(byte[] packetBytes, byte[] signingKey) {
+ MessageDigest digest;
+ try {
+ digest = MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("SHA-256 not available", e);
+ }
+
+ digest.update(packetBytes);
+ digest.update(signingKey);
+ return digest.digest();
+ }
+
+ private V2SignatureGenerator() {
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledField.java b/src/main/java/io/mapsmessaging/mavlink/message/CompiledField.java
similarity index 88%
rename from src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledField.java
rename to src/main/java/io/mapsmessaging/mavlink/message/CompiledField.java
index 24b6741..bbb8300 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledField.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/CompiledField.java
@@ -21,13 +21,13 @@
import io.mapsmessaging.mavlink.message.fields.AbstractMavlinkFieldCodec;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
import lombok.Data;
@Data
-public class MavlinkCompiledField {
+public class CompiledField {
- private MavlinkFieldDefinition fieldDefinition;
+ private FieldDefinition fieldDefinition;
private AbstractMavlinkFieldCodec fieldCodec;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java b/src/main/java/io/mapsmessaging/mavlink/message/CompiledMessage.java
similarity index 88%
rename from src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java
rename to src/main/java/io/mapsmessaging/mavlink/message/CompiledMessage.java
index 268de60..433f20e 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkCompiledMessage.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/CompiledMessage.java
@@ -25,12 +25,12 @@
import java.util.List;
@Data
-public class MavlinkCompiledMessage {
+public class CompiledMessage {
private int messageId;
private String name;
- private MavlinkMessageDefinition messageDefinition;
- private List compiledFields;
+ private MessageDefinition messageDefinition;
+ private List compiledFields;
private int payloadSizeBytes;
private int minimumPayloadSizeBytes;
@@ -53,7 +53,7 @@ public String toString() {
.append(messageDefinition.getExtraCrc())
.append("]\n");
- for (MavlinkCompiledField compiledField : compiledFields) {
+ for (CompiledField compiledField : compiledFields) {
builder.append(" ").append(compiledField.toString()).append("\n");
}
return builder.toString();
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkEnumResolver.java b/src/main/java/io/mapsmessaging/mavlink/message/EnumResolver.java
similarity index 81%
rename from src/main/java/io/mapsmessaging/mavlink/message/MavlinkEnumResolver.java
rename to src/main/java/io/mapsmessaging/mavlink/message/EnumResolver.java
index 6c368d9..fb50ca2 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkEnumResolver.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/EnumResolver.java
@@ -20,23 +20,23 @@
package io.mapsmessaging.mavlink.message;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumEntry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.EnumDefinition;
+import io.mapsmessaging.mavlink.message.fields.EnumEntry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-public final class MavlinkEnumResolver {
+public final class EnumResolver {
- private MavlinkEnumResolver() {
+ private EnumResolver() {
}
public static Object resolveEnumValue(
- MavlinkMessageRegistry registry,
- MavlinkFieldDefinition field,
+ MessageRegistry registry,
+ FieldDefinition field,
Object value
) throws IOException {
@@ -52,7 +52,7 @@ public static Object resolveEnumValue(
throw new IOException("Enum field '" + field.getName() + "' cannot be null");
}
- MavlinkEnumDefinition enumDef = registry.getEnumsByName().get(enumName);
+ EnumDefinition enumDef = registry.getEnumsByName().get(enumName);
if (enumDef == null) {
throw new IOException("Enum '" + enumName + "' not registered");
}
@@ -62,7 +62,7 @@ public static Object resolveEnumValue(
}
if (value instanceof String s) {
- MavlinkEnumEntry entry = enumDef.getByName(s);
+ EnumEntry entry = enumDef.getByName(s);
if (entry == null) {
throw new IOException(
"Unknown enum value '" + s + "' for enum '" + enumName + "'");
@@ -84,11 +84,11 @@ public static Object resolveEnumValue(
int mask = 0;
List res = new ArrayList<>();
for (Object element : arr) {
- MavlinkEnumEntry entry;
+ EnumEntry entry;
if(element instanceof Number index){
- List entries = enumDef.getByBitmask(index.longValue());
+ List entries = enumDef.getByBitmask(index.longValue());
mask = 0;
- for(MavlinkEnumEntry mavlinkEnumEntry:entries){
+ for(EnumEntry mavlinkEnumEntry:entries){
mask |= mavlinkEnumEntry.getValue();
}
res.add(mask);
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/Frame.java b/src/main/java/io/mapsmessaging/mavlink/message/Frame.java
new file mode 100644
index 0000000..5ca5947
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/message/Frame.java
@@ -0,0 +1,137 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.mapsmessaging.mavlink.message;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(
+ title = "MAVLink Frame",
+ description = "Decoded MAVLink frame with header, payload, checksum, and optional signature"
+)
+public class Frame {
+
+ @Schema(
+ description = "MAVLink protocol version",
+ example = "V2",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private Version version;
+
+ @Schema(
+ description = "Packet sequence number",
+ example = "42",
+ minimum = "0",
+ maximum = "255",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private int sequence;
+
+ @Schema(
+ description = "Source system ID",
+ example = "1",
+ minimum = "0",
+ maximum = "255",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private int systemId;
+
+ @Schema(
+ description = "Source component ID",
+ example = "1",
+ minimum = "0",
+ maximum = "255",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private int componentId;
+
+ @Schema(
+ description = "MAVLink message ID",
+ example = "33",
+ minimum = "0",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private int messageId;
+
+ @Schema(
+ description = "Payload length in bytes",
+ example = "12",
+ minimum = "0",
+ maximum = "255",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private int payloadLength;
+
+ @Schema(
+ description = "Raw payload bytes",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private byte[] payload;
+
+ @Schema(
+ description = "CRC checksum (X25) as unsigned 16-bit value",
+ example = "54321",
+ minimum = "0",
+ maximum = "65535",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private int checksum;
+
+ @Schema(
+ description = "True if the frame includes a MAVLink v2 signature",
+ example = "true",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private boolean signed;
+
+ @Schema(
+ description = "MAVLink v2 incompatibility flags",
+ example = "1",
+ minimum = "0",
+ maximum = "255",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private byte incompatibilityFlags;
+
+ @Schema(
+ description = "MAVLink v2 compatibility flags",
+ example = "0",
+ minimum = "0",
+ maximum = "255",
+ requiredMode = Schema.RequiredMode.REQUIRED
+ )
+ private byte compatibilityFlags;
+
+ @Schema(
+ description = "MAVLink v2 signature block (13 bytes) if present",
+ requiredMode = Schema.RequiredMode.NOT_REQUIRED,
+ nullable = true
+ )
+ private byte[] signature;
+
+ @Schema(
+ description = "True if CRC and (if present) signature validation succeeded",
+ example = "true",
+ requiredMode = Schema.RequiredMode.REQUIRED,
+ defaultValue = "false"
+ )
+ private boolean validated = false;
+}
\ No newline at end of file
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrameParser.java b/src/main/java/io/mapsmessaging/mavlink/message/FrameParser.java
similarity index 93%
rename from src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrameParser.java
rename to src/main/java/io/mapsmessaging/mavlink/message/FrameParser.java
index eb0b953..971032a 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrameParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/FrameParser.java
@@ -21,7 +21,7 @@
import java.util.Arrays;
-public class MavlinkFrameParser {
+public class FrameParser {
private static final int MAVLINK_V1_STX = 0xFE;
private static final int MAVLINK_V2_STX = 0xFD;
@@ -32,7 +32,7 @@ public class MavlinkFrameParser {
private static final int MAVLINK_V2_SIGNATURE_LENGTH = 13;
private static final int MAVLINK_V2_SIGNING_FLAG = 0x01;
- public MavlinkFrame parse(byte[] frameBytes) {
+ public Frame parse(byte[] frameBytes) {
if (frameBytes == null || frameBytes.length == 0) {
throw new IllegalArgumentException("Empty MAVLink frame");
}
@@ -48,7 +48,7 @@ public MavlinkFrame parse(byte[] frameBytes) {
throw new IllegalArgumentException("Unsupported MAVLink STX byte: 0x" + Integer.toHexString(startOfText));
}
- private MavlinkFrame parseV1(byte[] frameBytes) {
+ private Frame parseV1(byte[] frameBytes) {
if (frameBytes.length < MAVLINK_V1_MIN_LENGTH) {
throw new IllegalArgumentException("MAVLink v1 frame too short: " + frameBytes.length);
}
@@ -61,8 +61,8 @@ private MavlinkFrame parseV1(byte[] frameBytes) {
);
}
- MavlinkFrame frame = new MavlinkFrame();
- frame.setVersion(MavlinkVersion.V1);
+ Frame frame = new Frame();
+ frame.setVersion(Version.V1);
int sequence = frameBytes[2] & 0xFF;
int systemId = frameBytes[3] & 0xFF;
@@ -89,7 +89,7 @@ private MavlinkFrame parseV1(byte[] frameBytes) {
return frame;
}
- private MavlinkFrame parseV2(byte[] frameBytes) {
+ private Frame parseV2(byte[] frameBytes) {
if (frameBytes.length < MAVLINK_V2_MIN_LENGTH) {
throw new IllegalArgumentException("MAVLink v2 frame too short: " + frameBytes.length);
}
@@ -128,8 +128,8 @@ private MavlinkFrame parseV2(byte[] frameBytes) {
);
}
- MavlinkFrame frame = new MavlinkFrame();
- frame.setVersion(MavlinkVersion.V2);
+ Frame frame = new Frame();
+ frame.setVersion(Version.V2);
frame.setSequence(sequence);
frame.setSystemId(systemId);
frame.setComponentId(componentId);
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrame.java b/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrame.java
deleted file mode 100644
index 871ab2c..0000000
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkFrame.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *
- * Copyright [ 2020 - 2024 ] Matthew Buckton
- * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
- *
- * Licensed under the Apache License, Version 2.0 with the Commons Clause
- * (the "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * https://commonsclause.com/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.mapsmessaging.mavlink.message;
-
-import lombok.Data;
-
-@Data
-public class MavlinkFrame {
-
- private MavlinkVersion version;
- private int sequence;
- private int systemId;
- private int componentId;
- private int messageId;
- private int payloadLength;
- private byte[] payload;
- private int checksum;
- private boolean signed;
- private byte incompatibilityFlags;
- private byte compatibilityFlags;
- private byte[] signature;
-}
\ No newline at end of file
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageDefinition.java b/src/main/java/io/mapsmessaging/mavlink/message/MessageDefinition.java
similarity index 69%
rename from src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageDefinition.java
rename to src/main/java/io/mapsmessaging/mavlink/message/MessageDefinition.java
index 7d6f600..b6c5735 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageDefinition.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MessageDefinition.java
@@ -19,8 +19,8 @@
package io.mapsmessaging.mavlink.message;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkWireType;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.WireType;
import lombok.Getter;
import lombok.Setter;
@@ -30,7 +30,7 @@
@Getter
@Setter
-public class MavlinkMessageDefinition {
+public class MessageDefinition {
private int messageId;
private String name;
@@ -39,7 +39,7 @@ public class MavlinkMessageDefinition {
/**
* Wire-order, immutable after setXmlOrderedFields().
*/
- private List fields = List.of();
+ private List fields = List.of();
private int extraCrc;
@@ -53,29 +53,29 @@ public String toString() {
.append(", description=")
.append(description)
.append("\n");
- for (MavlinkFieldDefinition field : fields) {
+ for (FieldDefinition field : fields) {
builder.append(field.toString()).append("\n");
}
return builder.toString();
}
- public void setXmlOrderedFields(List xmlOrdered) {
+ public void setXmlOrderedFields(List xmlOrdered) {
if (xmlOrdered == null || xmlOrdered.isEmpty()) {
fields = List.of();
computeExtraCrc();
return;
}
- List ordered = orderForWire(xmlOrdered);
+ List ordered = orderForWire(xmlOrdered);
fields = List.copyOf(ordered); // locked
computeExtraCrc();
}
- private List orderForWire(List xmlOrdered) {
- List base = new ArrayList<>();
- List extensions = new ArrayList<>();
+ private List orderForWire(List xmlOrdered) {
+ List base = new ArrayList<>();
+ List extensions = new ArrayList<>();
- for (MavlinkFieldDefinition field : xmlOrdered) {
+ for (FieldDefinition field : xmlOrdered) {
if (field.isExtension()) {
extensions.add(field);
} else {
@@ -83,14 +83,14 @@ private List orderForWire(List x
}
}
- Comparator comparator = Comparator
- .comparingInt((MavlinkFieldDefinition f) -> f.getWireType().getSizeInBytes()).reversed()
- .thenComparingInt(MavlinkFieldDefinition::getIndex); // xml order tie-breaker
+ Comparator comparator = Comparator
+ .comparingInt((FieldDefinition f) -> f.getWireType().getSizeInBytes()).reversed()
+ .thenComparingInt(FieldDefinition::getIndex); // xml order tie-breaker
base.sort(comparator);
extensions.sort(comparator);
- List ordered = new ArrayList<>(base.size() + extensions.size());
+ List ordered = new ArrayList<>(base.size() + extensions.size());
ordered.addAll(base);
ordered.addAll(extensions);
@@ -103,12 +103,12 @@ private void computeExtraCrc() {
crcCharArray(crc, getName().toCharArray());
- for (MavlinkFieldDefinition field : fields) {
+ for (FieldDefinition field : fields) {
if (field.isExtension()) {
continue;
}
- MavlinkWireType fieldType = MavlinkWireType.fromXmlType(field.getType());
+ WireType fieldType = WireType.fromXmlType(field.getType());
crcCharArray(crc, fieldType.getWireName().toCharArray());
crcCharArray(crc, field.getName().toCharArray());
if (field.isArray()) {
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java b/src/main/java/io/mapsmessaging/mavlink/message/MessageRegistry.java
similarity index 57%
rename from src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
rename to src/main/java/io/mapsmessaging/mavlink/message/MessageRegistry.java
index bb51cb5..c8e0280 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkMessageRegistry.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/MessageRegistry.java
@@ -21,45 +21,45 @@
import com.google.gson.JsonObject;
import io.mapsmessaging.mavlink.message.fields.AbstractMavlinkFieldCodec;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldCodecFactory;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
-import io.mapsmessaging.mavlink.parser.MavlinkDialectDefinition;
-import io.mapsmessaging.mavlink.schema.MavlinkJsonSchemaBuilder;
+import io.mapsmessaging.mavlink.message.fields.EnumDefinition;
+import io.mapsmessaging.mavlink.message.fields.FieldCodecFactory;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.parser.DialectDefinition;
+import io.mapsmessaging.mavlink.schema.JsonSchemaBuilder;
import lombok.Getter;
import lombok.Setter;
import java.util.*;
@Getter
-public class MavlinkMessageRegistry {
+public class MessageRegistry {
@Setter
private String dialectName;
- private List compiledMessages;
+ private List compiledMessages;
- private Map compiledMessagesById;
+ private Map compiledMessagesById;
- private Map enumsByName;
+ private Map enumsByName;
private Map jsonSchema;
- public static MavlinkMessageRegistry fromDialectDefinition(MavlinkDialectDefinition dialectDefinition) {
- MavlinkMessageRegistry registry = new MavlinkMessageRegistry();
+ public static MessageRegistry fromDialectDefinition(DialectDefinition dialectDefinition) {
+ MessageRegistry registry = new MessageRegistry();
registry.setDialectName(dialectDefinition.getName());
- List compiledMessageList = new ArrayList<>();
- Map compiledByIdMap = new HashMap<>();
+ List compiledMessageList = new ArrayList<>();
+ Map compiledByIdMap = new HashMap<>();
Map schemaMap = new HashMap<>();
- for (MavlinkMessageDefinition messageDefinition : dialectDefinition.getMessages()) {
- MavlinkCompiledMessage compiledMessage = compileMessage(messageDefinition);
+ for (MessageDefinition messageDefinition : dialectDefinition.getMessages()) {
+ CompiledMessage compiledMessage = compileMessage(messageDefinition);
compiledMessageList.add(compiledMessage);
compiledByIdMap.put(compiledMessage.getMessageId(), compiledMessage);
- schemaMap.put(compiledMessage.getMessageId(), MavlinkJsonSchemaBuilder.buildSchema(compiledMessage, dialectDefinition.getEnumsByName()));
+ schemaMap.put(compiledMessage.getMessageId(), JsonSchemaBuilder.buildSchema(compiledMessage, dialectDefinition.getEnumsByName()));
}
registry.setCompiledMessages(compiledMessageList);
@@ -70,15 +70,15 @@ public static MavlinkMessageRegistry fromDialectDefinition(MavlinkDialectDefinit
return registry;
}
- private void setEnumsByName(Map stringMavlinkEnumDefinitionHashMap) {
+ private void setEnumsByName(Map stringMavlinkEnumDefinitionHashMap) {
this.enumsByName = Collections.unmodifiableMap(new HashMap<>(stringMavlinkEnumDefinitionHashMap));
}
- private void setCompiledMessagesById(Map compiledByIdMap) {
+ private void setCompiledMessagesById(Map compiledByIdMap) {
this.compiledMessagesById = Collections.unmodifiableMap(new HashMap<>(compiledByIdMap));
}
- private void setCompiledMessages(List compiledMessageList) {
+ private void setCompiledMessages(List compiledMessageList) {
this.compiledMessages = Collections.unmodifiableList(new ArrayList<>(compiledMessageList));
}
@@ -86,19 +86,19 @@ private void setJsonSchema(Map jsonSchemaMap ){
this.jsonSchema = Collections.unmodifiableMap(new HashMap<>(jsonSchemaMap));
}
- private static MavlinkCompiledMessage compileMessage(MavlinkMessageDefinition messageDefinition) {
- MavlinkCompiledMessage compiledMessage = new MavlinkCompiledMessage();
+ private static CompiledMessage compileMessage(MessageDefinition messageDefinition) {
+ CompiledMessage compiledMessage = new CompiledMessage();
compiledMessage.setMessageId(messageDefinition.getMessageId());
compiledMessage.setName(messageDefinition.getName());
compiledMessage.setMessageDefinition(messageDefinition);
- List compiledFields = new ArrayList<>();
+ List compiledFields = new ArrayList<>();
int currentOffset = 0;
- for (MavlinkFieldDefinition fieldDefinition : messageDefinition.getFields()) {
- AbstractMavlinkFieldCodec fieldCodec = MavlinkFieldCodecFactory.createCodec(fieldDefinition);
+ for (FieldDefinition fieldDefinition : messageDefinition.getFields()) {
+ AbstractMavlinkFieldCodec fieldCodec = FieldCodecFactory.createCodec(fieldDefinition);
- MavlinkCompiledField compiledField = new MavlinkCompiledField();
+ CompiledField compiledField = new CompiledField();
compiledField.setFieldDefinition(fieldDefinition);
compiledField.setFieldCodec(fieldCodec);
compiledField.setOffsetInPayload(currentOffset);
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkVersion.java b/src/main/java/io/mapsmessaging/mavlink/message/Version.java
similarity index 96%
rename from src/main/java/io/mapsmessaging/mavlink/message/MavlinkVersion.java
rename to src/main/java/io/mapsmessaging/mavlink/message/Version.java
index cbde5bb..8736469 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/MavlinkVersion.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/Version.java
@@ -19,6 +19,6 @@
package io.mapsmessaging.mavlink.message;
-public enum MavlinkVersion {
+public enum Version {
V1, V2
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/AbstractMavlinkFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/AbstractMavlinkFieldCodec.java
index c0738ee..085aaf0 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/AbstractMavlinkFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/AbstractMavlinkFieldCodec.java
@@ -24,13 +24,13 @@
public abstract class AbstractMavlinkFieldCodec {
- private final MavlinkWireType wireType;
+ private final WireType wireType;
- protected AbstractMavlinkFieldCodec(MavlinkWireType wireType) {
+ protected AbstractMavlinkFieldCodec(WireType wireType) {
this.wireType = wireType;
}
- public MavlinkWireType getWireType() {
+ public WireType getWireType() {
return wireType;
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
index c32ffb6..9c9bfcb 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/ArrayFieldCodec.java
@@ -45,7 +45,7 @@ public int getSizeInBytes() {
public Object decode(ByteBuffer buffer) {
buffer.order(ByteOrder.LITTLE_ENDIAN);
- if (treatAsString && getWireType() == MavlinkWireType.CHAR) {
+ if (treatAsString && getWireType() == WireType.CHAR) {
byte[] temp = new byte[arrayLength];
buffer.get(temp);
int end = 0;
@@ -62,7 +62,7 @@ public Object decode(ByteBuffer buffer) {
public void encode(ByteBuffer buffer, Object value) {
buffer.order(ByteOrder.LITTLE_ENDIAN);
- if (treatAsString && getWireType() == MavlinkWireType.CHAR) {
+ if (treatAsString && getWireType() == WireType.CHAR) {
String text = value == null ? "" : value.toString();
byte[] bytes = text.getBytes();
int length = Math.min(bytes.length, arrayLength);
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/CharFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/CharFieldCodec.java
index 85ec564..fe0e385 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/CharFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/CharFieldCodec.java
@@ -25,7 +25,7 @@
public class CharFieldCodec extends AbstractMavlinkFieldCodec {
public CharFieldCodec() {
- super(MavlinkWireType.CHAR);
+ super(WireType.CHAR);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/DoubleFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/DoubleFieldCodec.java
index 3c617ed..4534e4e 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/DoubleFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/DoubleFieldCodec.java
@@ -25,7 +25,7 @@
public class DoubleFieldCodec extends AbstractMavlinkFieldCodec {
public DoubleFieldCodec() {
- super(MavlinkWireType.DOUBLE);
+ super(WireType.DOUBLE);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumDefinition.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/EnumDefinition.java
similarity index 78%
rename from src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumDefinition.java
rename to src/main/java/io/mapsmessaging/mavlink/message/fields/EnumDefinition.java
index bdf3c29..18cc395 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumDefinition.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/EnumDefinition.java
@@ -30,7 +30,7 @@
@AllArgsConstructor
@NoArgsConstructor
-public class MavlinkEnumDefinition {
+public class EnumDefinition {
@Getter
@Setter
private String name;
@@ -40,21 +40,21 @@ public class MavlinkEnumDefinition {
@Getter
@Setter
private String description;
- private List entries = new ArrayList<>();
+ private List entries = new ArrayList<>();
- public List getEntries() {
+ public List getEntries() {
return Collections.unmodifiableList(entries);
}
- public void setEntries(List list) {
+ public void setEntries(List list) {
entries = Collections.unmodifiableList(list);
}
- public MavlinkEnumEntry getByName(String name) {
+ public EnumEntry getByName(String name) {
if (name == null) {
return null;
}
- for (MavlinkEnumEntry entry : entries) {
+ for (EnumEntry entry : entries) {
if (name.equals(entry.getName())) {
return entry;
}
@@ -66,8 +66,8 @@ public boolean hasEntry(String name) {
return getByName(name) != null;
}
- public MavlinkEnumEntry getByValue(long value) {
- for (MavlinkEnumEntry entry : entries) {
+ public EnumEntry getByValue(long value) {
+ for (EnumEntry entry : entries) {
if (entry.getValue() == value) {
return entry;
}
@@ -75,14 +75,14 @@ public MavlinkEnumEntry getByValue(long value) {
return null;
}
- public List getByBitmask(long mask) {
+ public List getByBitmask(long mask) {
if (!bitmask || mask == 0) {
return List.of();
}
- List result = new ArrayList<>();
+ List result = new ArrayList<>();
- for (MavlinkEnumEntry entry : entries) {
+ for (EnumEntry entry : entries) {
long value = entry.getValue();
if ((mask & value) == value) {
result.add(entry);
@@ -98,7 +98,7 @@ public String toString() {
builder.append(name)
.append(", bitmask=").append(bitmask)
.append(", description=").append(description).append("\n");
- for (MavlinkEnumEntry entry : entries) {
+ for (EnumEntry entry : entries) {
builder.append(entry.toString()).append("\n");
}
return builder.toString();
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumEntry.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/EnumEntry.java
similarity index 97%
rename from src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumEntry.java
rename to src/main/java/io/mapsmessaging/mavlink/message/fields/EnumEntry.java
index c7ee10d..2391172 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkEnumEntry.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/EnumEntry.java
@@ -22,7 +22,7 @@
import lombok.Data;
@Data
-public class MavlinkEnumEntry {
+public class EnumEntry {
private long value;
private String name;
private String description;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldCodecFactory.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/FieldCodecFactory.java
similarity index 90%
rename from src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldCodecFactory.java
rename to src/main/java/io/mapsmessaging/mavlink/message/fields/FieldCodecFactory.java
index 4e8cfe5..66c453b 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldCodecFactory.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/FieldCodecFactory.java
@@ -20,12 +20,12 @@
package io.mapsmessaging.mavlink.message.fields;
-public final class MavlinkFieldCodecFactory {
+public final class FieldCodecFactory {
- private MavlinkFieldCodecFactory() {
+ private FieldCodecFactory() {
}
- public static AbstractMavlinkFieldCodec createCodec(MavlinkFieldDefinition fieldDefinition) {
+ public static AbstractMavlinkFieldCodec createCodec(FieldDefinition fieldDefinition) {
String typeString = fieldDefinition.getType();
String baseType = typeString;
int arrayLength = 0;
@@ -42,7 +42,7 @@ public static AbstractMavlinkFieldCodec createCodec(MavlinkFieldDefinition field
AbstractMavlinkFieldCodec scalarCodec = createScalarCodec(baseType);
if (arrayLength > 0) {
- boolean treatAsString = scalarCodec.getWireType() == MavlinkWireType.CHAR;
+ boolean treatAsString = scalarCodec.getWireType() == WireType.CHAR;
return new ArrayFieldCodec(scalarCodec, arrayLength, treatAsString);
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldDefinition.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/FieldDefinition.java
similarity index 96%
rename from src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldDefinition.java
rename to src/main/java/io/mapsmessaging/mavlink/message/fields/FieldDefinition.java
index 986fac3..5fc864f 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkFieldDefinition.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/FieldDefinition.java
@@ -23,7 +23,7 @@
import lombok.Data;
@Data
-public class MavlinkFieldDefinition {
+public class FieldDefinition {
private int index;
private String type; // XML base type ("uint8_t", "char")
private String name;
@@ -31,7 +31,7 @@ public class MavlinkFieldDefinition {
private String description;
private String enumName;
- private MavlinkWireType wireType;
+ private WireType wireType;
private boolean extension;
private boolean array;
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/FloatFieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/FloatFieldCodec.java
index 58af855..2f2c7eb 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/FloatFieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/FloatFieldCodec.java
@@ -25,7 +25,7 @@
public class FloatFieldCodec extends AbstractMavlinkFieldCodec {
public FloatFieldCodec() {
- super(MavlinkWireType.FLOAT);
+ super(WireType.FLOAT);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int16FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int16FieldCodec.java
index 8d4e9d2..cf54f7f 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int16FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int16FieldCodec.java
@@ -25,7 +25,7 @@
public class Int16FieldCodec extends AbstractMavlinkFieldCodec {
public Int16FieldCodec() {
- super(MavlinkWireType.INT16);
+ super(WireType.INT16);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int32FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int32FieldCodec.java
index afdf39a..1e3a844 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int32FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int32FieldCodec.java
@@ -26,7 +26,7 @@
public class Int32FieldCodec extends AbstractMavlinkFieldCodec {
public Int32FieldCodec() {
- super(MavlinkWireType.INT32);
+ super(WireType.INT32);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int64FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int64FieldCodec.java
index 59e91df..137cc8f 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int64FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int64FieldCodec.java
@@ -25,7 +25,7 @@
public class Int64FieldCodec extends AbstractMavlinkFieldCodec {
public Int64FieldCodec() {
- super(MavlinkWireType.INT64);
+ super(WireType.INT64);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int8FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int8FieldCodec.java
index e7e4e50..9df3b3c 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/Int8FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/Int8FieldCodec.java
@@ -25,7 +25,7 @@
public class Int8FieldCodec extends AbstractMavlinkFieldCodec {
public Int8FieldCodec() {
- super(MavlinkWireType.INT8);
+ super(WireType.INT8);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt16FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt16FieldCodec.java
index a8193ff..045198c 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt16FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt16FieldCodec.java
@@ -26,7 +26,7 @@
public class UInt16FieldCodec extends AbstractMavlinkFieldCodec {
public UInt16FieldCodec() {
- super(MavlinkWireType.UINT16);
+ super(WireType.UINT16);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt32FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt32FieldCodec.java
index e8d0662..b148487 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt32FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt32FieldCodec.java
@@ -25,7 +25,7 @@
public class UInt32FieldCodec extends AbstractMavlinkFieldCodec {
public UInt32FieldCodec() {
- super(MavlinkWireType.UINT32);
+ super(WireType.UINT32);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt64FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt64FieldCodec.java
index 000206f..23ff4e1 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt64FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt64FieldCodec.java
@@ -25,7 +25,7 @@
public class UInt64FieldCodec extends AbstractMavlinkFieldCodec {
public UInt64FieldCodec() {
- super(MavlinkWireType.UINT64);
+ super(WireType.UINT64);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt8FieldCodec.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt8FieldCodec.java
index 90dae5e..ccd9975 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt8FieldCodec.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/UInt8FieldCodec.java
@@ -26,7 +26,7 @@
public class UInt8FieldCodec extends AbstractMavlinkFieldCodec {
public UInt8FieldCodec() {
- super(MavlinkWireType.UINT8);
+ super(WireType.UINT8);
}
@Override
diff --git a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java b/src/main/java/io/mapsmessaging/mavlink/message/fields/WireType.java
similarity index 94%
rename from src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java
rename to src/main/java/io/mapsmessaging/mavlink/message/fields/WireType.java
index 5d1c02f..5922320 100644
--- a/src/main/java/io/mapsmessaging/mavlink/message/fields/MavlinkWireType.java
+++ b/src/main/java/io/mapsmessaging/mavlink/message/fields/WireType.java
@@ -21,7 +21,7 @@
import lombok.Getter;
-public enum MavlinkWireType {
+public enum WireType {
INT8(1, "int8_t"),
UINT8(1, "uint8_t"),
@@ -41,12 +41,12 @@ public enum MavlinkWireType {
@Getter
private final String wireName;
- MavlinkWireType(int sizeInBytes, String wireName) {
+ WireType(int sizeInBytes, String wireName) {
this.sizeInBytes = sizeInBytes;
this.wireName = wireName;
}
- public static MavlinkWireType fromXmlType(String xmlType) {
+ public static WireType fromXmlType(String xmlType) {
if (xmlType == null) {
throw new IllegalArgumentException("MAVLink XML type is null");
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java b/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathIncludeResolver.java
similarity index 87%
rename from src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
rename to src/main/java/io/mapsmessaging/mavlink/parser/ClasspathIncludeResolver.java
index 98f5af0..8e6389c 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathMavlinkIncludeResolver.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/ClasspathIncludeResolver.java
@@ -19,17 +19,16 @@
package io.mapsmessaging.mavlink.parser;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
-public class ClasspathMavlinkIncludeResolver implements MavlinkIncludeResolver {
+public class ClasspathIncludeResolver implements IncludeResolver {
private final ClassLoader classLoader;
private final String basePath;
- public ClasspathMavlinkIncludeResolver(ClassLoader classLoader, String basePath) {
+ public ClasspathIncludeResolver(ClassLoader classLoader, String basePath) {
this.classLoader = Objects.requireNonNull(classLoader, "classLoader");
this.basePath = Objects.requireNonNull(basePath, "basePath");
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectDefinition.java b/src/main/java/io/mapsmessaging/mavlink/parser/DialectDefinition.java
similarity index 71%
rename from src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectDefinition.java
rename to src/main/java/io/mapsmessaging/mavlink/parser/DialectDefinition.java
index 19c19c1..93fb5a0 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectDefinition.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/DialectDefinition.java
@@ -20,17 +20,17 @@
package io.mapsmessaging.mavlink.parser;
-import io.mapsmessaging.mavlink.message.MavlinkMessageDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
+import io.mapsmessaging.mavlink.message.MessageDefinition;
+import io.mapsmessaging.mavlink.message.fields.EnumDefinition;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
-public class MavlinkDialectDefinition {
+public class DialectDefinition {
private String name;
- private List messages;
- private Map messagesById;
- private Map enumsByName;
+ private List messages;
+ private Map messagesById;
+ private Map enumsByName;
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectLoader.java b/src/main/java/io/mapsmessaging/mavlink/parser/DialectLoader.java
similarity index 77%
rename from src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectLoader.java
rename to src/main/java/io/mapsmessaging/mavlink/parser/DialectLoader.java
index 5630270..abb114a 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkDialectLoader.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/DialectLoader.java
@@ -19,8 +19,8 @@
package io.mapsmessaging.mavlink.parser;
-import io.mapsmessaging.mavlink.message.MavlinkMessageDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
+import io.mapsmessaging.mavlink.message.MessageDefinition;
+import io.mapsmessaging.mavlink.message.fields.EnumDefinition;
import lombok.RequiredArgsConstructor;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
@@ -31,9 +31,9 @@
import java.util.*;
@RequiredArgsConstructor
-public class MavlinkDialectLoader {
+public class DialectLoader {
- private final MavlinkXmlParser parser;
+ private final XmlParser parser;
/**
* Loads a dialect XML, recursively resolving directives.
@@ -41,7 +41,7 @@ public class MavlinkDialectLoader {
* Merge order:
* includes (deep-first) then current document overrides.
*/
- public MavlinkDialectDefinition load(String dialectName, InputStream rootXml, MavlinkIncludeResolver includeResolver)
+ public DialectDefinition load(String dialectName, InputStream rootXml, IncludeResolver includeResolver)
throws ParserConfigurationException, SAXException, IOException {
Objects.requireNonNull(dialectName, "dialectName");
@@ -55,15 +55,15 @@ public MavlinkDialectDefinition load(String dialectName, InputStream rootXml, Ma
return loadDocumentRecursive(dialectName, rootDoc, includeResolver, visiting, visited);
}
- private MavlinkDialectDefinition loadDocumentRecursive(
+ private DialectDefinition loadDocumentRecursive(
String dialectName,
Document document,
- MavlinkIncludeResolver includeResolver,
+ IncludeResolver includeResolver,
Set visiting,
Set visited) throws ParserConfigurationException, SAXException, IOException {
// Start with an empty dialect we will fill by merging includes + current doc
- MavlinkDialectDefinition merged = emptyDialect(dialectName);
+ DialectDefinition merged = emptyDialect(dialectName);
// 1) Load includes first (depth-first)
List includes = parser.parseIncludes(document);
@@ -80,7 +80,7 @@ private MavlinkDialectDefinition loadDocumentRecursive(
throw new IOException("Unable to resolve : " + includeName);
}
Document includeDoc = parser.parseDocument(includeStream);
- MavlinkDialectDefinition includeDialect =
+ DialectDefinition includeDialect =
loadDocumentRecursive(dialectName, includeDoc, includeResolver, visiting, visited);
mergeInto(merged, includeDialect);
} finally {
@@ -90,7 +90,7 @@ private MavlinkDialectDefinition loadDocumentRecursive(
}
// 2) Parse current document and overlay it (current wins)
- MavlinkDialectDefinition current = parser.parse(document, dialectName);
+ DialectDefinition current = parser.parse(document, dialectName);
mergeInto(merged, current);
// 3) Normalize lists/maps once at the end
@@ -99,8 +99,8 @@ private MavlinkDialectDefinition loadDocumentRecursive(
return merged;
}
- private MavlinkDialectDefinition emptyDialect(String dialectName) {
- MavlinkDialectDefinition def = new MavlinkDialectDefinition();
+ private DialectDefinition emptyDialect(String dialectName) {
+ DialectDefinition def = new DialectDefinition();
def.setName(dialectName);
def.setEnumsByName(new LinkedHashMap<>());
def.setMessages(new ArrayList<>());
@@ -111,14 +111,14 @@ private MavlinkDialectDefinition emptyDialect(String dialectName) {
/**
* Merge source into target. Target wins on conflicts (because caller controls order).
*/
- private void mergeInto(MavlinkDialectDefinition target, MavlinkDialectDefinition source) {
+ private void mergeInto(DialectDefinition target, DialectDefinition source) {
if (source == null) {
return;
}
// Enums by name
if (source.getEnumsByName() != null) {
- for (Map.Entry e : source.getEnumsByName().entrySet()) {
+ for (Map.Entry e : source.getEnumsByName().entrySet()) {
if (e.getKey() == null) {
continue;
}
@@ -128,7 +128,7 @@ private void mergeInto(MavlinkDialectDefinition target, MavlinkDialectDefinition
// Messages by id (canonical)
if (source.getMessagesById() != null) {
- for (Map.Entry e : source.getMessagesById().entrySet()) {
+ for (Map.Entry e : source.getMessagesById().entrySet()) {
if (e.getKey() == null || e.getKey() < 0) {
continue;
}
@@ -140,11 +140,11 @@ private void mergeInto(MavlinkDialectDefinition target, MavlinkDialectDefinition
/**
* Rebuild the messages list from messagesById, in id order, stable.
*/
- private void normalize(MavlinkDialectDefinition def) {
+ private void normalize(DialectDefinition def) {
List ids = new ArrayList<>(def.getMessagesById().keySet());
ids.sort(Integer::compareTo);
- List messages = new ArrayList<>(ids.size());
+ List messages = new ArrayList<>(ids.size());
for (Integer id : ids) {
messages.add(def.getMessagesById().get(id));
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java b/src/main/java/io/mapsmessaging/mavlink/parser/ExtraCrcCalculator.java
similarity index 78%
rename from src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java
rename to src/main/java/io/mapsmessaging/mavlink/parser/ExtraCrcCalculator.java
index c213134..7502df0 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkExtraCrcCalculator.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/ExtraCrcCalculator.java
@@ -19,25 +19,25 @@
package io.mapsmessaging.mavlink.parser;
-import io.mapsmessaging.mavlink.message.MavlinkMessageDefinition;
+import io.mapsmessaging.mavlink.message.MessageDefinition;
import io.mapsmessaging.mavlink.message.X25Crc;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
import java.nio.charset.StandardCharsets;
import java.util.List;
-public final class MavlinkExtraCrcCalculator {
+public final class ExtraCrcCalculator {
- private MavlinkExtraCrcCalculator() {
+ private ExtraCrcCalculator() {
}
- public static int computeExtraCrc(MavlinkMessageDefinition messageDefinition) {
+ public static int computeExtraCrc(MessageDefinition messageDefinition) {
X25Crc crc = new X25Crc();
String messageName = messageDefinition.getName();
- List wireOrderedFields = messageDefinition.getFields();
+ List wireOrderedFields = messageDefinition.getFields();
accumulateTokenWithSpace(crc, messageName);
- for (MavlinkFieldDefinition field : wireOrderedFields) {
+ for (FieldDefinition field : wireOrderedFields) {
if (field.isExtension()) {
continue;
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkIncludeResolver.java b/src/main/java/io/mapsmessaging/mavlink/parser/IncludeResolver.java
similarity index 95%
rename from src/main/java/io/mapsmessaging/mavlink/parser/MavlinkIncludeResolver.java
rename to src/main/java/io/mapsmessaging/mavlink/parser/IncludeResolver.java
index 1bc0acf..1b525e8 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkIncludeResolver.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/IncludeResolver.java
@@ -23,6 +23,6 @@
import java.io.InputStream;
@FunctionalInterface
-public interface MavlinkIncludeResolver {
+public interface IncludeResolver {
InputStream open(String includeName) throws IOException;
}
diff --git a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java b/src/main/java/io/mapsmessaging/mavlink/parser/XmlParser.java
similarity index 75%
rename from src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
rename to src/main/java/io/mapsmessaging/mavlink/parser/XmlParser.java
index 519b3b7..0fa517f 100644
--- a/src/main/java/io/mapsmessaging/mavlink/parser/MavlinkXmlParser.java
+++ b/src/main/java/io/mapsmessaging/mavlink/parser/XmlParser.java
@@ -19,11 +19,11 @@
package io.mapsmessaging.mavlink.parser;
-import io.mapsmessaging.mavlink.message.MavlinkMessageDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumEntry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkWireType;
+import io.mapsmessaging.mavlink.message.MessageDefinition;
+import io.mapsmessaging.mavlink.message.fields.EnumDefinition;
+import io.mapsmessaging.mavlink.message.fields.EnumEntry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.WireType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -40,18 +40,18 @@
import java.util.List;
import java.util.Map;
-public class MavlinkXmlParser {
+public class XmlParser {
- public MavlinkDialectDefinition parse(InputStream inputStream, String dialectName)
+ public DialectDefinition parse(InputStream inputStream, String dialectName)
throws ParserConfigurationException, SAXException, IOException {
Document document = parseDocument(inputStream);
return parse(document, dialectName);
}
- public MavlinkDialectDefinition parse(Document document, String dialectName) {
- Map enumsByName = parseEnums(document);
- List messages = parseMessages(document);
- Map messagesById = indexMessagesById(messages);
+ public DialectDefinition parse(Document document, String dialectName) {
+ Map enumsByName = parseEnums(document);
+ List messages = parseMessages(document);
+ Map messagesById = indexMessagesById(messages);
return buildDialectDefinition(dialectName, enumsByName, messages, messagesById);
}
@@ -86,13 +86,13 @@ protected Document parseDocument(InputStream inputStream)
return document;
}
- private MavlinkDialectDefinition buildDialectDefinition(
+ private DialectDefinition buildDialectDefinition(
String dialectName,
- Map enumsByName,
- List messages,
- Map messagesById) {
+ Map enumsByName,
+ List messages,
+ Map messagesById) {
- MavlinkDialectDefinition dialectDefinition = new MavlinkDialectDefinition();
+ DialectDefinition dialectDefinition = new DialectDefinition();
dialectDefinition.setName(dialectName);
dialectDefinition.setEnumsByName(enumsByName);
dialectDefinition.setMessages(messages);
@@ -100,16 +100,16 @@ private MavlinkDialectDefinition buildDialectDefinition(
return dialectDefinition;
}
- private Map indexMessagesById(List messageDefinitions) {
- Map byId = new LinkedHashMap<>();
- for (MavlinkMessageDefinition messageDefinition : messageDefinitions) {
+ private Map indexMessagesById(List messageDefinitions) {
+ Map byId = new LinkedHashMap<>();
+ for (MessageDefinition messageDefinition : messageDefinitions) {
byId.put(messageDefinition.getMessageId(), messageDefinition);
}
return byId;
}
- private Map parseEnums(Document document) {
- Map enumMap = new LinkedHashMap<>();
+ private Map parseEnums(Document document) {
+ Map enumMap = new LinkedHashMap<>();
NodeList enumNodes = document.getElementsByTagName("enum");
for (int i = 0; i < enumNodes.getLength(); i++) {
Node node = enumNodes.item(i);
@@ -117,7 +117,7 @@ private Map parseEnums(Document document) {
continue;
}
- MavlinkEnumDefinition enumDefinition = parseEnum(enumElement);
+ EnumDefinition enumDefinition = parseEnum(enumElement);
if (enumDefinition.getName() != null && !enumDefinition.getName().isEmpty()) {
enumMap.put(enumDefinition.getName(), enumDefinition);
}
@@ -126,8 +126,8 @@ private Map parseEnums(Document document) {
return enumMap;
}
- private MavlinkEnumDefinition parseEnum(Element enumElement) {
- MavlinkEnumDefinition def = new MavlinkEnumDefinition();
+ private EnumDefinition parseEnum(Element enumElement) {
+ EnumDefinition def = new EnumDefinition();
def.setName(enumElement.getAttribute("name"));
def.setBitmask(parseBitmask(enumElement.getAttribute("bitmask")));
@@ -141,8 +141,8 @@ private boolean parseBitmask(String bitmaskValue) {
return "true".equalsIgnoreCase(bitmaskValue) || "1".equals(bitmaskValue);
}
- private List parseEnumEntries(Element enumElement) {
- List entries = new ArrayList<>();
+ private List parseEnumEntries(Element enumElement) {
+ List entries = new ArrayList<>();
NodeList children = enumElement.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
@@ -160,8 +160,8 @@ private List parseEnumEntries(Element enumElement) {
return entries;
}
- private MavlinkEnumEntry parseEnumEntry(Element entryElement) {
- MavlinkEnumEntry entry = new MavlinkEnumEntry();
+ private EnumEntry parseEnumEntry(Element entryElement) {
+ EnumEntry entry = new EnumEntry();
String valueAttribute = entryElement.getAttribute("value");
if (valueAttribute != null && !valueAttribute.isEmpty()) {
@@ -173,8 +173,8 @@ private MavlinkEnumEntry parseEnumEntry(Element entryElement) {
return entry;
}
- private List parseMessages(Document document) {
- List messages = new ArrayList<>();
+ private List parseMessages(Document document) {
+ List messages = new ArrayList<>();
NodeList messageNodes = document.getElementsByTagName("message");
for (int i = 0; i < messageNodes.getLength(); i++) {
@@ -188,20 +188,20 @@ private List parseMessages(Document document) {
return messages;
}
- private MavlinkMessageDefinition parseMessage(Element messageElement) {
- MavlinkMessageDefinition messageDefinition = new MavlinkMessageDefinition();
+ private MessageDefinition parseMessage(Element messageElement) {
+ MessageDefinition messageDefinition = new MessageDefinition();
messageDefinition.setMessageId(parseIntAttribute(messageElement, "id"));
messageDefinition.setName(messageElement.getAttribute("name"));
messageDefinition.setDescription(getFirstChildTextContent(messageElement, "description"));
- List fields = parseMessageFields(messageElement);
+ List fields = parseMessageFields(messageElement);
messageDefinition.setXmlOrderedFields(fields);
return messageDefinition;
}
- private List parseMessageFields(Element messageElement) {
- List fieldDefinitions = new ArrayList<>();
+ private List parseMessageFields(Element messageElement) {
+ List fieldDefinitions = new ArrayList<>();
NodeList childNodes = messageElement.getChildNodes();
int fieldIndex = 0;
@@ -230,8 +230,8 @@ private List parseMessageFields(Element messageElement)
return fieldDefinitions;
}
- private MavlinkFieldDefinition parseField(Element fieldElement, int fieldIndex, boolean inExtensions) {
- MavlinkFieldDefinition fieldDefinition = new MavlinkFieldDefinition();
+ private FieldDefinition parseField(Element fieldElement, int fieldIndex, boolean inExtensions) {
+ FieldDefinition fieldDefinition = new FieldDefinition();
fieldDefinition.setIndex(fieldIndex);
String rawType = fieldElement.getAttribute("type");
@@ -245,7 +245,7 @@ private MavlinkFieldDefinition parseField(Element fieldElement, int fieldIndex,
fieldDefinition.setUnits(fieldElement.getAttribute("units"));
fieldDefinition.setDescription(safeText(fieldElement));
- fieldDefinition.setWireType(MavlinkWireType.fromXmlType(rawType));
+ fieldDefinition.setWireType(WireType.fromXmlType(rawType));
fieldDefinition.setExtension(inExtensions);
String enumName = fieldElement.getAttribute("enum");
diff --git a/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java b/src/main/java/io/mapsmessaging/mavlink/schema/JsonSchemaBuilder.java
similarity index 75%
rename from src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java
rename to src/main/java/io/mapsmessaging/mavlink/schema/JsonSchemaBuilder.java
index 3379311..6ddbc91 100644
--- a/src/main/java/io/mapsmessaging/mavlink/schema/MavlinkJsonSchemaBuilder.java
+++ b/src/main/java/io/mapsmessaging/mavlink/schema/JsonSchemaBuilder.java
@@ -21,23 +21,23 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumEntry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkWireType;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.fields.EnumDefinition;
+import io.mapsmessaging.mavlink.message.fields.EnumEntry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.WireType;
import java.util.Map;
-public final class MavlinkJsonSchemaBuilder {
+public final class JsonSchemaBuilder {
- private MavlinkJsonSchemaBuilder() {
+ private JsonSchemaBuilder() {
}
public static JsonObject buildSchema(
- MavlinkCompiledMessage message,
- Map enumsByName) {
+ CompiledMessage message,
+ Map enumsByName) {
JsonObject schema = new JsonObject();
schema.addProperty("$schema", "https://json-schema.org/draft/2020-12/schema");
@@ -49,8 +49,8 @@ public static JsonObject buildSchema(
JsonObject properties = new JsonObject();
JsonArray required = new JsonArray();
- for (MavlinkCompiledField compiledField : message.getCompiledFields()) {
- MavlinkFieldDefinition field = compiledField.getFieldDefinition();
+ for (CompiledField compiledField : message.getCompiledFields()) {
+ FieldDefinition field = compiledField.getFieldDefinition();
JsonObject fieldSchema = buildFieldSchema(field, enumsByName);
properties.add(field.getName(), fieldSchema);
@@ -73,8 +73,8 @@ public static JsonObject buildSchema(
}
private static JsonObject buildFieldSchema(
- MavlinkFieldDefinition field,
- Map enumsByName) {
+ FieldDefinition field,
+ Map enumsByName) {
JsonObject schema = new JsonObject();
@@ -82,7 +82,7 @@ private static JsonObject buildFieldSchema(
schema.addProperty("description", field.getDescription());
}
- MavlinkWireType wireType = field.getWireType();
+ WireType wireType = field.getWireType();
// char[N] → string
if (field.isArray() && wireType.isChar()) {
@@ -107,11 +107,11 @@ private static JsonObject buildFieldSchema(
}
private static JsonObject scalarSchema(
- MavlinkFieldDefinition field,
- Map enumsByName) {
+ FieldDefinition field,
+ Map enumsByName) {
JsonObject schema = new JsonObject();
- MavlinkWireType wireType = field.getWireType();
+ WireType wireType = field.getWireType();
if (wireType.isFloat() || wireType.isDouble()) {
schema.addProperty("type", "number");
@@ -120,7 +120,7 @@ private static JsonObject scalarSchema(
}
if (field.getEnumName() != null) {
- MavlinkEnumDefinition enumDef = enumsByName.get(field.getEnumName());
+ EnumDefinition enumDef = enumsByName.get(field.getEnumName());
if (enumDef != null) {
applyEnum(schema, enumDef);
}
@@ -131,7 +131,7 @@ private static JsonObject scalarSchema(
private static void applyEnum(
JsonObject schema,
- MavlinkEnumDefinition enumDef) {
+ EnumDefinition enumDef) {
schema.addProperty("x-enum-name", enumDef.getName());
@@ -142,7 +142,7 @@ private static void applyEnum(
}
JsonArray oneOf = new JsonArray();
- for (MavlinkEnumEntry entry : enumDef.getEntries()) {
+ for (EnumEntry entry : enumDef.getEntries()) {
JsonObject option = new JsonObject();
option.addProperty("const", entry.getValue());
option.addProperty("title", entry.getName());
diff --git a/src/main/java/io/mapsmessaging/mavlink/signing/MapSigningKeyProvider.java b/src/main/java/io/mapsmessaging/mavlink/signing/MapSigningKeyProvider.java
new file mode 100644
index 0000000..7c7f851
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/signing/MapSigningKeyProvider.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.mapsmessaging.mavlink.signing;
+
+import io.mapsmessaging.mavlink.framing.SigningKeyProvider;
+import lombok.Value;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class MapSigningKeyProvider implements SigningKeyProvider {
+
+ private final Map signingKeys;
+
+ public MapSigningKeyProvider() {
+ signingKeys = new ConcurrentHashMap<>();
+ }
+
+ public void register(int systemId, int componentId, int linkId, byte[] signature) {
+ SigningKey signingKey = new SigningKey(systemId, componentId, linkId);
+ signingKeys.put(signingKey, signature);
+ }
+
+ public void unregister(int systemId, int componentId, int linkId) {
+ signingKeys.remove(new SigningKey(systemId, componentId, linkId));
+
+ }
+
+ @Override
+ public boolean canValidate() {
+ return true;
+ }
+
+ @Override
+ public byte[] getSigningKey(int systemId, int componentId, int linkId) {
+ SigningKey signingKey = new SigningKey(systemId, componentId, linkId);
+ return signingKeys.get(signingKey);
+ }
+
+ @Value
+ private static class SigningKey{
+ int systemId;
+ int componentId;
+ int linkId;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/mapsmessaging/mavlink/signing/NoSigningKeyProvider.java b/src/main/java/io/mapsmessaging/mavlink/signing/NoSigningKeyProvider.java
new file mode 100644
index 0000000..47199ef
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/signing/NoSigningKeyProvider.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.mapsmessaging.mavlink.signing;
+
+import io.mapsmessaging.mavlink.framing.SigningKeyProvider;
+
+public class NoSigningKeyProvider implements SigningKeyProvider {
+ @Override
+ public boolean canValidate() {
+ return false;
+ }
+
+ @Override
+ public byte[] getSigningKey(int systemId, int componentId, int linkId) {
+ return new byte[0];
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/signing/StaticSigningKeyProvider.java b/src/main/java/io/mapsmessaging/mavlink/signing/StaticSigningKeyProvider.java
new file mode 100644
index 0000000..4d275c9
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/signing/StaticSigningKeyProvider.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright [ 2020 - 2024 ] Matthew Buckton
+ * Copyright [ 2024 - 2026 ] MapsMessaging B.V.
+ *
+ * Licensed under the Apache License, Version 2.0 with the Commons Clause
+ * (the "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * https://commonsclause.com/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.mapsmessaging.mavlink.signing;
+
+
+import io.mapsmessaging.mavlink.framing.SigningKeyProvider;
+
+import java.util.Arrays;
+
+public final class StaticSigningKeyProvider implements SigningKeyProvider {
+
+ private final byte[] signingKey;
+
+ public StaticSigningKeyProvider(byte[] signingKey) {
+ if (signingKey == null) {
+ throw new IllegalArgumentException("signingKey must not be null");
+ }
+ if (signingKey.length != 32) {
+ throw new IllegalArgumentException("signingKey must be 32 bytes");
+ }
+ this.signingKey = Arrays.copyOf(signingKey, signingKey.length);
+ }
+
+ @Override
+ public boolean canValidate() {
+ return true;
+ }
+
+ @Override
+ public byte[] getSigningKey(int systemId, int componentId, int linkId) {
+ return Arrays.copyOf(signingKey, signingKey.length);
+ }
+}
diff --git a/src/test/java/io/mapsmessaging/mavlink/BaseRoudTripTest.java b/src/test/java/io/mapsmessaging/mavlink/BaseRoudTripTest.java
index b544bed..f558f3f 100644
--- a/src/test/java/io/mapsmessaging/mavlink/BaseRoudTripTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/BaseRoudTripTest.java
@@ -19,12 +19,12 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkEnumEntry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.fields.EnumDefinition;
+import io.mapsmessaging.mavlink.message.fields.EnumEntry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@@ -49,18 +49,18 @@ static final class RandomValueFactory {
protected RandomValueFactory() {}
static Map buildValues(
- MavlinkMessageRegistry registry,
- MavlinkCompiledMessage msg,
+ MessageRegistry registry,
+ CompiledMessage msg,
MavlinkRoundTripAllMessagesTest.ExtensionMode extensionMode,
long baseSeed
) throws IOException {
Map values = new LinkedHashMap<>();
- List fields = msg.getCompiledFields();
+ List fields = msg.getCompiledFields();
for (int i = 0; i < fields.size(); i++) {
- MavlinkCompiledField cf = fields.get(i);
- MavlinkFieldDefinition fd = MavlinkTestSupport.fieldDefinition(cf);
+ CompiledField cf = fields.get(i);
+ FieldDefinition fd = MavlinkTestSupport.fieldDefinition(cf);
if (fd.isExtension() && extensionMode == MavlinkRoundTripAllMessagesTest.ExtensionMode.OMIT_ALL) {
continue;
@@ -82,9 +82,9 @@ static Map buildValues(
return values;
}
- static MavlinkFieldDefinition fieldByName(MavlinkCompiledMessage msg, String fieldName) {
- for (MavlinkCompiledField cf : msg.getCompiledFields()) {
- MavlinkFieldDefinition fd = MavlinkTestSupport.fieldDefinition(cf);
+ static FieldDefinition fieldByName(CompiledMessage msg, String fieldName) {
+ for (CompiledField cf : msg.getCompiledFields()) {
+ FieldDefinition fd = MavlinkTestSupport.fieldDefinition(cf);
if (fieldName.equals(fd.getName())) {
return fd;
}
@@ -93,9 +93,9 @@ static MavlinkFieldDefinition fieldByName(MavlinkCompiledMessage msg, String fie
}
protected static Object generateValueForField(
- MavlinkMessageRegistry registry,
+ MessageRegistry registry,
int messageId,
- MavlinkFieldDefinition fd,
+ FieldDefinition fd,
int fieldIndex,
long baseSeed
) throws IOException {
@@ -117,10 +117,10 @@ protected static Object generateValueForField(
return generateScalar(registry, fd, random);
}
- protected static Object generateScalar(MavlinkMessageRegistry registry, MavlinkFieldDefinition fd, Random random) throws IOException {
+ protected static Object generateScalar(MessageRegistry registry, FieldDefinition fd, Random random) throws IOException {
String enumName = fd.getEnumName();
if (enumName != null && !enumName.isEmpty()) {
- MavlinkEnumDefinition def = registry.getEnumsByName().get(enumName);
+ EnumDefinition def = registry.getEnumsByName().get(enumName);
if (def != null && def.getEntries() != null && !def.getEntries().isEmpty()) {
if (def.isBitmask()) {
return pickBitmask(def, random);
@@ -155,25 +155,25 @@ protected static Object generateScalar(MavlinkMessageRegistry registry, MavlinkF
};
}
- protected static long pickEnumValue(MavlinkEnumDefinition def, Random random) {
- List entries = def.getEntries();
- MavlinkEnumEntry entry = entries.get(random.nextInt(entries.size()));
+ protected static long pickEnumValue(EnumDefinition def, Random random) {
+ List entries = def.getEntries();
+ EnumEntry entry = entries.get(random.nextInt(entries.size()));
return entry.getValue();
}
- protected static long pickBitmask(MavlinkEnumDefinition def, Random random) {
- List entries = def.getEntries();
+ protected static long pickBitmask(EnumDefinition def, Random random) {
+ List entries = def.getEntries();
int count = Math.min(entries.size(), 1 + random.nextInt(3));
long mask = 0L;
for (int i = 0; i < count; i++) {
- MavlinkEnumEntry entry = entries.get(random.nextInt(entries.size()));
+ EnumEntry entry = entries.get(random.nextInt(entries.size()));
mask |= entry.getValue();
}
return mask;
}
- protected static boolean isCharType(MavlinkFieldDefinition fd) {
+ protected static boolean isCharType(FieldDefinition fd) {
String type = normalizeType(fd.getType());
return "char".equals(type);
}
@@ -253,10 +253,10 @@ static final class ValueAssertions {
protected ValueAssertions() {}
static void assertFieldEquals(
- MavlinkFieldDefinition fd,
+ FieldDefinition fd,
Object expected,
Object actual,
- MavlinkCompiledMessage msg
+ CompiledMessage msg
) {
String type = RandomValueFactory.normalizeType(fd.getType());
diff --git a/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java b/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
index dc5343c..dd446fe 100644
--- a/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/HeartbeatTest.java
@@ -19,7 +19,7 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
+import io.mapsmessaging.mavlink.message.Frame;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -284,10 +284,10 @@ void validateTruncatedPackets() throws Exception {
for (int i = 0; i < frames.size(); i++) {
ByteBuffer input = ByteBuffer.wrap(toByteArray(frames.get(i)));
- Optional frame = frameCodec.tryUnpackFrame(input);
+ Optional frame = frameCodec.tryUnpackFrame(input);
Assertions.assertTrue(frame.isPresent(), "Frame #" + i + " did not unpack. Remaining=" + input.remaining());
- MavlinkFrame payloadFrame = frame.get();
+ Frame payloadFrame = frame.get();
Map obj = payloadCodec.parsePayload(payloadFrame.getMessageId(), payloadFrame.getPayload());
Assertions.assertTrue(!obj.isEmpty());
}
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
index 9963b40..f2739b0 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkFrameRoundTripAllMessagesTest.java
@@ -19,41 +19,69 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkFrame;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.MavlinkVersion;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.Frame;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.Version;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.signing.MapSigningKeyProvider;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.Optional;
+import java.util.Random;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
class MavlinkFrameRoundTripAllMessagesTest extends BaseRoudTripTest {
+ private static final byte[] TEST_SIGNING_KEY = buildTestSigningKey();
+
+ private static byte[] buildTestSigningKey() {
+ Random random = new Random();
+ byte[] key = new byte[32];
+ random.nextBytes(key);
+ return key;
+ }
+
@TestFactory
- Stream allMessages_frame_roundTrip_v2_fullPayload() throws Exception {
+ Stream allMessages_frame_roundTrip_v2_unsigned_fullPayload() throws Exception {
+ return buildRoundTripTests(false);
+ }
+
+ @TestFactory
+ Stream allMessages_frame_roundTrip_v2_signed_fullPayload() throws Exception {
+ return buildRoundTripTests(true);
+ }
+
+ private Stream buildRoundTripTests(boolean signFrames) throws Exception {
MavlinkCodec payloadCodec = MavlinkTestSupport.codec();
- MavlinkFrameCodec frameCodec = new MavlinkFrameCodec(payloadCodec);
- MavlinkMessageRegistry registry = payloadCodec.getRegistry();
+
+
+ MapSigningKeyProvider signingKeyProvider = new MapSigningKeyProvider();
+ signingKeyProvider.register (1, 1, 0, TEST_SIGNING_KEY);
+ MavlinkFrameCodec frameCodec = new MavlinkFrameCodec(payloadCodec, signingKeyProvider);
+
+ MessageRegistry registry = payloadCodec.getRegistry();
+
+ String suffix = signFrames ? "signed" : "unsigned";
return registry.getCompiledMessages().stream()
.map(msg -> DynamicTest.dynamicTest(
- msg.getMessageId() + " " + msg.getName(),
- () -> frameRoundTripForMessageV2(frameCodec, payloadCodec, registry, msg)
+ msg.getMessageId() + " " + msg.getName() + " (" + suffix + ")",
+ () -> frameRoundTripForMessageV2(frameCodec, payloadCodec, registry, msg, signFrames)
));
}
private static void frameRoundTripForMessageV2(
MavlinkFrameCodec frameCodec,
MavlinkCodec payloadCodec,
- MavlinkMessageRegistry registry,
- MavlinkCompiledMessage msg
+ MessageRegistry registry,
+ CompiledMessage msg,
+ boolean signFrame
) throws Exception {
Map values =
@@ -62,8 +90,8 @@ private static void frameRoundTripForMessageV2(
byte[] payload = payloadCodec.encodePayload(msg.getMessageId(), values);
assertNotNull(payload);
- MavlinkFrame frame = new MavlinkFrame();
- frame.setVersion(MavlinkVersion.V2);
+ Frame frame = new Frame();
+ frame.setVersion(Version.V2);
frame.setSequence(42);
frame.setSystemId(1);
frame.setComponentId(1);
@@ -71,8 +99,8 @@ private static void frameRoundTripForMessageV2(
frame.setPayload(payload);
frame.setPayloadLength(payload.length);
- frame.setSigned(false);
- frame.setIncompatibilityFlags((byte) 0);
+ frame.setSigned(signFrame);
+ frame.setIncompatibilityFlags(signFrame ? (byte) 1 : (byte) 0);
frame.setCompatibilityFlags((byte) 0);
frame.setSignature(null);
@@ -84,10 +112,22 @@ private static void frameRoundTripForMessageV2(
ByteBuffer networkOwned = ByteBuffer.allocate(out.remaining() + 16);
networkOwned.put(out);
networkOwned.flip();
- Optional decodedOpt = frameCodec.tryUnpackFrame(networkOwned);
+
+ Optional decodedOpt = frameCodec.tryUnpackFrame(networkOwned);
assertTrue(decodedOpt.isPresent(), "Expected to decode a frame");
- MavlinkFrame decoded = decodedOpt.get();
+ Frame decoded = decodedOpt.get();
+
+ if (signFrame) {
+ assertTrue(decoded.isSigned(), "Expected signed frame");
+ assertTrue(decoded.isValidated(), "Expected signature validation to succeed");
+ assertNotNull(decoded.getSignature(), "Expected signature bytes");
+ assertEquals(13, decoded.getSignature().length, "Expected 13-byte MAVLink v2 signature block");
+ } else {
+ assertFalse(decoded.isSigned(), "Expected unsigned frame");
+ assertFalse(decoded.isValidated(), "Expected validated=false for unsigned frame");
+ assertNull(decoded.getSignature(), "Expected signature to be null for unsigned frame");
+ }
assertEquals(frame.getVersion(), decoded.getVersion());
assertEquals(frame.getSequence(), decoded.getSequence());
@@ -106,8 +146,8 @@ private static void frameRoundTripForMessageV2(
Object actual = output.get(fieldName);
assertNotNull(actual, "Missing field after decode: " + fieldName);
- MavlinkFieldDefinition fd = RandomValueFactory.fieldByName(msg, fieldName);
- ValueAssertions.assertFieldEquals(fd, expected, actual, msg);
+ FieldDefinition fieldDefinition = RandomValueFactory.fieldByName(msg, fieldName);
+ ValueAssertions.assertFieldEquals(fieldDefinition, expected, actual, msg);
}
}
}
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
index a3cfad9..73018ec 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkPayloadJsonSchemaValidationTest.java
@@ -28,8 +28,9 @@
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.SpecVersion;
import com.networknt.schema.ValidationMessage;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.schema.JsonSchemaBuilder;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
@@ -47,7 +48,7 @@ class MavlinkPayloadJsonSchemaValidationTest extends BaseRoudTripTest {
@TestFactory
Stream allMessages_payload_toJson_validatesAgainstSchema() throws Exception {
MavlinkCodec payloadCodec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = payloadCodec.getRegistry();
+ MessageRegistry registry = payloadCodec.getRegistry();
return registry.getCompiledMessages().stream()
.map(msg -> DynamicTest.dynamicTest(
@@ -58,8 +59,8 @@ Stream allMessages_payload_toJson_validatesAgainstSchema() throws E
private static void payloadToJsonValidates(
MavlinkCodec payloadCodec,
- MavlinkMessageRegistry registry,
- MavlinkCompiledMessage msg
+ MessageRegistry registry,
+ CompiledMessage msg
) throws Exception {
Map values =
@@ -75,7 +76,7 @@ private static void payloadToJsonValidates(
// Build schema for this message
JsonObject schemaObject =
- io.mapsmessaging.mavlink.schema.MavlinkJsonSchemaBuilder.buildSchema(msg, registry.getEnumsByName());
+ JsonSchemaBuilder.buildSchema(msg, registry.getEnumsByName());
JsonSchema schema = compileSchema(schemaObject);
Set errors = schema.validate(toJsonNode(jsonObject));
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkRoundTripAllMessagesTest.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkRoundTripAllMessagesTest.java
index 9fc0f20..3bc0c09 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkRoundTripAllMessagesTest.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkRoundTripAllMessagesTest.java
@@ -19,10 +19,10 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
@@ -38,7 +38,7 @@ class MavlinkRoundTripAllMessagesTest extends BaseRoudTripTest {
@TestFactory
Stream allMessages_baseFields_roundTrip() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
return registry.getCompiledMessages().stream()
.map(msg -> DynamicTest.dynamicTest(
@@ -50,7 +50,7 @@ Stream allMessages_baseFields_roundTrip() throws Exception {
@TestFactory
Stream allMessages_extensions_omitted_vs_present_payloadSizing() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
return registry.getCompiledMessages().stream()
.filter(msg -> msg.getCompiledFields().stream().anyMatch(cf -> MavlinkTestSupport.fieldDefinition(cf).isExtension()))
@@ -63,7 +63,7 @@ Stream allMessages_extensions_omitted_vs_present_payloadSizing() th
@TestFactory
Stream parallel_encode_decode_sanity_no_shared_state_per_message() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
int threads = Math.max(2, Runtime.getRuntime().availableProcessors() / 2);
int tasksPerMessage = 8; // tune: enough to shake shared state without being silly
@@ -77,8 +77,8 @@ Stream parallel_encode_decode_sanity_no_shared_state_per_message()
private static void runParallelRoundTrips(
MavlinkCodec codec,
- MavlinkMessageRegistry registry,
- MavlinkCompiledMessage msg,
+ MessageRegistry registry,
+ CompiledMessage msg,
int threads,
int tasksPerMessage
) throws Exception {
@@ -107,7 +107,7 @@ private static void runParallelRoundTrips(
fail("Missing field after decode: message " + msg.getMessageId() + " (" + msg.getName() + ") field=" + fieldName);
}
- MavlinkFieldDefinition fd = RandomValueFactory.fieldByName(msg, fieldName);
+ FieldDefinition fd = RandomValueFactory.fieldByName(msg, fieldName);
ValueAssertions.assertFieldEquals(fd, expected, actual, msg);
}
return null;
@@ -124,8 +124,8 @@ private static void runParallelRoundTrips(
}
private static void roundTripForMessage(
MavlinkCodec codec,
- MavlinkMessageRegistry registry,
- MavlinkCompiledMessage msg,
+ MessageRegistry registry,
+ CompiledMessage msg,
ExtensionMode extensionMode
) throws Exception {
@@ -150,15 +150,15 @@ private static void roundTripForMessage(
fail("Missing field after decode for message " + msg.getMessageId() + " (" + msg.getName() + "): " + fieldName);
}
- MavlinkFieldDefinition fd = RandomValueFactory.fieldByName(msg, fieldName);
+ FieldDefinition fd = RandomValueFactory.fieldByName(msg, fieldName);
ValueAssertions.assertFieldEquals(fd, expected, actual, msg);
}
}
private static void extensionSizingForMessage(
MavlinkCodec codec,
- MavlinkMessageRegistry registry,
- MavlinkCompiledMessage msg
+ MessageRegistry registry,
+ CompiledMessage msg
) throws Exception {
int baseSize = PayloadSizing.computeBaseSize(msg);
@@ -181,7 +181,7 @@ private static void extensionSizingForMessage(
Object actual = decoded.get(name);
assertNotNull(actual, "Missing base field after extension decode: " + name);
- MavlinkFieldDefinition fd = RandomValueFactory.fieldByName(msg, name);
+ FieldDefinition fd = RandomValueFactory.fieldByName(msg, name);
ValueAssertions.assertFieldEquals(fd, expected, actual, msg);
}
}
@@ -195,10 +195,10 @@ static final class PayloadSizing {
private PayloadSizing() {}
- static int computeBaseSize(MavlinkCompiledMessage msg) {
+ static int computeBaseSize(CompiledMessage msg) {
int size = 0;
- for (MavlinkCompiledField cf : msg.getCompiledFields()) {
- MavlinkFieldDefinition fd = MavlinkTestSupport.fieldDefinition(cf);
+ for (CompiledField cf : msg.getCompiledFields()) {
+ FieldDefinition fd = MavlinkTestSupport.fieldDefinition(cf);
if (fd.isExtension()) {
break;
}
diff --git a/src/test/java/io/mapsmessaging/mavlink/MavlinkTestSupport.java b/src/test/java/io/mapsmessaging/mavlink/MavlinkTestSupport.java
index 6093702..a6e3566 100644
--- a/src/test/java/io/mapsmessaging/mavlink/MavlinkTestSupport.java
+++ b/src/test/java/io/mapsmessaging/mavlink/MavlinkTestSupport.java
@@ -19,10 +19,10 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
import java.lang.reflect.Field;
import java.util.Comparator;
@@ -40,23 +40,23 @@ public static MavlinkCodec codec() throws Exception {
return loader.getDialectOrThrow("common");
}
- public static MavlinkMessageRegistry registry(MavlinkCodec codec) {
+ public static MessageRegistry registry(MavlinkCodec codec) {
return codec.getRegistry();
}
- public static MavlinkFieldDefinition fieldDefinition(MavlinkCompiledField compiledField) {
+ public static FieldDefinition fieldDefinition(CompiledField compiledField) {
try {
- Field field = MavlinkCompiledField.class.getDeclaredField("fieldDefinition");
+ Field field = CompiledField.class.getDeclaredField("fieldDefinition");
field.setAccessible(true);
- return (MavlinkFieldDefinition) field.get(compiledField);
+ return (FieldDefinition) field.get(compiledField);
} catch (Exception exception) {
throw new IllegalStateException("Cannot access MavlinkCompiledField.fieldDefinition", exception);
}
}
- public static int offset(MavlinkCompiledField compiledField) {
+ public static int offset(CompiledField compiledField) {
try {
- Field field = MavlinkCompiledField.class.getDeclaredField("offsetInPayload");
+ Field field = CompiledField.class.getDeclaredField("offsetInPayload");
field.setAccessible(true);
return (int) field.get(compiledField);
} catch (Exception exception) {
@@ -64,9 +64,9 @@ public static int offset(MavlinkCompiledField compiledField) {
}
}
- public static int size(MavlinkCompiledField compiledField) {
+ public static int size(CompiledField compiledField) {
try {
- Field field = MavlinkCompiledField.class.getDeclaredField("sizeInBytes");
+ Field field = CompiledField.class.getDeclaredField("sizeInBytes");
field.setAccessible(true);
return (int) field.get(compiledField);
} catch (Exception exception) {
@@ -74,33 +74,33 @@ public static int size(MavlinkCompiledField compiledField) {
}
}
- public static Optional firstMessageWithExtensions(MavlinkMessageRegistry registry) {
+ public static Optional firstMessageWithExtensions(MessageRegistry registry) {
return registry.getCompiledMessages().stream()
.filter(message -> message.getCompiledFields().stream().anyMatch(field -> fieldDefinition(field).isExtension()))
.findFirst();
}
- public static Optional firstMessageWithArray(MavlinkMessageRegistry registry) {
+ public static Optional firstMessageWithArray(MessageRegistry registry) {
return registry.getCompiledMessages().stream()
.filter(message -> message.getCompiledFields().stream().anyMatch(field -> fieldDefinition(field).isArray()))
.findFirst();
}
- public static Optional firstMessageWithEnum(MavlinkMessageRegistry registry) {
+ public static Optional firstMessageWithEnum(MessageRegistry registry) {
return registry.getCompiledMessages().stream()
.filter(message -> message.getCompiledFields().stream().anyMatch(field -> {
- MavlinkFieldDefinition definition = fieldDefinition(field);
+ FieldDefinition definition = fieldDefinition(field);
String enumName = definition.getEnumName();
return enumName != null && !enumName.isEmpty();
}))
.findFirst();
}
- public static Map payloadWithScalar(MavlinkFieldDefinition field, Number value) {
+ public static Map payloadWithScalar(FieldDefinition field, Number value) {
return Map.of(field.getName(), value);
}
- public static Map payloadWithArrayFilled(MavlinkFieldDefinition field, Number value) {
+ public static Map payloadWithArrayFilled(FieldDefinition field, Number value) {
int arrayLength = field.getArrayLength();
List list = java.util.stream.IntStream.range(0, arrayLength)
.mapToObj(index -> value)
@@ -108,7 +108,7 @@ public static Map payloadWithArrayFilled(MavlinkFieldDefinition
return Map.of(field.getName(), list);
}
- public static List fieldsSortedByOffset(MavlinkCompiledMessage message) {
+ public static List fieldsSortedByOffset(CompiledMessage message) {
return message.getCompiledFields().stream()
.sorted(Comparator.comparingInt(MavlinkTestSupport::offset))
.toList();
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkCharArrays.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkCharArrays.java
index c0b1d74..bbacea6 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkCharArrays.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkCharArrays.java
@@ -19,11 +19,11 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkWireType;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.WireType;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -39,18 +39,18 @@ class TestMavlinkCharArrays {
@Test
void charArray_stringIsTruncatedAndNullPadded() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
- MavlinkCompiledMessage message = MavlinkTestSupport.firstMessageWithArray(registry)
+ CompiledMessage message = MavlinkTestSupport.firstMessageWithArray(registry)
.orElseThrow(() -> new IllegalStateException("No message with array fields found"));
- MavlinkCompiledField charArrayField = findFirstCharArrayField(message);
+ CompiledField charArrayField = findFirstCharArrayField(message);
if (charArrayField == null) {
return; // no char arrays in this dialect revision, skip
}
int messageId = message.getMessageId();
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(charArrayField);
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(charArrayField);
String longText = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Map values = new HashMap<>();
@@ -85,18 +85,18 @@ void charArray_stringIsTruncatedAndNullPadded() throws Exception {
@Test
void charArray_byteArrayAccepted() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
- MavlinkCompiledMessage message = MavlinkTestSupport.firstMessageWithArray(registry)
+ CompiledMessage message = MavlinkTestSupport.firstMessageWithArray(registry)
.orElseThrow(() -> new IllegalStateException("No message with array fields found"));
- MavlinkCompiledField charArrayField = findFirstCharArrayField(message);
+ CompiledField charArrayField = findFirstCharArrayField(message);
if (charArrayField == null) {
return;
}
int messageId = message.getMessageId();
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(charArrayField);
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(charArrayField);
byte[] input = "HELLO".getBytes(StandardCharsets.UTF_8);
@@ -111,11 +111,11 @@ void charArray_byteArrayAccepted() throws Exception {
Assertions.assertNotNull(decoded.get(fieldDefinition.getName()));
}
- private MavlinkCompiledField findFirstCharArrayField(MavlinkCompiledMessage message) {
- List fields = message.getCompiledFields();
- for (MavlinkCompiledField compiledField : fields) {
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(compiledField);
- if (fieldDefinition.isArray() && fieldDefinition.getWireType() == MavlinkWireType.CHAR) {
+ private CompiledField findFirstCharArrayField(CompiledMessage message) {
+ List fields = message.getCompiledFields();
+ for (CompiledField compiledField : fields) {
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(compiledField);
+ if (fieldDefinition.isArray() && fieldDefinition.getWireType() == WireType.CHAR) {
return compiledField;
}
}
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkExtensions.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkExtensions.java
index 962d0ff..562a278 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkExtensions.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkExtensions.java
@@ -19,10 +19,10 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -35,17 +35,17 @@ class TestMavlinkExtensions {
@Test
void extensionFields_omitted_doNotIncreasePayloadSize() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
- MavlinkCompiledMessage message = MavlinkTestSupport.firstMessageWithExtensions(registry)
+ CompiledMessage message = MavlinkTestSupport.firstMessageWithExtensions(registry)
.orElseThrow(() -> new IllegalStateException("No message with extensions found in dialect"));
int messageId = message.getMessageId();
- List compiledFields = message.getCompiledFields();
+ List compiledFields = message.getCompiledFields();
int baseSize = 0;
- for (MavlinkCompiledField compiledField : compiledFields) {
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(compiledField);
+ for (CompiledField compiledField : compiledFields) {
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(compiledField);
if (fieldDefinition.isExtension()) {
break;
}
@@ -60,13 +60,13 @@ void extensionFields_omitted_doNotIncreasePayloadSize() throws Exception {
@Test
void extensionFields_present_extendPayloadToLastPresentExtension() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
- MavlinkCompiledMessage message = MavlinkTestSupport.firstMessageWithExtensions(registry)
+ CompiledMessage message = MavlinkTestSupport.firstMessageWithExtensions(registry)
.orElseThrow(() -> new IllegalStateException("No message with extensions found in dialect"));
int messageId = message.getMessageId();
- List fields = message.getCompiledFields();
+ List fields = message.getCompiledFields();
int firstExtensionIndex = -1;
int lastExtensionIndex = -1;
@@ -82,8 +82,8 @@ void extensionFields_present_extendPayloadToLastPresentExtension() throws Except
Assertions.assertTrue(firstExtensionIndex >= 0, "Expected at least one extension field");
- MavlinkCompiledField firstExtensionField = fields.get(firstExtensionIndex);
- MavlinkFieldDefinition firstExtensionDefinition = MavlinkTestSupport.fieldDefinition(firstExtensionField);
+ CompiledField firstExtensionField = fields.get(firstExtensionIndex);
+ FieldDefinition firstExtensionDefinition = MavlinkTestSupport.fieldDefinition(firstExtensionField);
Map values = new HashMap<>();
values.put(firstExtensionDefinition.getName(), numericSampleValue(firstExtensionDefinition));
@@ -92,8 +92,8 @@ void extensionFields_present_extendPayloadToLastPresentExtension() throws Except
int expectedSize = 0;
for (int index = 0; index < fields.size(); index++) {
- MavlinkCompiledField compiledField = fields.get(index);
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(compiledField);
+ CompiledField compiledField = fields.get(index);
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(compiledField);
expectedSize += MavlinkTestSupport.size(compiledField);
@@ -106,8 +106,8 @@ void extensionFields_present_extendPayloadToLastPresentExtension() throws Except
"Payload should extend exactly through the last included extension field for message " + messageId);
if (lastExtensionIndex > firstExtensionIndex) {
- MavlinkCompiledField lastExtensionField = fields.get(lastExtensionIndex);
- MavlinkFieldDefinition lastExtensionDefinition = MavlinkTestSupport.fieldDefinition(lastExtensionField);
+ CompiledField lastExtensionField = fields.get(lastExtensionIndex);
+ FieldDefinition lastExtensionDefinition = MavlinkTestSupport.fieldDefinition(lastExtensionField);
Map later = new HashMap<>();
later.put(lastExtensionDefinition.getName(), numericSampleValue(lastExtensionDefinition));
@@ -127,13 +127,13 @@ void extensionFields_present_extendPayloadToLastPresentExtension() throws Except
@Test
void extensionFields_middleOmitted_zeroFilledIfLaterExtensionPresent() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
- MavlinkCompiledMessage message = MavlinkTestSupport.firstMessageWithExtensions(registry)
+ CompiledMessage message = MavlinkTestSupport.firstMessageWithExtensions(registry)
.orElseThrow(() -> new IllegalStateException("No message with extensions found in dialect"));
int messageId = message.getMessageId();
- List fields = message.getCompiledFields();
+ List fields = message.getCompiledFields();
List extensionIndexes = new java.util.ArrayList<>();
for (int index = 0; index < fields.size(); index++) {
@@ -149,7 +149,7 @@ void extensionFields_middleOmitted_zeroFilledIfLaterExtensionPresent() throws Ex
int earlierIndex = extensionIndexes.get(0);
int laterIndex = extensionIndexes.get(extensionIndexes.size() - 1);
- MavlinkFieldDefinition later = MavlinkTestSupport.fieldDefinition(fields.get(laterIndex));
+ FieldDefinition later = MavlinkTestSupport.fieldDefinition(fields.get(laterIndex));
Map values = new HashMap<>();
values.put(later.getName(), numericSampleValue(later));
@@ -170,7 +170,7 @@ void extensionFields_middleOmitted_zeroFilledIfLaterExtensionPresent() throws Ex
Assertions.assertNotNull(decoded);
}
- private Number numericSampleValue(MavlinkFieldDefinition fieldDefinition) {
+ private Number numericSampleValue(FieldDefinition fieldDefinition) {
// We don't know the exact wire type here without importing codec internals,
// but for most numeric fields a small positive int is safe.
return 1;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkNumericArrays.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkNumericArrays.java
index 35f76bc..f63ab8b 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkNumericArrays.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkNumericArrays.java
@@ -20,12 +20,11 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
-import io.mapsmessaging.mavlink.message.fields.MavlinkWireType;
-import org.junit.jupiter.api.Assertions;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
+import io.mapsmessaging.mavlink.message.fields.WireType;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
@@ -40,18 +39,18 @@ class TestMavlinkNumericArrays {
@Test
void numericArray_listShorterThanLength_zeroPadsRemainder() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
- MavlinkCompiledMessage message = MavlinkTestSupport.firstMessageWithArray(registry)
+ CompiledMessage message = MavlinkTestSupport.firstMessageWithArray(registry)
.orElseThrow(() -> new IllegalStateException("No message with array fields found"));
- MavlinkCompiledField numericArray = findFirstNumericArrayField(message);
+ CompiledField numericArray = findFirstNumericArrayField(message);
if (numericArray == null) {
return;
}
int messageId = message.getMessageId();
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(numericArray);
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(numericArray);
List shortList = List.of(1, 2);
@@ -71,18 +70,18 @@ void numericArray_listShorterThanLength_zeroPadsRemainder() throws Exception {
@Test
void numericArray_listLongerThanLength_isTruncated() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
- MavlinkCompiledMessage message = MavlinkTestSupport.firstMessageWithArray(registry)
+ CompiledMessage message = MavlinkTestSupport.firstMessageWithArray(registry)
.orElseThrow(() -> new IllegalStateException("No message with array fields found"));
- MavlinkCompiledField numericArray = findFirstNumericArrayField(message);
+ CompiledField numericArray = findFirstNumericArrayField(message);
if (numericArray == null) {
return;
}
int messageId = message.getMessageId();
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(numericArray);
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(numericArray);
int length = fieldDefinition.getArrayLength();
@@ -102,16 +101,16 @@ void numericArray_listLongerThanLength_isTruncated() throws Exception {
assertNotNull(decoded.get(fieldDefinition.getName()));
}
- private MavlinkCompiledField findFirstNumericArrayField(MavlinkCompiledMessage message) {
- for (MavlinkCompiledField compiledField : message.getCompiledFields()) {
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(compiledField);
+ private CompiledField findFirstNumericArrayField(CompiledMessage message) {
+ for (CompiledField compiledField : message.getCompiledFields()) {
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(compiledField);
if (!fieldDefinition.isArray()) {
continue;
}
if (fieldDefinition.getWireType() == null) {
continue;
}
- if (fieldDefinition.getWireType() == MavlinkWireType.CHAR) {
+ if (fieldDefinition.getWireType() == WireType.CHAR) {
continue;
}
return compiledField;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRegistryInvariants.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRegistryInvariants.java
index a7ce7a0..b9aba8f 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRegistryInvariants.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRegistryInvariants.java
@@ -19,10 +19,10 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledField;
-import io.mapsmessaging.mavlink.message.MavlinkCompiledMessage;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
-import io.mapsmessaging.mavlink.message.fields.MavlinkFieldDefinition;
+import io.mapsmessaging.mavlink.message.CompiledField;
+import io.mapsmessaging.mavlink.message.CompiledMessage;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
+import io.mapsmessaging.mavlink.message.fields.FieldDefinition;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -34,11 +34,11 @@ class TestMavlinkRegistryInvariants {
@Test
void registryHasNoDuplicateMessageIdsAndLooksSane() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = MavlinkTestSupport.registry(codec);
+ MessageRegistry registry = MavlinkTestSupport.registry(codec);
Assertions.assertEquals("common", codec.getName());
- List messages = registry.getCompiledMessages();
+ List messages = registry.getCompiledMessages();
Assertions.assertNotNull(messages);
Assertions.assertTrue(
messages.size() >= 220 && messages.size() <= 260,
@@ -46,7 +46,7 @@ void registryHasNoDuplicateMessageIdsAndLooksSane() throws Exception {
);
Set ids = new HashSet<>();
- for (MavlinkCompiledMessage message : messages) {
+ for (CompiledMessage message : messages) {
Assertions.assertTrue(ids.add(message.getMessageId()), "Duplicate messageId: " + message.getMessageId());
Assertions.assertNotNull(message.getName());
Assertions.assertTrue(message.getPayloadSizeBytes() >= 0);
@@ -63,14 +63,14 @@ void registryHasNoDuplicateMessageIdsAndLooksSane() throws Exception {
@Test
void compiledFieldLayoutIsMonotonicAndMatchesPayloadSize() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = MavlinkTestSupport.registry(codec);
+ MessageRegistry registry = MavlinkTestSupport.registry(codec);
- for (MavlinkCompiledMessage message : registry.getCompiledMessages()) {
- List fields = MavlinkTestSupport.fieldsSortedByOffset(message);
+ for (CompiledMessage message : registry.getCompiledMessages()) {
+ List fields = MavlinkTestSupport.fieldsSortedByOffset(message);
Set names = new HashSet<>();
- for (MavlinkCompiledField field : fields) {
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(field);
+ for (CompiledField field : fields) {
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(field);
Assertions.assertTrue(
names.add(fieldDefinition.getName()),
@@ -84,8 +84,8 @@ void compiledFieldLayoutIsMonotonicAndMatchesPayloadSize() throws Exception {
}
for (int i = 1; i < fields.size(); i++) {
- MavlinkCompiledField previous = fields.get(i - 1);
- MavlinkCompiledField current = fields.get(i);
+ CompiledField previous = fields.get(i - 1);
+ CompiledField current = fields.get(i);
int previousEnd = MavlinkTestSupport.offset(previous) + MavlinkTestSupport.size(previous);
@@ -100,7 +100,7 @@ void compiledFieldLayoutIsMonotonicAndMatchesPayloadSize() throws Exception {
);
}
- MavlinkCompiledField last = fields.get(fields.size() - 1);
+ CompiledField last = fields.get(fields.size() - 1);
int computedPayloadSize = MavlinkTestSupport.offset(last) + MavlinkTestSupport.size(last);
Assertions.assertEquals(
@@ -114,14 +114,14 @@ void compiledFieldLayoutIsMonotonicAndMatchesPayloadSize() throws Exception {
@Test
void extensionFieldsAreAllTrailingInPackedOrder() throws Exception {
MavlinkCodec codec = MavlinkTestSupport.codec();
- MavlinkMessageRegistry registry = MavlinkTestSupport.registry(codec);
+ MessageRegistry registry = MavlinkTestSupport.registry(codec);
- for (MavlinkCompiledMessage message : registry.getCompiledMessages()) {
- List fields = message.getCompiledFields(); // assumes already in packed order
+ for (CompiledMessage message : registry.getCompiledMessages()) {
+ List fields = message.getCompiledFields(); // assumes already in packed order
boolean sawExtension = false;
- for (MavlinkCompiledField field : fields) {
- MavlinkFieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(field);
+ for (CompiledField field : fields) {
+ FieldDefinition fieldDefinition = MavlinkTestSupport.fieldDefinition(field);
if (fieldDefinition.isExtension()) {
sawExtension = true;
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRobustness.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRobustness.java
index 86afe64..3032b15 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRobustness.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkRobustness.java
@@ -20,7 +20,7 @@
package io.mapsmessaging.mavlink;
-import io.mapsmessaging.mavlink.message.MavlinkMessageRegistry;
+import io.mapsmessaging.mavlink.message.MessageRegistry;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -81,7 +81,7 @@ void commonDialectLoadsAndHasKnownMessageIds() throws Exception {
Assertions.assertNotNull(codec);
Assertions.assertEquals("common", codec.getName());
- MavlinkMessageRegistry registry = codec.getRegistry();
+ MessageRegistry registry = codec.getRegistry();
Assertions.assertNotNull(registry);
assertTrue(registry.getCompiledMessagesById().containsKey(0), "HEARTBEAT");
diff --git a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkXmlParserIncludes.java b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkXmlParserIncludes.java
index 90b3104..2ef0d97 100644
--- a/src/test/java/io/mapsmessaging/mavlink/TestMavlinkXmlParserIncludes.java
+++ b/src/test/java/io/mapsmessaging/mavlink/TestMavlinkXmlParserIncludes.java
@@ -34,11 +34,11 @@ void commonDialect_resolvesIncludes_andContainsKnownMessages() throws Exception
try (InputStream stream = classLoader.getResourceAsStream("mavlink/common.xml")) {
Assertions.assertNotNull(stream, "Missing resource mavlink/common.xml");
- MavlinkXmlParser parser = new MavlinkXmlParser();
- MavlinkDialectLoader loader = new MavlinkDialectLoader(parser);
+ XmlParser parser = new XmlParser();
+ DialectLoader loader = new DialectLoader(parser);
- MavlinkIncludeResolver resolver = new ClasspathMavlinkIncludeResolver(classLoader, "mavlink");
- MavlinkDialectDefinition dialect = loader.load("common", stream, resolver);
+ IncludeResolver resolver = new ClasspathIncludeResolver(classLoader, "mavlink");
+ DialectDefinition dialect = loader.load("common", stream, resolver);
Assertions.assertNotNull(dialect);
Assertions.assertEquals("common", dialect.getName());
From a5ccd3bc922c277f28aab60fac8c0cb0e95f02bc Mon Sep 17 00:00:00 2001
From: Matthew Buckton
Date: Fri, 16 Jan 2026 22:18:07 +1100
Subject: [PATCH 16/34] add system id context and simple frame based error
detection
---
.../mavlink/SystemContextManager.java | 83 ++++++
.../mavlink/context/Detection.java | 13 +
.../mavlink/context/DetectionSeverity.java | 7 +
.../mavlink/context/DetectionType.java | 12 +
.../mavlink/context/FrameFailureReason.java | 9 +
.../mavlink/context/FrameFingerprint.java | 34 +++
.../context/SequenceProcessingResult.java | 17 ++
.../mavlink/context/SequenceProcessor.java | 264 ++++++++++++++++++
.../context/SequenceProcessorConfig.java | 21 ++
.../context/SequenceRingBuffer256.java | 22 ++
.../mavlink/context/SequenceRingEntry.java | 11 +
.../mavlink/context/SequenceStats.java | 15 +
.../mavlink/context/SourceStats.java | 19 ++
.../mavlink/context/SweepConfig.java | 15 +
.../mavlink/context/SweepResult.java | 9 +
.../mavlink/context/SystemContext.java | 117 ++++++++
.../context/SystemContextSnapshot.java | 13 +
.../mavlink/SystemContextManagerTest.java | 198 +++++++++++++
18 files changed, 879 insertions(+)
create mode 100644 src/main/java/io/mapsmessaging/mavlink/SystemContextManager.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/Detection.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/DetectionSeverity.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/DetectionType.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/FrameFailureReason.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/FrameFingerprint.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessingResult.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessor.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessorConfig.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SequenceRingBuffer256.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SequenceRingEntry.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SequenceStats.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SourceStats.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SweepConfig.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SweepResult.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SystemContext.java
create mode 100644 src/main/java/io/mapsmessaging/mavlink/context/SystemContextSnapshot.java
create mode 100644 src/test/java/io/mapsmessaging/mavlink/SystemContextManagerTest.java
diff --git a/src/main/java/io/mapsmessaging/mavlink/SystemContextManager.java b/src/main/java/io/mapsmessaging/mavlink/SystemContextManager.java
new file mode 100644
index 0000000..40e39ca
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/SystemContextManager.java
@@ -0,0 +1,83 @@
+package io.mapsmessaging.mavlink;
+
+import io.mapsmessaging.mavlink.context.*;
+import io.mapsmessaging.mavlink.message.Frame;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Data
+public class SystemContextManager {
+
+ private final Map systemContexts;
+ private final SequenceProcessor sequenceProcessor;
+ private final SequenceProcessorConfig sequenceProcessorConfig;
+ private final SweepConfig sweepConfig;
+
+ public SystemContextManager() {
+ this(new SequenceProcessorConfig(), new SweepConfig());
+ }
+
+ public SystemContextManager(SequenceProcessorConfig sequenceProcessorConfig, SweepConfig sweepConfig) {
+ this.systemContexts = new ConcurrentHashMap<>();
+ this.sequenceProcessorConfig = sequenceProcessorConfig;
+ this.sequenceProcessor = new SequenceProcessor(sequenceProcessorConfig);
+ this.sweepConfig = sweepConfig;
+ }
+
+ public List onValidatedFrame(Frame frame, String streamId, long receivedAtNanos) {
+ int systemId = frame.getSystemId();
+ SystemContext systemContext = systemContexts.computeIfAbsent(systemId, this::createContext);
+ return systemContext.onValidatedFrame(frame, streamId, receivedAtNanos, sequenceProcessor);
+ }
+
+ public List onInvalidFrame(int systemId, String streamId, long receivedAtNanos, FrameFailureReason reason) {
+ SystemContext systemContext = systemContexts.get(systemId);
+ if (systemContext == null) {
+ return List.of();
+ }
+ return systemContext.onInvalidFrame(streamId, receivedAtNanos, reason);
+ }
+
+ public SweepResult sweep(long nowNanos) {
+ SweepResult result = new SweepResult();
+
+ int removedSources = 0;
+ int removedSystems = 0;
+
+ for (Map.Entry entry : systemContexts.entrySet()) {
+ SystemContext systemContext = entry.getValue();
+
+ removedSources += systemContext.sweep(nowNanos, sweepConfig, sequenceProcessorConfig);
+
+ if (systemContext.isExpired(nowNanos, sweepConfig)) {
+ systemContexts.remove(entry.getKey());
+ removedSystems++;
+ }
+ }
+ result.setRemovedSystems(removedSystems);
+ result.setRemovedSources(removedSources);
+ return result;
+ }
+
+ private SystemContext createContext(int systemId) {
+ SystemContext systemContext = new SystemContext();
+ systemContext.setSystemId(systemId);
+ systemContext.setSequenceRingBuffer(new SequenceRingBuffer256());
+ systemContext.setSourceStats(new ConcurrentHashMap<>());
+ systemContext.setSequenceStats(new SequenceStats());
+ systemContext.setLastActivityAtNanos(0L);
+ return systemContext;
+ }
+
+ public List snapshotAll() {
+ List snapshots = new ArrayList<>();
+ for (SystemContext systemContext : systemContexts.values()) {
+ snapshots.add(systemContext.snapshot());
+ }
+ return snapshots;
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/Detection.java b/src/main/java/io/mapsmessaging/mavlink/context/Detection.java
new file mode 100644
index 0000000..b2b4807
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/Detection.java
@@ -0,0 +1,13 @@
+package io.mapsmessaging.mavlink.context;
+
+import lombok.Data;
+
+@Data
+public class Detection {
+ private int systemId;
+ private String streamId;
+ private long occurredAtNanos;
+ private DetectionType type;
+ private DetectionSeverity severity;
+ private String details;
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/DetectionSeverity.java b/src/main/java/io/mapsmessaging/mavlink/context/DetectionSeverity.java
new file mode 100644
index 0000000..394482c
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/DetectionSeverity.java
@@ -0,0 +1,7 @@
+package io.mapsmessaging.mavlink.context;
+
+public enum DetectionSeverity {
+ INFO,
+ WARN,
+ ALERT
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/DetectionType.java b/src/main/java/io/mapsmessaging/mavlink/context/DetectionType.java
new file mode 100644
index 0000000..081b7d2
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/DetectionType.java
@@ -0,0 +1,12 @@
+package io.mapsmessaging.mavlink.context;
+
+public enum DetectionType {
+ SEQ_DUPLICATE,
+ SEQ_REORDER,
+ SEQ_GAP,
+ SEQ_RESET_SUSPECTED,
+ SEQ_SUSPICIOUS_BACKWARDS,
+ SEQ_SAME_SEQ_DIFFERENT_FINGERPRINT,
+ SYSTEM_MULTI_SOURCE_ACTIVE,
+ FRAME_INVALID
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/FrameFailureReason.java b/src/main/java/io/mapsmessaging/mavlink/context/FrameFailureReason.java
new file mode 100644
index 0000000..6532549
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/FrameFailureReason.java
@@ -0,0 +1,9 @@
+package io.mapsmessaging.mavlink.context;
+
+public enum FrameFailureReason {
+ CRC_FAILED,
+ SIGNATURE_FAILED,
+ CRC_AND_SIGNATURE_FAILED,
+ MALFORMED,
+ UNKNOWN
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/FrameFingerprint.java b/src/main/java/io/mapsmessaging/mavlink/context/FrameFingerprint.java
new file mode 100644
index 0000000..2f1b345
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/FrameFingerprint.java
@@ -0,0 +1,34 @@
+package io.mapsmessaging.mavlink.context;
+
+import io.mapsmessaging.mavlink.message.Frame;
+
+public class FrameFingerprint {
+
+ private FrameFingerprint() {
+ }
+
+ public static int computeFingerprint(Frame frame) {
+ int hash = 0x811C9DC5;
+
+ hash = fnv1a(hash, frame.getVersion() == null ? 0 : frame.getVersion().ordinal());
+ hash = fnv1a(hash, frame.getSystemId());
+ hash = fnv1a(hash, frame.getComponentId());
+ hash = fnv1a(hash, frame.getMessageId());
+ hash = fnv1a(hash, frame.getPayloadLength());
+
+ byte[] payload = frame.getPayload();
+ if (payload != null) {
+ int length = Math.min(payload.length, frame.getPayloadLength());
+ for (int index = 0; index < length; index++) {
+ hash = fnv1a(hash, payload[index]);
+ }
+ }
+
+ return hash;
+ }
+
+ private static int fnv1a(int hash, int value) {
+ int next = hash ^ value;
+ return next * 16777619;
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessingResult.java b/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessingResult.java
new file mode 100644
index 0000000..75c4a5d
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessingResult.java
@@ -0,0 +1,17 @@
+package io.mapsmessaging.mavlink.context;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+public class SequenceProcessingResult {
+ private boolean acceptedAsHead;
+ private int sequence;
+ private List detections;
+
+ public SequenceProcessingResult() {
+ this.detections = new ArrayList<>();
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessor.java b/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessor.java
new file mode 100644
index 0000000..8ddded9
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessor.java
@@ -0,0 +1,264 @@
+package io.mapsmessaging.mavlink.context;
+
+import io.mapsmessaging.mavlink.message.Frame;
+
+import java.util.Map;
+
+public record SequenceProcessor(SequenceProcessorConfig config) {
+
+ public SequenceProcessingResult process(SystemContext systemContext, Frame frame, String streamId, long receivedAtNanos) {
+ SequenceProcessingResult result = new SequenceProcessingResult();
+ int sequence = frame.getSequence() & 0xFF;
+ result.setSequence(sequence);
+
+ int fingerprint = FrameFingerprint.computeFingerprint(frame);
+
+ SequenceRingEntry previousEntryForSequence = systemContext.getSequenceRingBuffer().get(sequence);
+ if (previousEntryForSequence != null) {
+ long ageNanos = receivedAtNanos - previousEntryForSequence.getLastSeenAtNanos();
+ boolean withinDupWindow = ageNanos >= 0 && ageNanos <= config.getDuplicateTimeWindowNanos();
+
+ if (withinDupWindow) {
+ if (previousEntryForSequence.getFingerprint() == fingerprint) {
+ incrementDuplicate(systemContext, frame, streamId, receivedAtNanos, result);
+ updateRing(systemContext, sequence, fingerprint, streamId, receivedAtNanos);
+ detectMultiSourceActive(systemContext, streamId, receivedAtNanos, result);
+ return result;
+ }
+
+ Detection detection = new Detection();
+ detection.setSystemId(systemContext.getSystemId());
+ detection.setStreamId(streamId);
+ detection.setOccurredAtNanos(receivedAtNanos);
+ detection.setType(DetectionType.SEQ_SAME_SEQ_DIFFERENT_FINGERPRINT);
+ detection.setSeverity(DetectionSeverity.ALERT);
+ detection.setDetails("seq=" + sequence + " previousStream=" + previousEntryForSequence.getStreamId());
+
+ result.getDetections().add(detection);
+
+ updateRing(systemContext, sequence, fingerprint, streamId, receivedAtNanos);
+ detectMultiSourceActive(systemContext, streamId, receivedAtNanos, result);
+ return result;
+ }
+ }
+
+ if (!systemContext.isInitialized()) {
+ systemContext.setInitialized(true);
+ systemContext.setLastAcceptedSequence(sequence);
+ systemContext.setLastAcceptedAtNanos(receivedAtNanos);
+ setLastAcceptedSequenceForSource(systemContext, streamId, sequence);
+ updateRing(systemContext, sequence, fingerprint, streamId, receivedAtNanos);
+ detectMultiSourceActive(systemContext, streamId, receivedAtNanos, result);
+ result.setAcceptedAsHead(true);
+ return result;
+ }
+
+ int lastAcceptedSequence = systemContext.getLastAcceptedSequence() & 0xFF;
+ int delta = (sequence - lastAcceptedSequence) & 0xFF;
+
+ if (delta == 0) {
+ incrementDuplicate(systemContext, frame, streamId, receivedAtNanos, result);
+ updateRing(systemContext, sequence, fingerprint, streamId, receivedAtNanos);
+ detectMultiSourceActive(systemContext, streamId, receivedAtNanos, result);
+ return result;
+ }
+
+ if (delta <= 127) {
+ if (delta > 1) {
+ int lostPackets = delta - 1;
+ incrementGap(systemContext, streamId, receivedAtNanos, result, lostPackets);
+ }
+
+ systemContext.setLastAcceptedSequence(sequence);
+ systemContext.setLastAcceptedAtNanos(receivedAtNanos);
+ setLastAcceptedSequenceForSource(systemContext, streamId, sequence);
+ updateRing(systemContext, sequence, fingerprint, streamId, receivedAtNanos);
+ detectMultiSourceActive(systemContext, streamId, receivedAtNanos, result);
+ result.setAcceptedAsHead(true);
+ return result;
+ }
+
+ int backwardDistance = 256 - delta;
+
+ boolean withinReorderDistance = backwardDistance <= config.getReorderDistanceWindow();
+ long ageSinceHeadNanos = receivedAtNanos - systemContext.getLastAcceptedAtNanos();
+ boolean withinReorderTime = ageSinceHeadNanos >= 0 && ageSinceHeadNanos <= config.getReorderTimeWindowNanos();
+
+ if (withinReorderDistance && withinReorderTime) {
+ incrementReorder(systemContext, streamId, receivedAtNanos, result, backwardDistance);
+ updateRing(systemContext, sequence, fingerprint, streamId, receivedAtNanos);
+ detectMultiSourceActive(systemContext, streamId, receivedAtNanos, result);
+ return result;
+ }
+
+ incrementSuspiciousBackward(systemContext, streamId, receivedAtNanos, result, backwardDistance);
+
+ if (looksLikeReset(systemContext, sequence, receivedAtNanos)) {
+ incrementResetSuspected(systemContext, streamId, receivedAtNanos, result, lastAcceptedSequence, sequence);
+ }
+
+ updateRing(systemContext, sequence, fingerprint, streamId, receivedAtNanos);
+ detectMultiSourceActive(systemContext, streamId, receivedAtNanos, result);
+
+ return result;
+ }
+
+ private void updateRing(SystemContext systemContext, int sequence, int fingerprint, String streamId, long receivedAtNanos) {
+ SequenceRingEntry entry = new SequenceRingEntry();
+ entry.setSequence(sequence);
+ entry.setFingerprint(fingerprint);
+ entry.setStreamId(streamId);
+ entry.setLastSeenAtNanos(receivedAtNanos);
+ systemContext.getSequenceRingBuffer().put(sequence, entry);
+ }
+
+ private void setLastAcceptedSequenceForSource(SystemContext systemContext, String streamId, int sequence) {
+ SourceStats stats = systemContext.getSourceStats().get(streamId);
+ if (stats == null) {
+ return;
+ }
+ stats.setLastAcceptedSequenceFromSource(sequence);
+ }
+
+ private void incrementDuplicate(SystemContext systemContext, Frame frame, String streamId, long receivedAtNanos, SequenceProcessingResult result) {
+ systemContext.getSequenceStats().setDuplicates(systemContext.getSequenceStats().getDuplicates() + 1);
+
+ Detection detection = new Detection();
+ detection.setSystemId(systemContext.getSystemId());
+ detection.setStreamId(streamId);
+ detection.setOccurredAtNanos(receivedAtNanos);
+ detection.setType(DetectionType.SEQ_DUPLICATE);
+ detection.setSeverity(DetectionSeverity.INFO);
+ detection.setDetails("seq=" + (frame.getSequence() & 0xFF));
+
+ result.getDetections().add(detection);
+ }
+
+ private void incrementGap(SystemContext systemContext, String streamId, long receivedAtNanos, SequenceProcessingResult result, int lostPackets) {
+ systemContext.getSequenceStats().setGaps(systemContext.getSequenceStats().getGaps() + 1);
+ systemContext.getSequenceStats().setLostPackets(systemContext.getSequenceStats().getLostPackets() + lostPackets);
+
+ Detection detection = new Detection();
+ detection.setSystemId(systemContext.getSystemId());
+ detection.setStreamId(streamId);
+ detection.setOccurredAtNanos(receivedAtNanos);
+ detection.setType(DetectionType.SEQ_GAP);
+ detection.setSeverity(DetectionSeverity.WARN);
+ detection.setDetails("lost=" + lostPackets);
+
+ result.getDetections().add(detection);
+ }
+
+ private void incrementReorder(SystemContext systemContext, String streamId, long receivedAtNanos, SequenceProcessingResult result, int backwardDistance) {
+ systemContext.getSequenceStats().setReorders(systemContext.getSequenceStats().getReorders() + 1);
+
+ Detection detection = new Detection();
+ detection.setSystemId(systemContext.getSystemId());
+ detection.setStreamId(streamId);
+ detection.setOccurredAtNanos(receivedAtNanos);
+ detection.setType(DetectionType.SEQ_REORDER);
+ detection.setSeverity(DetectionSeverity.INFO);
+ detection.setDetails("back=" + backwardDistance);
+
+ result.getDetections().add(detection);
+ }
+
+ private void incrementSuspiciousBackward(SystemContext systemContext, String streamId, long receivedAtNanos, SequenceProcessingResult result, int backwardDistance) {
+ systemContext.getSequenceStats().setSuspiciousBackwards(systemContext.getSequenceStats().getSuspiciousBackwards() + 1);
+
+ Detection detection = new Detection();
+ detection.setSystemId(systemContext.getSystemId());
+ detection.setStreamId(streamId);
+ detection.setOccurredAtNanos(receivedAtNanos);
+ detection.setType(DetectionType.SEQ_SUSPICIOUS_BACKWARDS);
+
+ DetectionSeverity severity = backwardDistance >= config.getSuspiciousBackwardDistance()
+ ? DetectionSeverity.ALERT
+ : DetectionSeverity.WARN;
+
+ detection.setSeverity(severity);
+ detection.setDetails("back=" + backwardDistance);
+
+ result.getDetections().add(detection);
+ }
+
+ private void incrementResetSuspected(SystemContext systemContext, String streamId, long receivedAtNanos, SequenceProcessingResult result, int lastAcceptedSequence, int sequence) {
+ systemContext.getSequenceStats().setResetsSuspected(systemContext.getSequenceStats().getResetsSuspected() + 1);
+
+ Detection detection = new Detection();
+ detection.setSystemId(systemContext.getSystemId());
+ detection.setStreamId(streamId);
+ detection.setOccurredAtNanos(receivedAtNanos);
+ detection.setType(DetectionType.SEQ_RESET_SUSPECTED);
+ detection.setSeverity(DetectionSeverity.WARN);
+ detection.setDetails("head=" + lastAcceptedSequence + " seq=" + sequence);
+
+ result.getDetections().add(detection);
+ }
+
+ private boolean looksLikeReset(SystemContext systemContext, int sequence, long receivedAtNanos) {
+ int lastAcceptedSequence = systemContext.getLastAcceptedSequence() & 0xFF;
+
+ boolean headWasMidRange = lastAcceptedSequence >= 50 && lastAcceptedSequence <= 200;
+ boolean newIsLow = sequence <= 10;
+
+ if (!headWasMidRange || !newIsLow) {
+ return false;
+ }
+
+ long silenceNanos = receivedAtNanos - systemContext.getLastAcceptedAtNanos();
+ return silenceNanos > config.getMultiSourceActiveWindowNanos();
+ }
+
+ private void detectMultiSourceActive(SystemContext systemContext, String streamId, long receivedAtNanos, SequenceProcessingResult result) {
+ String primaryStreamId = findPrimaryStreamId(systemContext, receivedAtNanos);
+ if (primaryStreamId == null) {
+ markPrimary(systemContext, streamId, receivedAtNanos);
+ return;
+ }
+
+ if (primaryStreamId.equals(streamId)) {
+ return;
+ }
+
+ systemContext.getSequenceStats().setMultiSourceActive(systemContext.getSequenceStats().getMultiSourceActive() + 1);
+
+ Detection detection = new Detection();
+ detection.setSystemId(systemContext.getSystemId());
+ detection.setStreamId(streamId);
+ detection.setOccurredAtNanos(receivedAtNanos);
+ detection.setType(DetectionType.SYSTEM_MULTI_SOURCE_ACTIVE);
+ detection.setSeverity(DetectionSeverity.WARN);
+ detection.setDetails("primary=" + primaryStreamId);
+
+ result.getDetections().add(detection);
+ }
+
+ private String findPrimaryStreamId(SystemContext systemContext, long receivedAtNanos) {
+ long activeWindowNanos = config.getMultiSourceActiveWindowNanos();
+
+ for (Map.Entry entry : systemContext.getSourceStats().entrySet()) {
+ SourceStats stats = entry.getValue();
+ if (!stats.isPrimary()) {
+ continue;
+ }
+
+ long ageNanos = receivedAtNanos - stats.getLastSeenAtNanos();
+ if (ageNanos >= 0 && ageNanos <= activeWindowNanos) {
+ return stats.getStreamId();
+ }
+ }
+
+ return null;
+ }
+
+ private void markPrimary(SystemContext systemContext, String streamId, long receivedAtNanos) {
+ SourceStats stats = systemContext.getSourceStats().get(streamId);
+ if (stats == null) {
+ return;
+ }
+
+ stats.setPrimary(true);
+ stats.setPrimarySinceAtNanos(receivedAtNanos);
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessorConfig.java b/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessorConfig.java
new file mode 100644
index 0000000..6aca599
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SequenceProcessorConfig.java
@@ -0,0 +1,21 @@
+package io.mapsmessaging.mavlink.context;
+
+import lombok.Data;
+
+@Data
+public class SequenceProcessorConfig {
+
+ private int reorderDistanceWindow;
+ private long reorderTimeWindowNanos;
+ private long duplicateTimeWindowNanos;
+ private int suspiciousBackwardDistance;
+ private long multiSourceActiveWindowNanos;
+
+ public SequenceProcessorConfig() {
+ this.reorderDistanceWindow = 20;
+ this.reorderTimeWindowNanos = 500_000_000L;
+ this.duplicateTimeWindowNanos = 1_000_000_000L;
+ this.suspiciousBackwardDistance = 64;
+ this.multiSourceActiveWindowNanos = 2_000_000_000L;
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SequenceRingBuffer256.java b/src/main/java/io/mapsmessaging/mavlink/context/SequenceRingBuffer256.java
new file mode 100644
index 0000000..1ffdabd
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SequenceRingBuffer256.java
@@ -0,0 +1,22 @@
+package io.mapsmessaging.mavlink.context;
+
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+public class SequenceRingBuffer256 {
+
+ private final AtomicReferenceArray entries;
+
+ public SequenceRingBuffer256() {
+ this.entries = new AtomicReferenceArray<>(256);
+ }
+
+ public SequenceRingEntry get(int sequence) {
+ int index = sequence & 0xFF;
+ return entries.get(index);
+ }
+
+ public void put(int sequence, SequenceRingEntry entry) {
+ int index = sequence & 0xFF;
+ entries.set(index, entry);
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SequenceRingEntry.java b/src/main/java/io/mapsmessaging/mavlink/context/SequenceRingEntry.java
new file mode 100644
index 0000000..a23d18d
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SequenceRingEntry.java
@@ -0,0 +1,11 @@
+package io.mapsmessaging.mavlink.context;
+
+import lombok.Data;
+
+@Data
+public class SequenceRingEntry {
+ private int sequence;
+ private int fingerprint;
+ private String streamId;
+ private long lastSeenAtNanos;
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SequenceStats.java b/src/main/java/io/mapsmessaging/mavlink/context/SequenceStats.java
new file mode 100644
index 0000000..c5ed6a9
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SequenceStats.java
@@ -0,0 +1,15 @@
+package io.mapsmessaging.mavlink.context;
+
+import lombok.Data;
+
+@Data
+public class SequenceStats {
+ private long duplicates;
+ private long reorders;
+ private long gaps;
+ private long lostPackets;
+ private long suspiciousBackwards;
+ private long resetsSuspected;
+ private long invalidFrames;
+ private long multiSourceActive;
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SourceStats.java b/src/main/java/io/mapsmessaging/mavlink/context/SourceStats.java
new file mode 100644
index 0000000..77247ab
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SourceStats.java
@@ -0,0 +1,19 @@
+package io.mapsmessaging.mavlink.context;
+
+import lombok.Data;
+
+@Data
+public class SourceStats {
+
+ private final String streamId;
+ private long lastSeenAtNanos;
+ private long packetCount;
+ private long invalidPacketCount;
+ private boolean primary;
+ private long primarySinceAtNanos;
+ private Integer lastAcceptedSequenceFromSource;
+
+ public SourceStats(String streamId) {
+ this.streamId = streamId;
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SweepConfig.java b/src/main/java/io/mapsmessaging/mavlink/context/SweepConfig.java
new file mode 100644
index 0000000..586111e
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SweepConfig.java
@@ -0,0 +1,15 @@
+package io.mapsmessaging.mavlink.context;
+
+import lombok.Data;
+
+@Data
+public class SweepConfig {
+
+ private long systemTtlNanos;
+ private long sourceTtlNanos;
+
+ public SweepConfig() {
+ this.systemTtlNanos = 10L * 60L * 1_000_000_000L;
+ this.sourceTtlNanos = 60L * 1_000_000_000L;
+ }
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SweepResult.java b/src/main/java/io/mapsmessaging/mavlink/context/SweepResult.java
new file mode 100644
index 0000000..01074ac
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SweepResult.java
@@ -0,0 +1,9 @@
+package io.mapsmessaging.mavlink.context;
+
+import lombok.Data;
+
+@Data
+public class SweepResult {
+ private int removedSystems;
+ private int removedSources;
+}
diff --git a/src/main/java/io/mapsmessaging/mavlink/context/SystemContext.java b/src/main/java/io/mapsmessaging/mavlink/context/SystemContext.java
new file mode 100644
index 0000000..a137f6b
--- /dev/null
+++ b/src/main/java/io/mapsmessaging/mavlink/context/SystemContext.java
@@ -0,0 +1,117 @@
+package io.mapsmessaging.mavlink.context;
+
+import io.mapsmessaging.mavlink.message.Frame;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class SystemContext {
+
+ private int systemId;
+ private boolean initialized;
+ private int lastAcceptedSequence;
+ private long lastAcceptedAtNanos;
+ private long lastActivityAtNanos;
+ private SequenceRingBuffer256 sequenceRingBuffer;
+ private Map sourceStats;
+ private SequenceStats sequenceStats;
+
+ public List onValidatedFrame(Frame frame, String streamId, long receivedAtNanos, SequenceProcessor sequenceProcessor) {
+ lastActivityAtNanos = receivedAtNanos;
+
+ List detections = new ArrayList<>();
+
+ SourceStats statsForSource = sourceStats.computeIfAbsent(streamId, key -> new SourceStats(streamId));
+ statsForSource.setLastSeenAtNanos(receivedAtNanos);
+ statsForSource.setPacketCount(statsForSource.getPacketCount() + 1);
+
+ SequenceProcessingResult result = sequenceProcessor.process(this, frame, streamId, receivedAtNanos);
+ detections.addAll(result.getDetections());
+
+ return detections;
+ }
+
+ public List