Also known as: NMEA 0183, NMEA-0183, NMEA sentence
NMEA 0183 is the plain-text sentence format GPS receivers speak — a $, a five-character
talker-and-type tag, comma-separated fields, and an optional trailing *hh checksum.1 It
is not a radio protocol itself, but several trunked-radio GPS schemes (P25 Motorola Unit GPS,
Tait CCDI, many MOTOTRBO GPS profiles) transport a verbatim NMEA sentence as their payload, so
GopherTrunk parses it as the protocol-agnostic core that per-protocol decoders feed once they
have extracted a GPS message’s text.2
How it works
GopherTrunk’s ParseNMEA trims the sentence, requires the leading $, and — when a *hh
suffix is present — verifies the checksum before parsing any fields. It then splits on commas
and dispatches on the last three characters of the first field (the sentence type), ignoring the
two-character talker ID so any of GP, GN, GL and friends are accepted. Only two sentence
types carry a usable fix and are handled; anything else returns an “unsupported sentence” error
rather than a wrong guess.
GGA and RMC
The two supported sentences place their coordinate fields at fixed positions:
| Sentence | Meaning | Latitude field | Longitude field | Extra |
|---|---|---|---|---|
GGA |
Fix data | 2 (N/S in 3) | 4 (E/W in 5) | — |
RMC |
Recommended minimum | 3 (N/S in 4) | 5 (E/W in 6) | status (2), speed (7), course (8) |
RMC additionally carries a status letter — A for a valid fix, V for “void” — and GopherTrunk
returns ErrNoFix on a void sentence. When present, RMC’s speed (knots) and course (degrees)
fields are parsed into the position. A (0,0) result is treated as invalid: it is the
overwhelmingly common “no fix yet” placeholder, and Null Island is open ocean.
Coordinate decoding and checksum
NMEA reports coordinates as ddmm.mmmm for latitude and dddmm.mmmm for longitude — degrees
concatenated with decimal minutes — so nmeaDegrees splits off the leading degree digits (two
for latitude, three for longitude) and adds minutes / 60, then applies the hemisphere letter
as the sign. The checksum is deliberately trivial: the exclusive-OR of every byte of the
sentence body, the text strictly between $ and *.
// nmeaChecksum XORs every byte of an NMEA sentence body (between '$' and '*').
func nmeaChecksum(body string) byte {
var c byte
for i := 0; i < len(body); i++ {
c ^= body[i]
}
return c
}
That one-byte XOR is enough to catch the odd character corruption that a text-transport GPS link introduces, without the weight of a full cyclic redundancy check — appropriate for a format whose fields are already human-readable and self-delimiting.
Sources
-
NMEA 0183 — Wikipedia, on the sentence structure, talker IDs, GGA/RMC content and the XOR checksum. ↩
-
Global Positioning System — Wikipedia, on the GPS fixes NMEA sentences report. ↩