MeshCore KISS Modem Protokoll
MeshCore KISS Modem Protokoll
Standard-KISS-TNC-Firmware (Terminal Node Controller) für MeshCore LoRa-Funkgeräte. Kompatibel mit jedem KISS-Client (wie Direwolf, APRSdroid, YAAC usw.) zum Senden und Empfangen von Rohdatenpaketen. MeshCore-spezifische Erweiterungen (Kryptografie, Funkkonfiguration, Telemetrie) sind über den Standard-SetHardware-Befehl (0x06) verfügbar.
Serielle Konfiguration
115200 Baud, 8N1, keine Flusskontrolle (no flow control).
Frame-Format
Standard-KISS-Framing gemäß der KA9Q/K3MC-Spezifikation.
| Byte | Name | Description |
|---|---|---|
0xC0 | FEND | Frame-Begrenzer |
0xDB | FESC | Escape-Zeichen |
0xDC | TFEND | Escaped FEND (FESC + TFEND = 0xC0) |
0xDD | TFESC | Escaped FESC (FESC + TFESC = 0xDB) |
Typ-Byte (Type Byte)
Das Typ-Byte (Type Byte) ist in zwei Nibbles (Halb-Bytes) aufgeteilt:
| Bits | Feld | Description |
|---|---|---|
| 7-4 | Port | Portnummer (0 für Single-Port-TNC) |
| 3-0 | Command | Befehlsnummer |
Maximale, nicht-escapte Frame-Größe: 512 Bytes.
Standard-KISS-Befehle
Host an TNC
| Command | Value | Data | Description |
|---|---|---|---|
| Data | 0x00 | Raw packet | Paket zum Senden in die Warteschlange stellen (nur eines gleichzeitig ausstehend) |
| TXDELAY | 0x01 | Delay (1 byte) | Sende-Keyup-Verzögerung in 10-ms-Einheiten (Standard: 50 = 500ms) |
| Persistence | 0x02 | P (1 byte) | CSMA-Persistenzparameter 0-255 (Standard: 63) |
| SlotTime | 0x03 | Interval (1 byte) | CSMA-Slot-Intervall in 10-ms-Einheiten (Standard: 10 = 100ms) |
| TXtail | 0x04 | Delay (1 byte) | Post-TX-Haltezeit in 10-ms-Einheiten (Standard: 0) |
| FullDuplex | 0x05 | Mode (1 byte) | 0 = Halbduplex, ungleich Null = Vollduplex (Standard: 0) |
| SetHardware | 0x06 | Sub-command + data | MeshCore-Erweiterungen (siehe unten) |
| Return | 0xFF | - | KISS-Modus verlassen (keine Operation) |
TNC an Host
| Type | Value | Data | Description |
|---|---|---|---|
| Data | 0x00 | Raw packet | Empfangenes Paket vom Funkgerät |
Datenframes enthalten nur Rohpaketdaten, ohne vorangestellte Metadaten. Die Nutzlast des Datenbefehls (Data command payload) ist auf 255 Bytes begrenzt, um der maximalen Übertragungseinheit (MTU – Maximum Transmission Unit) von MeshCore zu entsprechen; Frames, die größer als 255 Bytes sind, werden stillschweigend verworfen. Die KISS-Spezifikation empfiehlt mindestens 1024 Bytes für allgemeine TNCs; dieses Modem ist jedoch nur für MeshCore-Pakete vorgesehen, deren Protokoll-MTU 255 Bytes beträgt.
Es kann immer nur ein Paket zur Funkübertragung anstehen. Wenn der Host einen zweiten Datenframe sendet, bevor der erste abgeschlossen ist, antwortet das Modem mit Fehler (0xF1) und TxBusy (0x07).
Host-Ausgabe-Gegendruck (Host Output Backpressure)
Ausgehende Frames werden in eine 2-Slot-Warteschlange kodiert und geleert, sobald serieller Ausgabespeicher verfügbar ist; loop() blockiert niemals bei Schreibvorgängen. Der TX-Status des Funkgeräts schreitet unabhängig von der Host-Lesegeschwindigkeit voran. TxDone wird beibehalten, bis es in die Warteschlange gestellt werden kann. Ist die ausgehende Warteschlange voll, antwortet das Modem mit Fehler (0xF1) und TxBusy (0x07). Hosts sollten die serielle Schnittstelle zeitnah auslesen, um verzögerte Antworten zu vermeiden.
CSMA-Verhalten
Das TNC implementiert p-persistent CSMA (Carrier Sense Multiple Access) für den Halbduplex-Betrieb:
- Wenn ein Paket in die Warteschlange gestellt wird, wird die Trägererkennung (carrier detect) überwacht.
- Wenn der Kanal frei wird, wird ein Zufallswert von 0-255 generiert.
- Wenn der Wert kleiner oder gleich P (Persistenz) ist, wird nach einer Wartezeit von TXDELAY gesendet.
- Andernfalls wird SlotTime gewartet und der Vorgang ab Schritt 1 wiederholt.
SetHardware-Erweiterungen (0x06)
MeshCore-spezifische Funktionen verwenden den Standard-KISS-SetHardware-Befehl. Das erste Byte der SetHardware-Daten ist ein Unterbefehl (Sub-command). Standard-KISS-Clients ignorieren diese Frames.
Frame-Format
Anforderungs-Unterbefehle (Host an TNC)
| Sub-command | Value | Data |
|---|---|---|
| GetIdentity | 0x01 | - |
| GetRandom | 0x02 | Length (1 byte, 1-64) |
| VerifySignature | 0x03 | PubKey (32) + Signature (64) + Data |
| SignData | 0x04 | Data to sign |
| EncryptData | 0x05 | Key (32) + Plaintext |
| DecryptData | 0x06 | Key (32) + MAC (2) + Ciphertext |
| KeyExchange | 0x07 | Remote PubKey (32) |
| Hash | 0x08 | Data to hash |
| SetRadio | 0x09 | Freq (4) + BW (4) + SF (1) + CR (1) |
| SetTxPower | 0x0A | Power dBm (1) |
| GetRadio | 0x0B | - |
| GetTxPower | 0x0C | - |
| GetCurrentRssi | 0x0D | - |
| IsChannelBusy | 0x0E | - |
| GetAirtime | 0x0F | Packet length (1) |
| GetNoiseFloor | 0x10 | - |
| GetVersion | 0x11 | - |
| GetStats | 0x12 | - |
| GetBattery | 0x13 | - |
| GetMCUTemp | 0x14 | - |
| GetSensors | 0x15 | Permissions (1) |
| GetDeviceName | 0x16 | - |
| Ping | 0x17 | - |
| Reboot | 0x18 | - |
| SetSignalReport | 0x19 | Enable (1): 0x00=disable, nonzero=enable |
| GetSignalReport | 0x1A | - |
Antwort-Unterbefehle (TNC an Host)
Antwortcodes verwenden die High-Bit-Konvention (das höchstwertige Bit ist gesetzt): response = command | 0x80. Allgemeine und unaufgeforderte Antworten verwenden den Bereich 0xF0+.
| Sub-command | Value | Data |
|---|---|---|
| Identity | 0x81 | PubKey (32) |
| Random | 0x82 | Random bytes (1-64) |
| Verify | 0x83 | Result (1): 0x00=invalid, 0x01=valid |
| Signature | 0x84 | Signature (64) |
| Encrypted | 0x85 | MAC (2) + Ciphertext |
| Decrypted | 0x86 | Plaintext |
| SharedSecret | 0x87 | Shared secret (32) |
| Hash | 0x88 | SHA-256 hash (32) |
| Radio | 0x8B | Freq (4) + BW (4) + SF (1) + CR (1) |
| TxPower | 0x8C | Power dBm (1) |
| CurrentRssi | 0x8D | RSSI dBm (1, signed) |
| ChannelBusy | 0x8E | Result (1): 0x00=clear, 0x01=busy |
| Airtime | 0x8F | Milliseconds (4) |
| NoiseFloor | 0x90 | dBm (2, signed) |
| Version | 0x91 | Version (1) + Reserved (1) |
| Stats | 0x92 | RX (4) + TX (4) + Errors (4) |
| Battery | 0x93 | Millivolts (2) |
| MCUTemp | 0x94 | Temperature (2, signed) |
| Sensors | 0x95 | CayenneLPP payload |
| DeviceName | 0x96 | Name (variable, UTF-8) |
| Pong | 0x97 | - |
| SignalReport | 0x9A | Status (1): 0x00=disabled, 0x01=enabled |
| OK | 0xF0 | - |
| Error | 0xF1 | Error code (1) |
| TxDone | 0xF8 | Result (1): 0x00=failed, 0x01=success |
| RxMeta | 0xF9 | SNR (1) + RSSI (1) |
Fehlercodes
| Code | Value | Description |
|---|---|---|
| InvalidLength | 0x01 | Anforderungsdaten zu kurz |
| InvalidParam | 0x02 | Ungültiger Parameterwert |
| NoCallback | 0x03 | Funktion nicht verfügbar |
| MacFailed | 0x04 | MAC-Verifizierung fehlgeschlagen |
| UnknownCmd | 0x05 | Unbekannter Unterbefehl |
| EncryptFailed | 0x06 | Verschlüsselung fehlgeschlagen |
| TxBusy | 0x07 | Funk-TX belegt, oder Host-Ausgangswarteschlange voll |
Unaufgeforderte Ereignisse (Unsolicited Events)
Das TNC sendet diese SetHardware-Frames ohne vorherige Anfrage:
TxDone (0xF8): Wird gesendet, nachdem die Funkübertragung abgeschlossen ist. Enthält ein einzelnes Byte: 0x01 für Erfolg, 0x00 für Fehler. Die Übermittlung an den Host kann unter seriellem Gegendruck verzögert werden, wird aber nicht verworfen. RxMeta (0xF9): Wird nach jedem Standard-Datenframe (Typ 0x00) mit SNR (1 Byte, signed, Wert x4) und RSSI (1 Byte, signed, dBm) gesendet. Wird zusammen mit dem Datenframe in die Warteschlange gestellt; wird weggelassen, wenn der Datenframe nicht in die Warteschlange gestellt werden kann. Standardmäßig aktiviert; kann mit SetSignalReport umgeschaltet werden. Standard-KISS-Clients ignorieren diesen Frame.Datenformate
Funkparameter (SetRadio / Radio response)
Alle Werte sind Little-Endian.
| Feld | Size | Description |
|---|---|---|
| Frequency | 4 bytes | Hz (z.B. 869618000) |
| Bandwidth | 4 bytes | Hz (z.B. 62500) |
| SF | 1 byte | Spreading Factor (5-12) |
| CR | 1 byte | Coding Rate (5-8) |
Version (Version response)
| Feld | Size | Description |
|---|---|---|
| Version | 1 byte | Firmware-Version |
| Reserved | 1 byte | Immer 0 |
Verschlüsselt (Encrypted response)
| Feld | Size | Description |
|---|---|---|
| MAC | 2 bytes | HMAC-SHA256 auf 2 Bytes gekürzt |
| Ciphertext | variable | AES-128 Block-verschlüsselte Daten mit Null-Padding |
Sendezeit (Airtime response)
Alle Werte sind Little-Endian.
| Feld | Size | Description |
|---|---|---|
| Airtime | 4 bytes | uint32_t, geschätzte Sendezeit in Millisekunden |
Grundrauschen (NoiseFloor response)
Alle Werte sind Little-Endian.
| Feld | Size | Description |
|---|---|---|
| Noise floor | 2 bytes | int16_t, dBm (signed) |
Das Modem kalibriert das Grundrauschen alle 2 Sekunden neu, mit einem AGC-Reset (Automatic Gain Control) alle 30 Sekunden.
Statistiken (Stats response)
Alle Werte sind Little-Endian.
| Feld | Size | Description |
|---|---|---|
| RX | 4 bytes | Empfangene Pakete |
| TX | 4 bytes | Gesendete Pakete |
| Errors | 4 bytes | Empfangsfehler |
Batterie (Battery response)
Alle Werte sind Little-Endian.
| Feld | Size | Description |
|---|---|---|
| Millivolts | 2 bytes | uint16_t, Batteriespannung in mV |
MCU-Temperatur (MCUTemp response)
Alle Werte sind Little-Endian.
| Feld | Size | Description |
|---|---|---|
| Temperature | 2 bytes | int16_t, Zehntel °C (z.B. 253 = 25.3°C) |
Gibt den NoCallback-Fehler zurück, wenn das Board keine Temperaturmessungen unterstützt.
Gerätename (DeviceName response)
| Feld | Size | Description |
|---|---|---|
| Name | variable | UTF-8-String, kein Null-Terminator |
Neustart (Reboot)
Sendet eine OK-Antwort, leert die serielle Schnittstelle und startet dann das Gerät neu. Der Host sollte erwarten, dass die Verbindung getrennt wird.
Sensor-Berechtigungen (GetSensors)
| Bit | Value | Description |
|---|---|---|
| 0 | 0x01 | Basis (Batterie) |
| 1 | 0x02 | Standort (GPS) |
| 2 | 0x04 | Umgebung (Temperatur, Luftfeuchtigkeit, Druck) |
Verwenden Sie 0x07 für alle Berechtigungen.
Sensordaten (Sensors response)
Die Daten werden im CayenneLPP-Format zurückgegeben. Informationen zur Analyse finden Sie in der CayenneLPP-Dokumentation.
Kryptografische Algorithmen
| Operation | Algorithm |
|---|---|
| Identität / Signieren / Verifizieren | Ed25519 |
| Schlüsselaustausch | X25519 (ECDH – Elliptic Curve Diffie-Hellman) |
| Verschlüsselung | AES-128 Blockverschlüsselung mit Null-Padding + HMAC-SHA256 (MAC auf 2 Bytes gekürzt) |
| Hashing | SHA-256 |
Hinweise
- Die maximale Nutzlastgröße (255 Bytes) entspricht der MeshCore MAX_TRANS_UNIT (Maximum Transmission Unit); es sind keine Änderungen für die KISS-Empfehlung "1024+ empfohlen" erforderlich (dies gilt für allgemeine TNCs, nicht für MeshCore).
- Das Modem generiert die Identität beim ersten Start (wird im Flash-Speicher gespeichert).
- Alle Mehrbyte-Werte sind Little-Endian, sofern nicht anders angegeben.
- SNR-Werte (Signal-Rausch-Verhältnis) in RxMeta werden mit 4 multipliziert, um eine Präzision von 0,25 dB zu erreichen.
- TxDone wird nach jeder Übertragung als SetHardware-Ereignis gesendet.
- Standard-KISS-Clients empfangen nur Datenframes vom Typ 0x00 und können alle SetHardware-Frames (0x06) bedenkenlos ignorieren.
- Siehe packet_format.md für das Paketformat.