If you are writing software that talks to an LX navigation instrument — a logger front end, a glass panel of your own, a piece of test gear, a soaring app that wants real sensor data instead of a phone's guesses — this is the protocol you will be speaking. It is called LX NMEA 2.0, it is ASCII, it is comma-separated, and it will not take you an afternoon to learn.
This article is an orientation rather than a field-by-field reference. It tells you where the protocol runs, how a sentence is built, what the two sentence families are for, which command groups exist, and where the exhaustive document lives. The last section covers NAVIA, which does not use this protocol at all and is worth reading even if you never touch an Era.
Where the protocol runs
Three outputs carry the selected sentences — the user port, the FLARM port and Bluetooth — and two of them are worth describing. The user port is an RS232 UART serial interface — 8 data bits, no parity, baud rate anywhere from 4800 to 115200, with 38400 the default on an Era, LX 10K or Colibri X. The Bluetooth interface, on instruments that have one, serves the identical stream once the instrument is put into Bluetooth server mode.
Which sentences the instrument emits is a set of tick boxes under Setup › NMEA, and for anything you are developing against you want all of GPGGA, GPRMC, GPRMB, LXWPx, LXDT, LXBC and PFLAx. Note that LXDT is the one enabling input as well as output. Without it your requests go nowhere and you will spend an hour blaming your checksum routine.
What else is on the wire
Your parser will see more than LX sentences, because the instrument forwards standard traffic alongside its own:
| Prefix | Source | Carries |
|---|---|---|
$GPGGA | GNSS module | Fix information |
$GPRMC | GNSS module | Recommended minimum GPS data |
$GPRMB | Instrument | Recommended minimum navigation info |
$PFLAx | Connected FLARM | PFLAU, PFLAA, PFLAC, PFLAE, PFLAL, PFLAQ — see FLARM's own documentation |
$LXWPx | Instrument | LXWP0 flight data, LXWP1 device info, LXWP2 basic and LXWP3 detailed parameters |
The LXWP family belongs to the older LX NMEA 1.0 protocol, which is still documented and still emitted; LX NMEA 2.0 is an extension of it rather than a replacement, so a robust parser handles both.
Sentence anatomy
Every sentence starts with $, names a data type, carries zero or more comma-separated parameters, and ends with *, a two-byte checksum in hex, then <CR><LF> (0x0D 0x0A). Two data types exist.
$LXBC,<sentence_code>,<parameter_1>,...,<parameter_n>*<CRC><CR><LF>
$LXDT,<sentence_action>,<sentence_code>,<parameter_1>,...,<parameter_n>*<CRC><CR><LF>LXBC is broadcast — the instrument talking without being asked. LXDT is data transfer — a request/response conversation. Parameters are typed but untagged — position is everything. An invalid or unconfigured value is sent as an empty field, not as a zero or a sentinel, so $LXBC,AHRS,,,,,0.8,-0.3,-0.6*3e is a perfectly valid sentence saying the attitude solution is not available but the accelerometers are.
The checksum
Eight-bit XOR of every byte between the $ (excluded) and the * (excluded), transmitted as two ASCII hex characters:
uint8_t byCRC = 0;
for(int32_t i=0; i<iN; i++)
{
byCRC ^= pString[i];
}That is the whole algorithm. It is a XOR, not a hash, so collisions are ordinary rather than remarkable — LXDT,GET,INFO and LXDT,ANS,OK both come to 5c. Do not use the checksum to identify a sentence.
$LXBC: the broadcasts
Four broadcast sentences, each carrying a different slice of the aircraft's state.
| Code | Carries | Interval |
|---|---|---|
AHRS | Pitch, roll, yaw, slip, and G-force in three axes | Settable |
SENS | OAT, main and backup voltage, current and recommended flap, gear position, SC/vario mode | Settable |
FAST | IAS, TAS, altitude, vario, netto, fusion vario, SC/vario mode — up to 10 Hz | Settable, off by default |
FUSION | Fusion netto and smart vario, instant and average wind, solution confidence and status | Fixed at 2 s, not configurable |
Two traps live in that table. FAST is disabled by default and its interval is not remembered across a power cycle, so your software must enable it on every connection. FUSION requires a valid fusion licence, rides along with the LXWP block (so LXWPx output must be enabled), has no GET request at all, and leaves its value fields empty until the solution locks.
Intervals are read with GET,BC_INT and written with SET,BC_INT as <type>,<interval> pairs — keywords AHRS, SENS, FAST, or ALL to set them together, as in $LXDT,SET,BC_INT,AHRS,0.5,SENS,2,FAST,0.1*7e. The value is seconds as a float, minimum 0.1, and 0 disables the broadcast.
$LXDT: GET, SET and ANS
Three actions, and the whole conversational model fits in one line each: GET — your device asks the instrument for data. SET — your device sends data to the instrument. ANS — the instrument answers, either way.
The instrument responds to everything. A SET it accepted returns ANS,OK; a GET returns the corresponding ANS,<code>; anything it did not understand returns ANS,ERROR.
The command groups
| Code | GET | SET | What it covers |
|---|---|---|---|
INFO | Yes | — | Device name, serial, software and hardware version |
TP, ZONE | Yes | Yes | Task turnpoints and observation zones |
GLIDER, PILOT | Yes | Yes | Glider registration, competition ID, class; pilot name |
TSK_PAR | Yes | Yes | AAT time and finish altitude |
MC_BAL | Yes | Yes | MacCready, ballast, bugs, volume — also emitted automatically on change |
SENS | Yes | — | The sensor block, on demand rather than broadcast |
SC_VAR | Yes | Yes | Speed-command / vario mode state |
NAVIGATE | Yes | Yes | Current destination: name, position, elevation, distance, bearing, and for airports the frequency and runway direction |
RADIO | Yes | Yes | Active and standby frequency, volume, squelch, VOX — emitted on any change |
R_SWITCH, R_DUAL, R_SPACING | — | Yes | Swap frequencies, dual watch, 25 / 8.33 kHz spacing |
FLIGHTS_NO, FLIGHT_INFO | Yes | — | Logbook contents |
EVENT | — | Yes | Trigger a pilot event in the IGC log and on the CAN bus |
ERROR, OK | — | — | Response codes only |
Note that NAVIGATE exposes the destination's frequency; the instrument's own Send APT freq. setting is what pushes it to the radio. If you are building anything that touches the radio, read connecting a radio to an LX instrument alongside this.
A worked exchange
Ask the instrument what the radio is doing:
TX: $LXDT,GET,RADIO*03<CR><LF>
RX: $LXDT,ANS,RADIO,128.800,118.475,10,5,33*1c<CR><LF>The request has no parameters, so the checksummed span is exactly LXDT,GET,RADIO; XOR its 14 bytes and you get 0x03. The response reports active 128.800, standby 118.475, volume 10, squelch 5, VOX 33, over a span checksumming to 0x1c. Both verify against the algorithm above — worth doing once by hand, because it settles any doubt about which bytes you should be including.
Declaring a task
Task declaration is not a single command. It is a sequence: each point via SET,TP (takeoff, start, turnpoints, finish, landing — indexed from zero), each observation zone via SET,ZONE, then SET,TSK_PAR for AAT time and finish altitude, then SET,GLIDER and SET,PILOT for the header. Every one gets its own ANS,OK before you send the next. The protocol document ends with a complete communication log of exactly this, for a task with takeoff, start, one turnpoint, finish and landing — copy its shape rather than guessing at it.
Errors, and the silence that means a bad checksum
An error response carries a human-readable description, which is more than most binary protocols manage:
RX: $LXDT,ANS,ERROR,Parameter count mismatch*02<CR><LF>The failure that catches people out is the one with no sentence attached at all. If a request draws no response whatsoever, the cause is almost always an incorrect checksum: the instrument discards what it cannot verify rather than complaining about it. Silence is a failure mode here, not an idle link.
| Symptom | Cause | Fix |
|---|---|---|
| No response at all to a valid-looking request | Incorrect checksum | XOR every byte between $ and *, excluding both |
SET,SC_VAR ignored | SC mode not Manual, or SC switch not Toggle | Set Setup › Vario/SC › SC mode = Manual and Setup › Glider › SC switch = Toggle |
ANS,ERROR to GET,RADIO | No radio connected, or radio disabled in settings | Check Setup › NMEA › Radio |
FAST broadcasts stop after a power cycle | The interval is not remembered | Re-send SET,BC_INT on every connection |
No FUSION sentence at all | LXWPx output off, or no fusion licence | Enable LXWPx; check the licence |
FUSION fields empty | Not locked — status low byte is not 3 | Check the status field before parsing the values |
Error from GET,FLIGHTS_NO | Logbook access is refused in flight | Expected behaviour — wait until the flight has ended |
AHRS pitch, roll, yaw and slip blank | Attitude solution invalid | Not a parse error; the G-force fields are still good |
NAVIA is a different animal
NAVIA does not extend this protocol; it replaces the whole idea. The Core Pro was designed around an open data concept, and everything the system captures — AHRS telemetry, engine parameters, live traffic, GPS — is available over the local network through a bidirectional WebSocket and REST API.
Bidirectional is the interesting word. NAVIA does not only serve data, it accepts it: build a custom sensor or an unusual piece of hardware, push its telemetry into the API, and the Core Pro processes and routes it alongside its own. For people who want to build the hardware too, there is a dedicated development board for prototyping devices that talk natively to the ecosystem.
API documentation, integration guides and sample code are public at https://github.com/LXNavigation/navia-open-platform. The platform itself is described in the NAVIA Core Pro documentation.
Where to go next
- The full field-by-field protocol document, with every parameter, data type and range, is a PDF in the download centre.
- Getting a device physically connected first: connecting XCSoar, Oudie and other PDAs.
- Background on what the numbers mean: GNSS and the CAN bus.
- Building something and stuck on a detail the document does not cover: talk to us.