NMEA 0183 Treiber
Überblick
Eigene Java-Implementierung des ASCII-Standardprotokolls NMEA 0183 v4.x aus dem Bereich Marine / Schiffbau / GNSS. Basierend auf der öffentlichen Spezifikation der NMEA-Vereinigung, Wikipedia und allgemeinen Handbüchern. Keine externen Bibliotheken, kein kopierter GitHub-Code.
| Punkt | Wert |
|---|---|
opc_type | NMEA |
| Implementierungsklasse | plantpulse.driver.protocol.nmea.NMEADriver |
| Bibliothek | (keine — Eigenimplementierung. NMEA 0183 v4) |
| read | gut (basierend auf Empfangs-Cache) |
| write | ❌ (isWriteSupported() = false, nur Empfang) |
| Standardport | 10110 (NMEA over IP de facto) |
| Sicherheit | keine |
Für NMEA 0183 ist RS-232/RS-422 seriell (4800 / 38400 Baud) der Standard, im realen Betrieb ist jedoch NMEA over IP üblich, bei dem Multiplexer/Gateways die Daten über TCP oder UDP weiterleiten. Dieser Treiber verarbeitet die TCP-Variante.
Klassen / Struktur
NMEADriver (BaseProtocolDriver)
├── Socket / BufferedReader (US-ASCII)
├── receiverThread — daemon, "NMEA-Receiver-<opc_id>"
├── lastByType — ConcurrentHashMap<sentenceType, parsed map>
├── readLine() — CR/LF 분리 + MAX_LINE_LEN(256) 가드
├── processLine(line) — '$' / checksum 검증 / talker 제거 / 필드 split
├── addAliases(type, fields) — RMC/GGA/GLL/VTG/GSA/GSV/HDT/HDM/MWV/DBT/DPT/MTW/VHW/ZDA/XDR
└── xorChecksum(payload) — '$' 와 '*' 사이 XOR
socket.setSoTimeout(0) — für serielle Emulation / langsame Geräte.
Zusammenfassung des Wire-Formats
$<talker><sentence>,f1,f2,...,fN*<CC><CR><LF>
예) $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
- Talker ID 2 Zeichen (GP/GL/GN/GA/HC/II/AI ...) + Sentence Type 3 Zeichen.
- Das proprietäre Präfix
Pwird ohne Talker-Abtrennung direkt als Cache-Key verwendet. *<CC>Checksum = XOR aller Zeichen zwischen$und*(2-stelliger Hex-Wert, Großbuchstaben).- Längenbegrenzung 82 Zeichen (Standard NMEA 0183 v4), diese Implementierung nutzt eine
MAX_LINE_LEN=256-Guard.
Cache- / read-Format
Nachrichten, die processLine() passiert haben, werden unter dem Sentence Type (z. B. RMC) als Key in lastByType abgelegt:
parsed = {
"__raw__": "$GPRMC,...",
"__type__": "RMC",
"1": "123519", // utc
"2": "A", // status
...
// alias
"utc": "123519",
"lat": "4807.038",
...
}
read("RMC.7") → Feld 7 (speed). read("RMC.lat") → Alias.
OPC-Registrierungsoptionen
Ist options.nmea.port vorhanden, wird opc_agent_port des OPC überschrieben.
Keine Optionen connect-timeout / read-timeout — CONNECT_TIMEOUT_MS = 5000, soTimeout = 0.
Tag-Adressformat
| Notation | Bedeutung |
|---|---|
RMC.7 | Feld 7 des Sentence RMC |
GGA.2 | Feld 2 von GGA (Breitengrad) |
RMC.utc / RMC.lat / RMC.lon / RMC.speed | Alias |
RMC | Roh-String (kein Feldindex / Alias angegeben) |
Unterstützte Sentences + Alias
addAliases() definiert:
| type | Alias-Beispiele |
|---|---|
RMC | utc, status, lat, ns, lon, ew, speed, course, date, magvar, magvarew, mode |
GGA | utc, lat, ns, lon, ew, fix, sats, hdop, alt, altunit, geoidsep, sepunit, dgpsage, dgpsid |
GLL | lat, ns, lon, ew, utc, status, mode |
VTG | cogtrue, cogmag, speed, speedkn, speedkm, mode |
GSA | mode1, mode2, pdop, hdop, vdop |
GSV | totalmsgs, msgnum, satsinview |
HDT / HDM | heading, t / m |
MWV | angle, ref, speed, units, status |
DBT / DPT | depthft, depthm, depth, depthfa / depth, offset, max |
MTW | temp, units |
VHW | headingt, headingm, speed, speedkm |
ZDA | utc, day, month, year, tzh, tzm |
XDR | type, value, units, id (nur erste Gruppe) |
Auch bei nicht definierten Sentences ist der Indexzugriff 1..N möglich.
Unterstützt / nicht unterstützt
- ✅ Checksum-Prüfung (XOR von
$bis*), bei Abweichung wird die Zeile verworfen - ✅ Automatisches Entfernen der Talker ID (z. B.
GPRMC→RMC) - ✅ Aliase für 16 häufig verwendete Sentences
- ✅ Proprietäre
$P...-Zeilen bleiben unverändert erhalten - ❌
!Encapsulation (AIVDM u. a. AIS) — derzeit wird nur$verarbeitet - ❌ Akkumulation von Multi-Message-GSV
- ❌ write / Sentence-Versand
Testabdeckung
test/java/plantpulse/driver/protocol/nmea/
| Klasse | Anzahl Tests |
|---|---|
NMEADriverTest | 15 |
NMEASpecTest | 22 |
Insgesamt 37 Tests — Checksum, Talker-Abtrennung, Alias-Mapping, Indexzugriff, Längenbegrenzung.
Referenzen
- Standard NMEA 0183 v4 (öffentliche Angaben der NMEA-Vereinigung)
- Code:
src/plantpulse/driver/protocol/nmea/NMEADriver.java