본문으로 건너뛰기

NMEA 0183 드라이버

개요

해양 / 선박 / GNSS 분야 표준 ASCII 프로토콜 NMEA 0183 v4.x 의 자체 자바 구현. NMEA 협회 공개 spec + 위키피디아 + 일반 매뉴얼 기반. 외부 라이브러리 / 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