NMEA 0183 ドライバ
概要
海洋 / 船舶 / GNSS 分野の標準 ASCII プロトコル NMEA 0183 v4.x の独自 Java 実装。NMEA 協会の公開 spec + Wikipedia + 一般マニュアルに基づく。外部ライブラリ / GitHub コードのコピーは一切なし。
| 項目 | 値 |
|---|---|
opc_type | NMEA |
| 実装クラス | 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.7 | sentence RMC の7番フィールド |
GGA.2 | GGA の2番フィールド (緯度) |
RMC.utc / RMC.lat / RMC.lon / RMC.speed | alias |
RMC | raw 文字列 (フィールドインデックス / alias 未指定) |
対応 sentence + alias
addAliases() が定義:
| type | alias 例 |
|---|---|
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 (最初のグループのみ) |
未定義の sentence でも 1..N のインデックスアクセスは可能。
対応 / 非対応
- ✅ checksum 検証 (
$~*の XOR)、不一致時は該当行を破棄 - ✅ Talker ID の自動除去 (例
GPRMC→RMC) - ✅ よく使われる16種 sentence の alias
- ✅ proprietary
$P...行をそのまま保持 - ❌
!encapsulation (AIVDM などの AIS) — 現在は$のみ受信 - ❌ multi-message GSV の累積
- ❌ write / Sentence 送信
テストカバレッジ
test/java/plantpulse/driver/protocol/nmea/
| クラス | テスト数 |
|---|---|
NMEADriverTest | 15 |
NMEASpecTest | 22 |
計 37 テスト — checksum、talker 分離、alias マッピング、インデックスアクセス、長さ上限。
参考
- NMEA 0183 v4 標準 (NMEA 協会の公開項目)
- コード:
src/plantpulse/driver/protocol/nmea/NMEADriver.java