Zum Hauptinhalt springen

Paketstruktur

Diese Seite erklärt den Aufbau eines MeshCore-Pakets auf Bit- und Byte-Ebene – vom LoRa-Funkpaket bis zum Mesh-Protokoll.

Zwei Schichten: LoRa vs. Mesh

Ein MeshCore-Paket besteht aus zwei ineinander geschachtelten Protokoll-Schichten:

1. LoRa Physical Layer

Der LoRa-Chip (z.B. SX1262, SX1276, LLCC68) fügt automatisch hinzu:

KomponenteGrößeHinzugefügt vonBeschreibung
PreamblekonfigurierbarLoRa-ChipSynchronisation der Empfänger
LoRa Header0-20 BitsLoRa-ChipExplicit/Implicit Mode, Coding Rate
PayloadvariabelFirmwareDas Mesh-Paket (siehe unten)
CRC-162 BytesLoRa-ChipHardware-Checksumme über Payload
LoRa-CRC wird automatisch validiert

Der LoRa-Chip prüft die CRC-16 automatisch. Nur fehlerfreie Pakete werden an die Firmware übergeben. setCRC(1) aktiviert dies in der Firmware.

2. Mesh Protocol Layer

Das Mesh-Paket innerhalb des LoRa-Payloads hat folgende Struktur:

Detaillierte Frame-Struktur

Minimales Frame (ohne Transport Codes, ohne Path)

Frame-Struktur:

Header-Byte im Detail:

Bit-Layout:

 Bit:  7   6   5   4   3   2   1   0
┌───┬───┬───┬───┬───┬───┬───┬───┐
│Ver│Ver│ Type │ Type │RT │RT │
└───┴───┴───┴───┴───┴───┴───┴───┘
└─┬─┘ └────┬────┘ └──┬──┘
Payload Payload Route
Version Type Type
(2 Bits) (4 Bits) (2 Bits)

Gesamtlänge in Bytes: 2 + Payload-Länge

Vollständiges Frame (mit Transport Codes und Path)

Frame-Struktur:

Beispiel mit 3 Hops:

Beispiel-Bytes:

Byte  0:    Header
Byte 1-2: Transport Code 1 (16-bit, Little Endian)
Byte 3-4: Transport Code 2 (16-bit, Little Endian)
Byte 5: Path Length (z.B. 0x03 für 3 Hops)
Byte 6-8: Path (3 Node-Hashes à 1 Byte)
Byte 9+: Payload

Gesamtlänge in Bytes: 6 + Path-Länge + Payload-Länge

Längenbestimmung

Keine explizite Payload-Länge

Das Mesh-Protokoll speichert keine explizite Payload-Länge. Diese wird implizit berechnet.

Formel:

payload_len = total_frame_len - header_size - transport_codes_size - 1 - path_len

Beispiele

Beispiel 1: Advertisement eines Repeaters

Ein Repeater in Bonn-Hardtberg sendet ein Advertisement (FLOOD-Routing):

Vollständiger Frame (131 Bytes):

1100FE5616140E71B9E01E5DA75103F56550FFFD78C7DE35CEB30161401CD3A155990B7C5F69FC2DE8FE34DE983DED22BD24A7866A258D823DA714654926A9EDEB54C23EFD990FF25FB22C2B74E0C30177AEB7635CC5CB03CA65BD59A407B891F976FE883D0C9232D1050372946B00442D424E2D353331323320486172647462657267

Farbige Byte-Range-Übersicht:

Hex-Breakdown mit Byte-Positionen:

BytesFeldHex-Wert
0Header11
1Path Length00
2-33Public KeyFE5616140E71B9E01E5DA75103F56550FFFD78C7DE35CEB30161401CD3A15599
34-37Timestamp0B7C5F69
38-101SignatureFC2DE8FE34DE983DED22BD24A7866A258D823DA714654926A9EDEB54C23EFD990FF25FB22C2B74E0C30177AEB7635CC5CB03CA65BD59A407B891F976FE883D0C
102App Flags92
103-106Latitude32D10503
107-110Longitude72946B00
111-130Node Name442D424E2D353331323320486172647462657267

Dekodierte Werte:

FeldRoh-WertDekodiert
Header0x11FLOOD (0x01) + ADVERT (0x04) + Version 1
Path Length0x000 Bytes (kein Pfad bei FLOOD)
Public Key32 BytesEd25519 Public Key (Node-Identität)
Timestamp0B7C5F69 (LE)1767865355 = 2026-01-08 09:42:35 UTC
Signature64 BytesEd25519-Signatur über (PubKey + Timestamp + AppData)
App Flags0x92 = 10010010Repeater ✓, Location ✓, Name ✓
Latitude32D10503 (LE)5071288250.712882° N
Longitude72946B00 (LE)70503547.050354° E
Node NameASCII-Hex"D-BN-53123 Hardtberg" (20 Zeichen)

Header-Bit-Dekodierung:

App Data Flags (0x92 = 10010010 binär):

Standort:

  • Koordinaten: 50.712882°N, 7.050354°E
  • Ort: Bonn-Hardtberg, Deutschland (Rheinland)
  • Postleitzahl: D-BN-53123
  • Node-Typ: Repeater mit GPS und Name

Visualisierung im MeshCore Analyzer:

Advertisement Frame Breakdown

Dieser Screenshot zeigt die detaillierte Paket-Analyse mit Byte-für-Byte-Breakdown und farbcodierter Darstellung aller Felder.

Beispiel 2: Text Message "Hallo Ulli!"

Eine echte Textnachricht an Ulli mit dem Inhalt "Hallo Ulli!" direkt übermittelt ohne Hops:

Vollständiger Frame (22 Bytes):

0A004F37CD40E201D82228058A434BF27B926B6F43F7

Farbige Byte-Range-Übersicht:

Hex-Breakdown mit Byte-Positionen:

BytesFeldHex-Wert
0Header0A
1Path Length00
2Dest Hash4F
3Source Hash37
4-5MACCD40
6-21CiphertextE201D82228058A434BF27B926B6F43F7

Dekodierte Werte:

FeldRoh-WertDekodiert
Header0x0ADIRECT (0x02) + TEXT_MSG (0x02) + Version 1
Path Length0x000 Bytes (keine Repeater, direkte Verbindung)
Dest Hash0x4FEmpfänger: Ulli (Hash von Public Key)
Source Hash0x37Sender (Hash von Public Key)
MAC0xCD40Message Authentication Code (2 Bytes)
Ciphertext16 BytesVerschlüsselt: Timestamp + Type + "Hallo Ulli!"

Header-Bit-Dekodierung:

Struktur nach Entschlüsselung:

Nach Entschlüsselung mit ECDH (Ed25519) enthält der Ciphertext:

Nachricht:

  • Text: "Hallo Ulli!" (UTF-8, 11 Bytes)
  • Type: 0x00 = Plain Text
  • Attempt: 0 (erste Übertragung)

Besonderheiten:

  • Path Length = 0: Direkte Punkt-zu-Punkt-Verbindung ohne Repeater
  • DIRECT Routing: Verwendet vorher gelernten Pfad (in diesem Fall leer = lokale Kommunikation)
  • Verschlüsselung: ECDH mit Ed25519-Schlüsseln, nur Empfänger kann entschlüsseln

Visualisierung im MeshCore Analyzer:

Text Message Frame Breakdown

Dieser Screenshot zeigt die Textnachricht "Hallo Ulli!" mit vollständiger Frame-Dekodierung und verschlüsseltem Payload.

Maximale Frame-Größe

Konstanten (aus MeshCore.h):

#define MAX_PATH_SIZE        64
#define MAX_PACKET_PAYLOAD 184
#define MAX_TRANS_UNIT 255

Berechnung:

Ohne Transport Codes:
1 (Header) + 1 (Path Len) + 64 (Path) + 184 (Payload) = 250 Bytes ✅

Mit Transport Codes:
1 (Header) + 4 (Codes) + 1 (Path Len) + 64 (Path) + 184 (Payload) = 254 Bytes ✅

Checksumme / CRC

Warum keine Mesh-CRC?

Das Mesh-Protokoll hat keine eigene Checksumme, weil:

  1. LoRa-Hardware-CRC ist bereits aktiv (setCRC(1))
  2. LoRa-CRC-16 ist sehr zuverlässig (Hamming-Distanz)
  3. Nur CRC-valide Frames werden an Firmware übergeben
  4. Zusätzliche CRC wäre redundant

Frame-Parsing-Ablauf

Header-Bit-Dekodierung

Der Header (1 Byte) kodiert drei Werte:

Bit:     7  6  5  4  3  2  1  0
[Ver ][ Type ][ RT ]

RT = Route Type (2 Bits)
Type = Payload Type (4 Bits)
Ver = Payload Version (2 Bits)

Beispiel: Header = 0x0A (binär: 00001010)

  0  0  0  0  1  0  1  0
[0 0][0 1 0 0][1 0]
Ver=0 Type=4 RT=2
  • Route Type: 10 = DIRECT (0x02)
  • Payload Type: 0100 = ADVERT (0x04)
  • Version: 00 = Version 1 (0x00)

Umgekehrt kodieren:

header = (route_type & 0x03)           // Bits 0-1
| ((payload_type & 0x0F) << 2) // Bits 2-5
| ((version & 0x03) << 6); // Bits 6-7

Zusammenfassung

AspektWert
Minimale Frame-Größe2 Bytes (Header + Path-Len=0 + leere Payload)
Maximale Frame-Größe254 Bytes (mit Transport Codes)
ChecksummeLoRa-Hardware-CRC-16 (automatisch)
LängenbestimmungImplizit: payload_len = total - overhead
Header-Größe1 Byte (Route, Type, Version)
Optionale FelderTransport Codes (4 Bytes), Path (0-64 Bytes)
Wire-Format ist kompakt

MeshCore nutzt jeden Byte effizient: Keine Padding-Bytes, keine redundanten Längenfelder, keine doppelte Checksumme.