メインコンテンツまでスキップ

NMEA 0183 ドライバ

概要

海洋 / 船舶 / GNSS 分野の標準 ASCII プロトコル NMEA 0183 v4.x の独自 Java 実装。NMEA 協会の公開 spec + Wikipedia + 一般マニュアルに基づく。外部ライブラリ / GitHub コードのコピーは一切なし。

項目
opc_typeNMEA
実装クラスplantpulse.driver.protocol.nmea.NMEADriver
ライブラリ(なし — 独自実装。NMEA 0183 v4)
read良好 (受信キャッシュベース)
write❌ (isWriteSupported() = false、受信専用)
デフォルトポート10110 (NMEA over IP の de-facto)
セキュリティなし
原本メディア

NMEA 0183 は RS-232/RS-422 シリアル (4800 / 38400 baud) が標準ですが、実運用ではマルチプレクサ/ゲートウェイが TCP または UDP へ forwarding した NMEA over IP が一般的であり、本ドライバは TCP 変形を受信します。


クラス / 構造

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) — シリアルエミュレーション / 低速機器への対応。


wire フォーマット概要

$<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文字 (GP/GL/GN/GA/HC/II/AI ...) + sentence type 3文字。
  • Proprietary P プレフィックスは talker を分離せずそのままキャッシュキーとして使用。
  • *<CC> checksum = $* の間のすべての char の XOR (2桁 hex 大文字)。
  • 長さ上限は 82文字 (NMEA 0183 v4 標準)、本実装は MAX_LINE_LEN=256 でガード。

キャッシュ / read 形式

processLine() を通過したメッセージは sentence type (例 RMC) をキーとして lastByType に格納:

parsed = {
"__raw__": "$GPRMC,...",
"__type__": "RMC",
"1": "123519", // utc
"2": "A", // status
...
// alias
"utc": "123519",
"lat": "4807.038",
...
}

read("RMC.7") → 7番フィールド(speed)。read("RMC.lat") → alias。


OPC 登録オプション

options.nmea.port があれば OPC の opc_agent_port を override。

connect-timeout / read-timeout オプションなし — CONNECT_TIMEOUT_MS = 5000、soTimeout = 0。


タグアドレス形式

表記意味
RMC.7sentence RMC の7番フィールド
GGA.2GGA の2番フィールド (緯度)
RMC.utc / RMC.lat / RMC.lon / RMC.speedalias
RMCraw 文字列 (フィールドインデックス / alias 未指定)

対応 sentence + alias

addAliases() が定義:

typealias 例
RMCutc, status, lat, ns, lon, ew, speed, course, date, magvar, magvarew, mode
GGAutc, lat, ns, lon, ew, fix, sats, hdop, alt, altunit, geoidsep, sepunit, dgpsage, dgpsid
GLLlat, ns, lon, ew, utc, status, mode
VTGcogtrue, cogmag, speed, speedkn, speedkm, mode
GSAmode1, mode2, pdop, hdop, vdop
GSVtotalmsgs, msgnum, satsinview
HDT / HDMheading, t / m
MWVangle, ref, speed, units, status
DBT / DPTdepthft, depthm, depth, depthfa / depth, offset, max
MTWtemp, units
VHWheadingt, headingm, speed, speedkm
ZDAutc, day, month, year, tzh, tzm
XDRtype, value, units, id (最初のグループのみ)

未定義の sentence でも 1..N のインデックスアクセスは可能。


対応 / 非対応

  • ✅ checksum 検証 ($~* の XOR)、不一致時は該当行を破棄
  • ✅ Talker ID の自動除去 (例 GPRMCRMC)
  • ✅ よく使われる16種 sentence の alias
  • ✅ proprietary $P... 行をそのまま保持
  • ! encapsulation (AIVDM などの AIS) — 現在は $ のみ受信
  • ❌ multi-message GSV の累積
  • ❌ write / Sentence 送信

テストカバレッジ

test/java/plantpulse/driver/protocol/nmea/

クラステスト数
NMEADriverTest15
NMEASpecTest22

計 37 テスト — checksum、talker 分離、alias マッピング、インデックスアクセス、長さ上限。


参考

  • NMEA 0183 v4 標準 (NMEA 協会の公開項目)
  • コード: src/plantpulse/driver/protocol/nmea/NMEADriver.java