Table of Contents

Jump Star GNSS X11 Firmware Analysis

Main X11 page

This page is what I have worked out from the MCU firmware so far. Almost all of it comes from reading the GD32F303 flash dump in a disassembler. A smaller part comes from live tests over Bluetooth and from a few helper scripts. Where it matters I say which kind of evidence a claim rests on:

Treat the addresses as a map, not as gospel. Some were read by eye and some are still being checked.

Status as of 2026-11-06: the firmware is read and mostly mapped. The Winbond flash has not been read yet. The first read of the config block is scripted and waiting for the unit to be powered.

The dump

Item Value
Chip GigaDevice GD32F303VCT6
Flash dump 262,144 bytes (256 KB). sha256 bf782a78c5abf63e4fef54c54ed8d13134f9c9c041bff3a56114eb34c3530724. Two dumps, identical.
Readout protection Off. Option bytes at 0x1FFFF800 read ffff5aa5; the RDP byte is 0xA5.
Image size The last non-0xFF byte is at 0x31756. About 197 KB of the 256 KB is used.
External flash Winbond W25Q128 (16 MB). The firmware reads it through its own routine. See Winbond flash below.

I dumped the flash over SWD with an RP2040 debug probe. The read was done with the core halted, and nothing was written.

Boot and application layout

Internal flash holds two images:

The bootloader looks at Winbond address 0x030000 for the ASCII string PRGAMOK. If it finds it, the bootloader erases the application area, reads a new image from Winbond address 0x032000, XORs each 32-bit word with 0x4E4E4E4E, programs the result into flash, and then clears the flag. This is almost certainly how a firmware update is installed. In the code (flow read); not exercised. On my unit the staging area at 0x032000 is all 0xFF, so no update image is staged.

Startup of the application runs through 0x080304D4, then SystemInit (0x08001200, inferred), then the C runtime at 0x08030C34. That enables the FPU and calls main at 0x0801CD7C.

Main loop

main is not a set of one-time init calls followed by sleep. It is a cooperative loop. Each pass writes a step number to RAM 0x20007E41, runs one task, and clears the soft-watchdog counter (more on that under Power and resets). The tasks that matter so far:

Step Function What I think it does
8 0x08018590 Parser B. Reads text commands that arrive on the RS232 port (SP…, CK…, #JMS).
9 0x08027C26 Bluetooth/Wi-Fi module open and close, driven by the enable flags.
20 0x0800405C Reads the UM980 receive buffer and drives the GGA logger to the TF card.
12, 15, 21, 22 0x08015A36, 0x08014D8C, 0x0800C024, 0x0800C08A Run only under certain flag values. Not identified yet.

Full table of the other steps is in my working notes, not here.

Serial ports

The MCU has five USART/UART peripherals. The init order gives them channel numbers 0 to 4 (channel 0 = USART0 … channel 4 = UART4). The UM980 and Bluetooth roles below are read from the code and the send-call sites, and the Bluetooth-to-UM980 path has been confirmed live.

Peripheral Role Evidence
USART0 (IRQ 37) MCU RS232 port, 9600 baud, on the 10 pin connector. Text commands, #JMS commands, and the binary factory-test frames all come in here. The boot log comes out here. In the code (ISR 0x08025DAF). Boot log observed.
UART3 (IRQ 52) UM980 link (channel 3). Receive ring 2500 bytes. In the code: all UM980 commands go out on channel 3. Forwarding from Bluetooth to channel 3 observed live.
UART4 (IRQ 53) FSC-BW246 Bluetooth/Wi-Fi module (channel 4). Receive ring 1500 bytes. In the code. Module traffic observed over SPP.
USART1, USART2 Not identified. Possibly the modem or radio. Not yet.

Receive handling on UART4 has limits that shape everything above it:

Bluetooth to UM980 forwarding

The frame handler at 0x08026BD0 decides what happens to each Bluetooth frame. Three RAM flags control it:

So the vendor's own “phone internet” corrections path appears not to work on this hardware. The route that works is +++ followed by raw data. Observed for RTCM at modest rates; see the limits above.

Bluetooth module

At boot the MCU runs a short AT sequence on UART4: AT+VER, AT+ADDR, AT+STAT, AT+NAME, AT+ROLE=1, AT+TPMODE=1. The reply to AT+VER decides the receive mode. BT986 gives mode 1, BW236 gives mode 2, BW246 gives mode 3. This unit reports FSC-BW246,V5.1.3, so it runs in mode 3. In the code and observed in the boot log.

The firmware contains no AT command that configures Wi-Fi. There is no SSID, password, or AP/STA setting anywhere in the image. The only Wi-Fi string is AT+WFSEND=0,. In the code.

Corrections: what the limits did to the test

These are numbers from my own tests, not from the code. Observed.

Those numbers are why the Bluetooth route is not yet a reliable correction path. The UM980 solution also stayed at quality 1 with Bluetooth corrections, while the same corrections over RS232 produced RTK float. That points at the UM980 side rather than the MCU link. See lead A under Open questions.

Config store

Everything that survives a power cycle lives in one 2048-byte block in the Winbond. There are two copies:

Every setter writes both copies. At boot the loader at 0x0800D14C to 0x0800D67C copies a fixed set of indexes into RAM variables. The accessors are:

Function Address What it does
read byte 0x0800CF78 Read one byte at an index
write byte 0x0800CDDC Write one byte, both copies
write 16 bit 0x0800CE50 Big-endian 16-bit write
write n bytes 0x0800CED4 Write a run of bytes
read n bytes 0x0800D08E Read a run of bytes

Some settings and where they live. Index numbers are byte offsets into the 2048-byte block:

Key Index RAM variable Note
GNSS.MODE 0x6CD 0x20007E23 0 = MOVE (rover), 1 = BASE
GNSS.ENABLE 0x48D 0x20007E29
GPRS.ENABLE 0x6FA 0x20007E25
BLE.ENABLE 0x786 0x20007D9B
WIFI.ENABLE 0x79B 0x20007D9C
WIFI.NAME 0x79C (string)
RADIO.ENABLE 0x7BB 0x20007E19
Backup server record 46
Main server record 55
NTRIP record 1300

The header is the one open discrepancy in this section. The reader scans for A5 5A. The probe read on the laptop at Winbond 0x000000 returned 00 00 AA 55 05 43 4D 49 4F 54, which is the APN record CMIOT. I do not yet know how these two fit together. The full read will settle it.

The $JMS,BASE status line

The unit sends a status line about once a second. In the code it is built at 0x080026EC. The fields I have decoded:

# Value What it is
1 V1.03-250220 Protocol version. Same as the BASE.PROTOCOL key.
2 13900063393 Serial number.
3 FY-X11-GGA-V0.30-251013 Software version.
4 X11-V5-20241228 Hardware version.
5 24 Board temperature in degrees C, one byte from RAM.
6 42 Battery percent: (adc - 325) * 10 / 9, clamped to 0 to 100, where adc is the battery sense reading on PC3. In the code.
7 0 1 when the external DC input is at or above 7.0 V. The sense is on PC4 through an 11:1 divider. This settles the field the wiki page left open. In the code.
8 0 Corrections link flag. Set to 1 when request id 50 returns 1, and cleared by the keep-alive monitor. Which peer it refers to is not identified yet. In the code, partly inferred.
9 to 13 OFF ON ON OFF OFF GPRS, GNSS, BLE, WIFI, and RADIO enable flags, in that order. In the code, matches the key dump.

“BASE” in the line is only the section name. The field does not say whether the unit is a base.

Base and rover

The mode is RAM flag A (0x20007E23): 0 = rover, 1 = base. Setting GNSS.MODE changes it and writes index 0x6CD. The MCU then sends its GNSS setup to the UM980 again. The UM980 keeps its own base/rover configuration, so the MCU's RAM flag is only what the firmware itself remembers about the mode. In the code, inferred for the UM980 side.

The #JMS command parser

The parser at 0x0801C6A0 handles the #JMS frames. The frame layout is:

#JMS,GET,GNSS.MODE*xx
#JMS,SET,GNSS.MODE,MOVE*xx

Each frame is under 201 bytes. The checksum is the XOR of the body, written as two uppercase hex digits. Replies start with @JMS,. A HEART command sets a link-alive byte (0x20007D9A), which is what $JMS,LINK prints. Group dispatch covers BASE, GPRS, GNSS, BLE, WIFI, and RADIO. Anything else returns CMD ERR. In the code.

The same parser reads X11-CONFIG.txt from the TF card (see below). The line syntax is identical.

Reply routing is not settled. For the TF card path my notes say replies go out on USART0. Over Bluetooth and RS232 I have seen replies come back on the link the command arrived on. See Open questions.

TF card slot

The datasheet says the slot is reserved. The firmware uses it, in SPI mode, with FatFs.

Because the card path uses the same parser and the same setters, a correctly checksummed #JMS,SET line in X11-CONFIG.txt would persist exactly like one sent over Bluetooth. Inferred. Not run.

Text commands

The firmware has a family of text commands. They are reachable from the RS232 port, and the code placement suggests from Bluetooth too. Reachable over Bluetooth is in the code; not tested live.

Prefix Password (plain text in image) Role State of decoding
<SPTF…> TFGPS Set JT808 platform parameters, fields as A C I K N P S T X p t x y Fields not decoded
<CKTF> - Report the SPTF values -
<SPGD…> GDGPS Set. Fields E N P X Y Z Purpose not decoded
<SPYC…> YCGPS Set NTRIP client settings. *r:0 selects NTRIP, *r:1 selects QXSDK Partly decoded
<CKYC> - Report the SPYC values -
<CKINFO>, <INFO> - Information report Not decoded
<INS: - Not decoded -
<CK-SIXENTS>, <SIXENTS - Third-party service report and setting Not decoded
<RETTF> - Reboot (“Reset OK!”) Reachable by code placement; not run
<RECTF> - Factory reset Destructive. See below
<EXT - Firmware update entry Do not send
<GNSS_UPDATE, <RADIO_UPDATE - Module firmware pass-through Do not send

The binary frames on RS232 (a $ start byte, a 0xFF end byte, and an XOR checksum) are a factory production-test protocol. Commands 0xED, 0xEE, and 0xEF exist, and 0xED and 0xEF run the factory reset. Do not send them. In the code.

Factory reset

<RECTF> calls 0x0800D67E. The routine:

1. Writes ''AA 55'' to bytes 0 and 1 of the config block.
2. Zeroes config indexes 65 to 2039.
3. Writes the defaults. The APN becomes ''CMNET''. The JT808 identity becomes placeholders (HT-600, 13800180001, plate "Yue A88888"). GNSS.MODE becomes MOVE. The enable flags, including GNSS.ENABLE and BLE.ENABLE, become 0.
4. Writes the block to both copies.
5. Erases Winbond 4 KB sectors at 0x002000, 0x00A000 to 0x011FFF, 0x016000 to 0x01FFFF, and 0x340000 to 0x344FFF (the 0x343000 sector is not in the list).

It does not touch the boot flag at 0x030000 or the staging area at 0x032000, so a reset cannot break the boot path.

Two consequences I have not tested. First, with GNSS.ENABLE and BLE.ENABLE both 0 after a reset, the unit may come up with no Bluetooth and no GNSS output, and would need an RS232 connection to recover. Inferred. Second, the APN CMIOT on this unit is written by a different reset path, one that the binary factory-test commands reach. So the unit was probably provisioned on a bench through that path. Inferred.

Do not send <RECTF> without reading the config block first and keeping a copy.

Power and resets

Three things can restart or power off the MCU. I can name the mechanism for each, but I have not caught all of them in the act.

At boot the firmware prints its reset cause (POR/PDR, software, low-power, PIN, independent watchdog, window watchdog). It clears the RCC reset flags itself, so the cause cannot be read back over SWD after boot. Capture the RS232 port during a test to see the message. In the code.

Winbond flash

The external flash is a W25Q128 on SPI1 (PA5, PA6, PA7), with chip select PA4 driven by software. The firmware's read routine at 0x0801E442 uses only opcodes 0x03 (read) and 0x05 (status). The write and erase routines exist in the image (opcodes 0x06, 0x02, and 0x20), and factory reset uses the 0x20 sector erase. In the code.

Known regions, from the code:

Address Contents
0x000000 Config block, primary copy (2 KB)
0x002000 Data store, erased by factory reset. Contents unknown.
0x030000 Boot flag, PRGAMOK when an update is pending
0x032000 Staged update image, XOR 0x4E4E4E4E
0x00A000 to 0x011FFF Data store, erased by factory reset. Contents unknown.
0x016000 to 0x01FFFF Data store, erased by factory reset. Contents unknown.
0x390000 Config block, backup copy (2 KB)
0x395000 Small record starting AA 55
0x340000 to 0x344FFF Data store, erased by factory reset. Contents unknown.

Observed on my unit: 0x032000 is all 0xFF, so there is no staged update.

The full image has not been read. A capture is scripted (swd_capture.py) to read the two config copies and a few probe ranges in one halted session, because the unit's low-power shutdown gives a window of about nine seconds. The full 16 MB read is not authorised yet.

Open questions

These are the things I could not settle from the code, and the things I think are most useful to check next:

Tools

The analysis tools live with the firmware dump in the project directory:

The JMS and RTCM test tools (spp2tcp.py, rtcm_relay.py, rtcm_replay.py) are described on the Software page.