Firmware Internals
Second round of reverse engineering targeting binaries from the Waveshare LC29H wiki downloads. The first round analyzed QGNSS.exe and QNMEA.dll; this round covers the QXWZ RTK SDK, firmware update tool, bootloader, and log analyzer.
Targets
Section titled “Targets”| Binary | Type | Size | Functions | Purpose |
|---|---|---|---|---|
libqxwz-pssdk-1.5.0 | ARM ELF 32-bit | 233 KB | 826 | QXWZ RTK positioning SDK |
FlashUpdater4775_CL389797_r.exe | Win32 PE | 2.3 MB | 14,425 | LC29H firmware update tool |
bootloader.pkg | Raw firmware (f3f2f1f0) | 20 KB | N/A | Broadcom bootloader package |
QGNSSLog.exe | Win64 PE | 2.0 MB | 4,143 | NMEA log analyzer/plotter |
1. QXWZ PSSDK
Section titled “1. QXWZ PSSDK”Overview
Section titled “Overview”- Architecture: ARM:LE:32:v8 (ARMv8-A 32-bit, little-endian)
- Stripped: No (full symbols — 826 named functions)
- Compiler: GCC 4.8.3 (Linaro GCC 2014.03)
- Vendor: QXWZ (Qianxun Spatial Intelligence)
QXWZ operates China’s national high-precision positioning network, providing RTK corrections via their “FindCM” service. This SDK is the client-side library for accessing that service on embedded Linux (Raspberry Pi).
Architecture
Section titled “Architecture”The SDK has a clean layered architecture with six major subsystems:
graph TD
SDK["qxwz_sdk_init / qxwz_sdk_start / qxwz_sdk_tick"]
SDK --> Account & Auth & Capabilities & Config & PubSub["Data Pub/Sub"] & Manager
Account & Auth & Capabilities --> OpenAPI["OpenAPI · HTTP REST\nqxwz_http_*"]
Config & PubSub & Manager --> OSS["OSS · MQTT-based\nqxwz_oss_*"]
OpenAPI & OSS --> Socket["Socket Layer\nqxwz_sock_* / qxwz_dns_*"]
SDK Lifecycle
Section titled “SDK Lifecycle”From decompilation of qxwz_sdk_init():
qxwz_log_init()— Initialize loggingsdk_mutex_init()— Create thread-safety mutexsdk_check_config(config)— Validate configuration structsdk_check_serv_conf()— Validate server configurationsdk_init_modules()— Initialize all subsystems- Set account credentials: key type, key, secret, device ID, device type
- Four additional callback function pointers stored from config
Error codes: -1 (mutex fail), -3 (bad config), -9 (already initialized), -15 (bad server config).
Configuration System
Section titled “Configuration System”qxwz_sdk_config() accepts a type code and config pointer:
| Type | Function | Description |
|---|---|---|
| 0 | qxwz_set_serv_conf() | Server host/port configuration |
| 1 | qxwz_set_oss_conf() | OSS (MQTT) connection settings |
| 2 | qxwz_set_bds3_fmt() | BDS-3 signal format preference |
| 3 | qxwz_set_net_timeout() | Network timeout values |
| 4 | qxwz_dns_set_server() | Custom DNS server (16 entries max) |
Default API endpoint: openapi.qxwz.com
Authentication Protocol
Section titled “Authentication Protocol”The auth system uses a Device Service Key (DSK) model with two key types:
Key Type 1 — Standard DSK flow:
auth_get_timestamp()— Sync time with QXWZ serversauth_reload_dsk()— Reload existing DSK from storageauth_alloc_dsk2()— Allocate a new DSK2 (v2 format)
Key Type 2 — Alternative auth path (possibly enterprise/OEM) with a different serial work sequence during auth_start().
Account credentials from the config struct:
| Offset | Field | Max Size |
|---|---|---|
0x00 | key_type | 4 bytes (int) |
0x04 | key | 128 bytes |
0x84 | secret | 128 bytes |
0x104 | device_id | 128 bytes |
0x184 | device_type | 128 bytes |
Signature Algorithm
Section titled “Signature Algorithm”The qxwz_signature() function implements HMAC-SHA384 request signing with deterministic canonicalization:
Algorithm:
- Format the secret into a key string (max 256 chars)
- Format the timestamp into a nonce string (max 64 chars)
- Sort key-value pairs alphabetically by key (bubble sort with
strcmp) — ensures deterministic signatures regardless of parameter order - Initialize HMAC-SHA384 with the formatted secret as the HMAC key
- Feed data in strict order: path string → sorted k-v pairs (key then value) → timestamp nonce
- Sign → 48 bytes (384 bits)
- Hex-encode to 96-character lowercase hex string
The signature is appended as _sign parameter to API requests.
MQTT Authentication
Section titled “MQTT Authentication”Client ID (oss_sess_generate_clientid): Random UUID-like identifier with 5 groups of hex characters separated by dashes, generated via qxwz_gen_random_num() % 16.
Password (oss_sess_generate_password): A JSON object containing a signed device credential:
{ "deviceInfo": "<device_id>/<device_type>", "version": "<sdk_version>/<protocol_version>", "timestamp": 1234567890, "sign": "abcdef0123456789...96chars..."}The MQTT broker verifies the HMAC signature on every connection, providing per-session authentication tied to the device’s secret key.
Cryptography
Section titled “Cryptography”| Function | Algorithm | Usage |
|---|---|---|
qxwz_signature() | HMAC-SHA384 | API request signing |
qxwz_aes_cbc_encrypt/decrypt() | AES-128-CBC | DSK file encryption/decryption |
qxwz_crc24q() | CRC-24Q | RTCM3 frame validation |
qxwz_md5() | MD5 | Legacy hashing |
qxwz_base64_encode/decode() | Base64 | HTTP auth encoding |
The presence of qxwz_crc24q() confirms RTCM3 data handling — CRC-24Q is the standard RTCM 3.x frame check sequence.
OSS Protocol — MQTT-Based Correction Streaming
Section titled “OSS Protocol — MQTT-Based Correction Streaming”The “OSS” (Online Service System) is a custom MQTT v3.1 client. The protocol string MQIsdp at address 0x3d058 identifies MQTT v3.1 (v3.1.1 uses "MQTT" instead).
Connection state machine:
stateDiagram-v2
[*] --> UNCONNECTED
UNCONNECTED --> TCP_CONNECTING
TCP_CONNECTING --> TCP_CONNECTED
TCP_CONNECTED --> CONNECTING: MQTT CONNECT sent
CONNECTING --> CONNECTED: CONNACK received
CONNECTED --> DISCONNECTING
DISCONNECTING --> [*]
Data flow: GGA position is published upstream via qxwz_sdk_upload_gga() (max 256 bytes, requires state 0x03 “running”), and RTCM corrections are received via MQTT PUBLISH on subscribed topics.
SIDS Decoder
Section titled “SIDS Decoder”SIDS is QXWZ’s proprietary compact correction format using RTCM3 framing with proprietary payload encoding.
Frame structure:
packet-beta 0-7: "0xD2 Preamble" 8-13: "Reserved" 14-23: "Length (10-bit)" 24-55: "Payload (variable)" 56-79: "CRC-24Q (3 bytes)"
- Preamble:
0xD2(same as standard RTCM3) - Length: 10-bit field at bit offset 14
- CRC: 24-bit CRC-24Q, identical to RTCM3
Payload encoding uses bit-level extraction (qxwz_ubit_get()):
| Offset (bits) | Width | Field |
|---|---|---|
| 24 | 10 | constellation_id |
| 34 | 16 | signal_id |
| 50 | 30 | correction_data |
| 80 | 1 | status flag |
| 81 | 7 | type qualifier |
| 88+ | variable | satellite/signal masks + data |
Constellation ID mapping: 1=GPS, 4=GLONASS, 8=Galileo, 32=BeiDou.
OpenAPI REST Endpoints
Section titled “OpenAPI REST Endpoints”| Path | Description |
|---|---|
/rest/qxwz.core.reloadDSK | Reload device service key |
/rest/qxwz.core.allocateDSK.2 | Allocate new DSK v2 |
/rest/qxwz.core.queryDSK | Query DSK status |
/rest/qxwz.core.activateDSK.2 | Activate DSK v2 |
/rest/qxwz.core.resumeDSK | Resume expired DSK |
/rest/nosr.dsk.getCoordinateFrame | Get coordinate system |
/rest/nosr.dsk.setCoordinateFrame | Set coordinate system |
/rest/nosr.dsk.getConfig | Get NOSR configuration |
Supports WGS-84 and CGCS2000 coordinate systems.
2. FlashUpdater4775
Section titled “2. FlashUpdater4775”Overview
Section titled “Overview”- Architecture: x86 32-bit Windows PE (MSVC statically linked)
- Functions: 14,425
- Chip target: BCM4775 (Broadcom GNSS SoC in LC29H)
- Source path:
d:\gps\v10_4775bettab1\proprietary\deliverables\lhe2_dev\
The binary self-identifies as “BCM4775 Flash Updater” — revealing that the LC29H contains a Broadcom BCM4775 GNSS SoC (not MediaTek as initially assumed from the bootloader magic bytes).
Protocol Architecture
Section titled “Protocol Architecture”graph TD
FU["FlashUpdater\n(application layer)"]
LH["LhEngine\n(Link Handler engine)"]
RPC["RPC Engine\n(Remote Procedure Call layer)"]
TL["Transport Layer\n(packet framing, retransmit)"]
HAL["HAL\n(UART / SPI / I2C)"]
FU --> LH --> RPC --> TL --> HAL
Firmware Downloader State Machine
Section titled “Firmware Downloader State Machine”Decompilation of firmware_downloader.cpp reveals an 18-state FSM:
| State | Name | Action |
|---|---|---|
| 0 | FD_IDLE | Idle / Done |
| 1 | FD_REQUEST_DOWNLOAD | Set sync target to ROM, connect to ASIC |
| 2 | FD_WAIT4AUTOBAUD | Send auto-baud byte sequence |
| 3 | FD_SENT_AUTOBAUD | Wait for auto-baud response |
| 5 | FD_GOT_SYNC | Route to ROM (7) or RAM (14) sync target |
| 6 | FD_TIMEOUT_SYNC | Retry or fail |
| 7 | FD_GOT_SYNC_INIT | ROM SYNC received, send version request |
| 8 | FD_WAIT4VERSION_INIT | Waiting for ROM version response |
| 9 | FD_GOT_VERSION_INIT | Validate chip ID, decide next phase |
| 10 | FD_ROMRESET | ROM version mismatch, reset ASIC |
| 11 | FD_WAIT4DOWNLOAD_START | Initialize patch, begin transfer |
| 12 | FD_DOWNLOADING | Transfer patch data (500ms timeout) |
| 13 | FD_WAIT4APP | Wait for app to start |
| 14 | FD_GOT_SYNC_CONFIRM | RAM SYNC received, send version request |
| 15 | FD_WAIT4VERSION_CONFIRM | Waiting for RAM version |
| 16 | FD_GOT_VERSION_CONFIRM | Patch verified, notify completion |
| 17 | FD_DONE | Clean up, signal complete |
BCM477x Chip ID Table
Section titled “BCM477x Chip ID Table”State 9 validates the chip version register against supported BCM GNSS SoC revisions:
| Chip ID | SoC |
|---|---|
0x47730A30 | BCM4773 rev A30 |
0x47730A20 | BCM4773 rev A20 |
0x004774A0 | BCM4774 rev A0 |
0x004775A0 | BCM4775 rev A0 |
0x004775A1 | BCM4775 rev A1 |
0x004775B0 | BCM4775 rev B0 |
0x034775B0 | BCM4775 rev B0 (variant 3) |
0x074775B0 | BCM4775 rev B0 (variant 7) |
0x054775B0 | BCM4775 rev B0 (variant 5) |
0x044775B0 | BCM4775 rev B0 (variant 4) |
0x0D4775B1 | BCM4775 rev B1 (variant D) |
0x044775B1 | BCM4775 rev B1 (variant 4) |
0x004775B1 | BCM4775 rev B1 |
This confirms the LC29H module family uses the Broadcom BCM4773/4774/4775 GNSS SoC family. The variant prefix byte likely indicates package or OEM configuration.
Protocol Flow
Section titled “Protocol Flow”stateDiagram-v2
[*] --> REQUEST_DOWNLOAD: set sync target = ROM
REQUEST_DOWNLOAD --> AUTOBAUD
AUTOBAUD --> SENT_AUTOBAUD
SENT_AUTOBAUD --> GOT_SYNC: sync received
SENT_AUTOBAUD --> TIMEOUT: timeout
TIMEOUT --> AUTOBAUD: retry
GOT_SYNC --> GOT_SYNC_INIT: route to ROM
GOT_SYNC_INIT --> WAIT4VERSION: send version request
WAIT4VERSION --> GOT_VERSION: validate chip ID
GOT_VERSION --> WAIT4DOWNLOAD_START
WAIT4DOWNLOAD_START --> DOWNLOADING
DOWNLOADING --> WAIT4APP: patch transfer complete
WAIT4APP --> GOT_SYNC_CONFIRM: set sync target = RAM
GOT_SYNC_CONFIRM --> WAIT4VERSION_CONFIRM
WAIT4VERSION_CONFIRM --> GOT_VERSION_CONFIRM: patch verified
GOT_VERSION_CONFIRM --> DONE
DONE --> [*]
Flash Operations (RPC)
Section titled “Flash Operations (RPC)”After the bootloader patch loads, 6 RPC commands become available:
| RPC ID | Function |
|---|---|
| 6 | Flash Read |
| 9 | Flash Write |
| 10 | Flash Erase |
| 35 | Flash Config Query |
| 36 | Flash CRC Verify |
| 39 | Flash Status |
Flash operation sequence:
- Query flash config (RPC 35) — Get flash size and sector erase time
- Backup (optional, RPC 6) — Read entire flash to
FlashBackup_YYYYMMDD-HHMMSS.bin - Erase (RPC 10) — Erase sectors for new image (4KB sector-aligned)
- Write (RPC 9) — Write new image to flash
- Verify (RPC 36) — Read back and CRC compare
Command-Line Interface
Section titled “Command-Line Interface”FlashUpdater4775 [options] flash_bin_file
Options: eraseTime=<ms> # 4KB sector erase time flashOffset=<byte_offset> # Write offset (hex with 0x prefix) skipBackup=true|false # Skip flash backup patchFile=<patch_file> # Download patch first retrieveFile=<local_file> # Read flash to local file retrieveLength=<num_bytes> # Flash read length
HAL Configuration: HALserial=uart # or i2c or spi HALcom=COM20 # Serial port HALbaud=115200 # Baud rate HALgpio=COM3 # GPIO portSerial Hardware Support
Section titled “Serial Hardware Support”| Chip | Interface | HAL Classes |
|---|---|---|
| FTDI | UART + GPIO + SPI | FtdiGpio, FtSpiHal, FtSpiDev |
| CP210x (Silicon Labs) | USB-UART | CP21x library |
| CP213x (Silicon Labs) | USB-SPI | UsbSpiCp2130 |
3. Bootloader Package
Section titled “3. Bootloader Package”Overview
Section titled “Overview”- Magic bytes:
f3 f2 f1 f0(Broadcom firmware container header) - Size: 20,092 bytes
- Target: BCM4775 GNSS SoC
Header Analysis
Section titled “Header Analysis”Offset Bytes Interpretation0x00 f3 f2 f1 f0 Broadcom package magic (descending sequence)0x04 ac dd c1 11 Package identifier / version0x08 21 11 17 20 Build timestamp or version0x0c 5c 4e 00 00 Payload size (0x4E5C = 20,060 bytes ≈ file - header)0x20 48 00 00 18 Code entry / branch table0x24 48 00 00 8e Code entry / branch tableThe value at offset 0x0C (0x4E5C = 20,060) equals the file size minus the header (20,092 - 32 = 20,060), confirming it encodes the payload length.
Relationship to FlashUpdater
Section titled “Relationship to FlashUpdater”The bootloader is downloaded to BCM4775 RAM via the FlashUpdater’s patch mechanism (FSM states 11-12). It serves as a “Scratch APP” bootstrap that:
- Gets loaded to RAM at the specified
PatchAddress - Starts executing (jump from ROM to RAM code)
- Registers the 6 RPC flash command handlers
- Enables flash read/write/erase operations via the RPC protocol
Without this bootloader, the host cannot access the SPI flash through the GNSS chip — the ROM bootloader only supports download, not flash operations.
4. QGNSSLog
Section titled “4. QGNSSLog”Overview
Section titled “Overview”- Architecture: x86-64, Windows PE
- Version: QGNSSLog_V1.2.4
- Framework: Qt5 (QCustomPlot for visualization)
QGNSSLog is a standalone NMEA log file viewer and signal analyzer. It opens recorded .log, .txt, or .nma files and plots satellite signal quality metrics (SNR/C/N0, elevation, azimuth) over time.
Unlike QGNSS.exe (which commands live hardware), QGNSSLog performs no serial I/O — it is purely a post-processing visualization tool.
QNMEA.dll Log Analysis API
Section titled “QNMEA.dll Log Analysis API”QGNSSLog imports 7 functions from QNMEA.dll, revealing a log analysis API not discovered in round 1:
| Import | Purpose |
|---|---|
QNMEA_NEW | Create parser instance |
QNMEA_DELETE | Destroy parser instance |
Read_log | Parse an entire log file |
set_qlog_data_cb | Register per-sentence data callback |
set_qlog_status_cb | Register progress/status callback |
Set_Read_PKG | Set read buffer size (1 MB) |
Set_Qlog_cfg | Pass filter configuration |
Data pipeline:
sequenceDiagram
participant App as QGNSSLog.exe
participant Lib as QNMEA.dll
App->>Lib: QNMEA_NEW()
Note right of Lib: Create parser
App->>Lib: set_qlog_data_cb(fn, ctx)
App->>Lib: set_qlog_status_cb(fn)
App->>Lib: Set_Read_PKG(0x100000)
Note right of Lib: 1 MB buffer
App->>Lib: Set_Qlog_cfg(&cfg)
App->>Lib: Read_log(filepath)
Lib-->>App: data_cb(sentence, ctx)
Note left of App: Per sentence
Lib-->>App: status_cb(progress)
Note left of App: Periodic
App->>Lib: QNMEA_DELETE()
Note right of Lib: Cleanup
Filter Configuration
Section titled “Filter Configuration”The QLOG_CFG struct (loaded from FilterOptions.ini):
struct QLOG_CFG { uint8_t elevation; // min satellite elevation (degrees) uint8_t snr_cn0; // min SNR/C/N0 threshold (dB-Hz) uint8_t reserved[2]; // padding uint16_t azimuth; // azimuth filter (degrees)};GNSS Signal Catalog
Section titled “GNSS Signal Catalog”QGNSSLog contains the most comprehensive signal reference found in any Quectel binary: 52 signals across 7 constellations plus SBAS augmentation.
GPS (8 signals)
Section titled “GPS (8 signals)”| Signal | Band | Description |
|---|---|---|
| L1 C/A | 1575.42 MHz | Civilian standard |
| L1 P(Y) | 1575.42 MHz | Military precision (encrypted) |
| L1M | 1575.42 MHz | Military M-code |
| L2 P(Y) | 1227.60 MHz | Precision on L2 |
| L2C-M | 1227.60 MHz | Civilian medium-length code |
| L2C-L | 1227.60 MHz | Civilian long code |
| L5-I | 1176.45 MHz | In-phase component |
| L5-Q | 1176.45 MHz | Quadrature component |
GLONASS (4 signals)
Section titled “GLONASS (4 signals)”| Signal | Band | Description |
|---|---|---|
| G1 C/A | ~1602 MHz | Standard accuracy |
| G1P | ~1602 MHz | High accuracy |
| G2 C/A | ~1246 MHz | Standard accuracy |
| G2P | ~1246 MHz | High accuracy |
Galileo (7 signals)
Section titled “Galileo (7 signals)”| Signal | Band | Description |
|---|---|---|
| E5a | 1176.45 MHz | Open service (= L5) |
| E5b | 1207.14 MHz | Open service |
| E5a+b | 1191.795 MHz | AltBOC wideband |
| E6A | 1278.75 MHz | Public Regulated Service |
| E6BC | 1278.75 MHz | Commercial Service |
| L1A | 1575.42 MHz | Public Regulated Service |
| L1BC | 1575.42 MHz | Open service (= L1) |
BeiDou (12 signals)
Section titled “BeiDou (12 signals)”| Signal | Band | Description |
|---|---|---|
| B1I | 1561.098 MHz | BDS-2 open service |
| B1Q | 1561.098 MHz | BDS-2 authorized |
| B1C | 1575.42 MHz | BDS-3 open (= L1/E1) |
| B1A | 1575.42 MHz | BDS-3 authorized |
| B2a | 1176.45 MHz | BDS-3 open (= L5/E5a) |
| B2b | 1207.14 MHz | BDS-3 open (= E5b) |
| B2a+b | 1191.795 MHz | BDS-3 wideband (= E5a+b) |
| B3I | 1268.52 MHz | BDS-2/3 open |
| B3Q | 1268.52 MHz | BDS-2 authorized |
| B3A | 1268.52 MHz | BDS-3 authorized |
| B2I | 1207.14 MHz | BDS-2 open |
| B2Q | 1207.14 MHz | BDS-2 authorized |
QZSS (10 signals)
Section titled “QZSS (10 signals)”| Signal | Band | Description |
|---|---|---|
| L1 C/A | 1575.42 MHz | GPS-compatible |
| L1CD / L1CP | 1575.42 MHz | L1C data/pilot channels |
| L1S | 1575.42 MHz | Sub-meter augmentation |
| L2C-M / L2C-L | 1227.60 MHz | GPS-compatible L2C |
| L5-I / L5-Q | 1176.45 MHz | L5 in-phase/quadrature |
| L6D | 1278.75 MHz | CLAS data |
| L6E | 1278.75 MHz | MADOCA |
NavIC / IRNSS (5 signals)
Section titled “NavIC / IRNSS (5 signals)”| Signal | Band | Description |
|---|---|---|
| L5 SPS | 1176.45 MHz | Standard positioning |
| S-SPS | 2492.028 MHz | S-band standard |
| L5 RS | 1176.45 MHz | Restricted service |
| S-RS | 2492.028 MHz | S-band restricted |
| L1 SPS | 1575.42 MHz | L1 standard positioning |
SBAS Augmentation Services
Section titled “SBAS Augmentation Services”| Service | Coverage |
|---|---|
| WAAS | North America |
| SDCM | Russia |
| EGNOS | Europe |
| BDSBAS | China / Asia-Pacific |
| MSAS | Japan |
| GAGAN | India |
Cross-Binary Insights
Section titled “Cross-Binary Insights”Complete Firmware Update Pipeline
Section titled “Complete Firmware Update Pipeline”sequenceDiagram
participant Host as Host (Linux/Windows)
participant SoC as BCM4775 GNSS SoC
rect rgba(59, 130, 246, 0.1)
Note over Host,SoC: ROM Bootloader Phase
Host->>SoC: Auto-baud detection
SoC-->>Host: Sync response
end
rect rgba(34, 197, 94, 0.1)
Note over Host,SoC: Patch Download Phase
Host->>SoC: Download bootloader.pkg (to RAM)
SoC-->>Host: Patch verified
Host->>SoC: Start bootloader (jump to RAM)
SoC-->>Host: RPC available
end
rect rgba(234, 179, 8, 0.1)
Note over Host,SoC: Flash Operations (RPC)
Host->>SoC: Query flash config
SoC-->>Host: Flash size, erase time
Host->>SoC: Read flash (backup)
SoC-->>Host: Flash data
Host->>SoC: Erase sectors
Host->>SoC: Write flash (new image)
Host->>SoC: CRC verify
SoC-->>Host: Match
end
QXWZ vs Standard NTRIP
Section titled “QXWZ vs Standard NTRIP”| Feature | Standard NTRIP | QXWZ Service |
|---|---|---|
| Transport | HTTP/1.0 TCP | MQTT v3.1 |
| Auth | Basic HTTP auth | HMAC-SHA384 + DSK |
| Corrections | RTCM3 stream | RTCM3 + proprietary SIDS |
| Position upload | GGA via HTTP body | GGA via MQTT PUBLISH |
| API | Source table only | Full REST API |
| Encryption | None | AES-128-CBC for credentials |
| Coordinate frames | WGS-84 only | WGS-84 + CGCS2000 |
Potential Linux Firmware Update Tool
Section titled “Potential Linux Firmware Update Tool”The FlashUpdater protocol is now documented in sufficient detail to implement a Linux-native firmware update tool, eliminating the Windows dependency for firmware updates on the Waveshare LC29H HAT. The key components are:
- Transport: UART auto-baud → ROM SYNC handshake → version request/validate against BCM477x chip ID table
- Patch download: Stream
bootloader.pkgto RAM, verify, start Scratch APP (0x41) - RAM SYNC: Second handshake after bootloader starts
- RPC flash operations: Query (35), Read (6), Erase (10), Write (9), CRC verify (36), Status (39)
- Verification: Read-back + CRC comparison
The transport layer uses sequence numbers, ACKs, and automatic retry (tracked via RxPacketLost, TxPacketRetry, MaxRetry counters).
See Also
Section titled “See Also”- QNMEA.dll Decompilation — Round 1: QNMEA parser architecture and command catalogs
- GNSS Protocol Spec — Official command documentation
- Variant Matrix — Feature comparison across LC29H variants