Skip to content

GPS: u-blox ZED-F9P and ZED-X20P as their own receiver models - #12083

Draft
Raffi1202 wants to merge 8 commits into
iNavFlight:maintenance-10.xfrom
Raffi1202:feature/ublox-f9p-x20p
Draft

Raffi1202 wants to merge 8 commits into
iNavFlight:maintenance-10.xfrom
Raffi1202:feature/ublox-f9p-x20p

Conversation

@Raffi1202

@Raffi1202 Raffi1202 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Builds on #12021 (X20 detection via PROTVER). Until that is merged this branch carries its commits; the change here is the last commit, 2c92c0f.

Background

  • The ZED-F9P reports the M9's hardware ID 00190000 and is configured like an M9. configureGNSS() enables Galileo with E1 only and GLONASS with L1 only (sigCfgMask = 0x01). The F9P accepts GPS, Galileo, GLONASS and QZSS only with both bands on or both off and answers anything else with ACK-NAK (ZED-F9P Integration Manual §3.1.4.3, Table 3). INAV then resets gps_ublox_use_galileo/beidou/glonass to their defaults while the receiver keeps its factory setup. u-blox F9 series GNSS support #10236 shows it: Galileo and GLONASS switched themselves off, BeiDou stayed on.
  • The ZED-X20P's default signal plan has no BeiDou B1I (ZED-X20P Integration Manual, Table 6), which configureGNSS10() enables whenever GLONASS is off.
  • The X20 answers UBX-MON-GNSS only in version 1, which INAV does not parse. It was still polled three times at startup and every 5 s after.

Changes

  • ubloxRefineHardwareVersion(): hardware 00190000 with a MON-VER extension MOD=...F9... becomes UBX_HW_VERSION_UBLOX_F9 = 0x89 (series 0b10, as reserved in the header). Without MOD= the swVersion decides: the F9 reports EXT CORE 1., the M9 EXT CORE 4.. MSP_GPSSTATISTICS reports 0x89, CLI status shows UBLOXF9.
  • The capability checks compare the generation bits, so the F9 keeps every M9 decision except the constellation setup.
  • F9 and X20 get one CFG-VALSET with only the constellation switches SBAS_ENA, GAL_ENA, BDS_ENA, QZSS_ENA, GLO_ENA. The per-signal keys stay at the receiver defaults, so the band rules cannot be broken. A constellation the receiver does not list in MON-VER/MON-GNSS is not sent (X20 HPG 2.00/2.02 have no GLONASS). ArduPilot's CFGv2 sends only these keys as well. M8, M9, M10 and unknown receivers keep their paths.
  • A MON-GNSS reply in a version other than 0 ends the startup poll and stops the periodic one.
  • gps_ublox_nav_hz description: F9P and X20P rate limits (data sheets).

No new settings, no PG version change.

Behaviour change: with the default gps_ublox_use_glonass = OFF an F9P now runs GPS, Galileo and BeiDou instead of its factory four constellations.

Testing

  • gps_ublox_unittest, table-driven: hardware refinement (real F9P/M9/X20 MON-VER strings; M8, M10, X20 and unknown hardware with F9 strings stay unchanged), capability matrix including F9 and X20, enable-key lists per constellation and supported mask. gps_null_port_unittest, gps_heartbeat_unittest and the full check target (601 tests) pass.
  • Not tested on hardware yet. A ZED-F9P and a ZED-X20P (HPG 2.11) will be tested on an AT32F435 board; results will be posted here. Draft until then.

Flash / RAM

Against maintenance-10.x + #12021, built locally. The size bot compares against 7e82f68, the merge base with maintenance-11.x, so its table includes the maintenance-10.x changes since then; compared with its report on #12021 the difference is +264 B on MATEKF405 and +424 B on MATEKF722.

Target Flash RAM
MATEKF405 +208 B 0
MATEKF722 +424 B (FLASH1 97.69 %) -8 B
IFLIGHT_BLITZ_ATF435 +224 B 0

Open

Configurator presets for both receivers: iNavFlight/inav-configurator#2813.

gpsParseFrameUBLOX() only looked for PROTVER after the hardware string
was recognised. Receivers newer than M10 stayed at Proto 0.00 and were
configured over legacy CFG messages they do not answer, so auto-config
never completed. Parse the protocol version from every extension field,
read the two-digit major/minor as integers instead of through fastA2F(),
drop MON-VER payloads shorter than the header, and let a known protocol
version finish detection. Adds gps_ublox_protocol_unittest.
The ZED-X20P reports hwVersion 000B0000 in MON-VER. Without a table
entry it stays UBX_HW_VERSION_UNKNOWN and gpsConfigure() skips the
constellation setup, so gps_ublox_use_galileo/beidou/glonass never
reach the receiver.

Add UBX_HW_VERSION_UBLOX20 (0x54) in the u-blox series, so the existing
">= UBX_HW_VERSION_UBLOX10" checks cover it: GNSS setup over CFG-VALSET,
MON-GNSS poll at start-up and MON-RF polling.

The F9P is not added. It reports 00190000, the same ID as the M9, and is
already handled as UBLOX9.

The test uses a MON-VER captured from a ZED-X20P running HPG 2.10.
The X20 answers MON-GNSS with message version 1, which the parser
ignores, so the start-up capability poll waits its full 3 x 500 ms.
Nothing refreshes the GPS timeout in that loop and gps.c restarts the
driver after 1000 ms. Since aa0d822 made the X20 known hardware, it
entered that loop and never finished configuration.

Refresh the timeout on each poll; the receiver already answered MON-VER.
The test now answers MON-GNSS with a capture from a ZED-X20P and checks
the longest gap without a timeout refresh.
The F9P reports the M9 hardware ID, answers MON-GNSS version 0 and still
accepts legacy CFG messages. The test uses replies captured from a
ZED-F9P running HPG 1.51 and checks that it keeps the M9 path:
constellations over CFG-GNSS, the rest over CFG-VALSET, and no GPS
timeout during start-up.
…le-driven

The hardware and protocol version decoders become pure functions in
gps_ublox_utils.c, so gps_ublox_unittest.cc tests them directly with
tables of known IDs, valid formats, the old float truncation cases and
malformed fields. The protocol harness that drove the whole driver
through a fake serial port, its CMake target and the target.h change
are dropped. No behaviour change.
A receiver whose hardware ID is not in the table but that reports
PROTVER 15.00 or newer (the first M8 protocol with CFG-GNSS and
MON-GNSS) now gets the GNSS capability poll, the constellation
detection from the MON-VER extensions and the constellation setup.
Such a receiver uses the M10 signal keys from protocol 34.00 on: below
that, the documented firmware (M9, F9P, F9R) lacks BDS_B1C, and M9 and
F9P still accept CFG-GNSS. Known hardware keeps its current path.

The decisions become pure functions in gps_ublox_utils.c with table
tests. ubloxEffectiveNavHz() returns the rate configureRATE is asked
for, including the 20/40 Hz limit that configureRATE used to apply on
its own, so the satellite info divider in iNavFlight#12001 can use the same value.
gps.c counts its timeout from the last gpsSetProtocolTimeout() call, not
from received frames, so the MON-VER retries only got two of their three
polls when an answer was lost. The timeout is now refreshed on each
poll, as the MON-GNSS loop already does. If none of the three polls
brings a hardware or protocol version, the driver restarts as on a
communication loss instead of setting the receiver up on the legacy
path.

The capability bits were cleared after MON-VER had set GAL/BDS/GLO from
its extensions. M8 to M10 set them again from MON-GNSS, but the X20
answers MON-GNSS version 1, so gpsinfo showed no constellations for it.
They are now cleared before MON-VER; on M8 to M10 a lost MON-GNSS answer
now leaves the MON-VER bits in place instead of none.

Document 0x54 (X20, hwVersion 000B0000) in gps_ublox.h, and drop the
typeconversion.h include that is unused since fastA2F went.
The ZED-F9P reports the M9's hardware ID. It is now told apart by the
MOD= extension of MON-VER (fallback: the "EXT CORE 1." base version)
and reported as 0x89, series 0b10. The capability checks compare the
generation, so the F9 keeps every M9 decision except the constellation
setup.

F9 and X20 get their constellations through the CFG-SIGNAL enable keys
only and keep the receiver's signal defaults. The F9 rejects the
single-band masks INAV sent, which reset the constellation settings to
their defaults, and the X20's default signal plan has no BeiDou B1I.

A MON-GNSS reply in a version INAV does not parse (X20: version 1)
ends the startup poll and stops the periodic poll.
@github-actions

Copy link
Copy Markdown

RAM / Flash usage vs. base commit 7e82f68 — commit 2c92c0f

Target Flash Δ RAM Δ
MATEKF405 ⚠️ +19916 B (+2.83%) CCM: +4096 B (+14.39%)
RAM: -5088 B (-4.66%)
MATEKF722 ⚠️ +9124 B (+1.93%) ITCM_RAM: +104 B (+0.84%)
RAM: -1584 B (-1.79%)
TCM: ±0 B (±0.00%)
MATEKF765 ⚠️ +13232 B (+1.78%) DTCM_RAM: +136 B (+0.48%)
SRAM1: -1764 B (-1.39%)
MATEKH743 ⚠️ +20092 B (+2.58%) D2_RAM: +160 B (+5.15%)
DTCM_RAM: +116 B (+0.90%)
ITCM_RAM: +64 B (+0.39%)
RAM: -1124 B (-0.78%)

See RAM/flash optimization guide for techniques to reduce usage.

@github-actions

Copy link
Copy Markdown

Test firmware build ready — commit 2c92c0f

Download firmware for PR #12083

251 targets built. Find your board's .hex file by name on that page (e.g. MATEKF405SE.hex). Files are individually downloadable — no GitHub login required.

Development build for testing only. Use Full Chip Erase when flashing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant