mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
Cellular modems (Quectel EM05/EM06/EM12, Sierra EM7565, ...) expose
GPS data as NMEA on a dedicated USB serial interface. Until now we
relied on ModemManager's --location-enable-gps-nmea, which makes MM
hold the NMEA port and parse the stream itself — useful for mmcli
but a dead end for the rest of the system. The result was that
modem GPS was visible only via 'show modem' and could not act as an
NTP fallback time source on devices without dedicated GPS hardware.
This commit reroutes the NMEA stream into the existing
gpsd → chronyd pipeline so cellular modems behave just like any
other NMEA-over-USB GPS dongle. No changes to gpsd, chronyd, or
the ietf-hardware:gps component — the user activates it the same
way as for a dedicated receiver, by adding a 'gps' hardware
component that references /dev/gpsN.
This is Phase 2 of the modem GPS / location integration plan
(.notes/modem-gps-plan.md).
udev (src/modemd/77-mm-modem-gps.rules):
- For known vendor:product:interface tuples, set ID_MM_PORT_IGNORE
so ModemManager keeps off the NMEA port, and add
SYMLINK+="gps%n" so gpsd's existing udev hook picks up the
device automatically.
- Interface-number match uses ENV{ID_USB_INTERFACE_NUM} rather
than ATTRS{bInterfaceNumber}: udev requires all ATTRS{} matches
in a rule to share one parent, but idVendor/idProduct live on
the USB device while bInterfaceNumber lives on the USB
interface. ENV{} matching has no parent constraint and udev
already populates ID_USB_INTERFACE_NUM from bInterfaceNumber.
- Initial entries: Quectel EM05 (2c7c:0125), EM06-E (2c7c:0306),
EM12-G (2c7c:0512), Sierra Wireless EM7565 (1199:9091).
Easy to extend.
modemd (modemd/__init__.py):
- GPS_AT_COMMANDS table maps manufacturer -> (enable, disable) AT
command pair. prepare_location() issues the vendor AT command
via 'mmcli --command=AT+QGPS=1' (or AT+CGPS=1 for Sierra)
instead of --location-enable-gps-{nmea,raw}. Vendor lookup is
substring-based ('Quectel' matches both 'Quectel' and 'Quectel
Incorporated') because ModemManager normalises differently
across firmware revisions. For unrecognised vendors the
high-level MM path is still used as a fallback, so nothing
regresses for hardware not yet in the table.
- The AT path runs based on the udev/vendor table, not on MM's
--location-status capabilities. Setting ID_MM_PORT_IGNORE on
the NMEA port removes 'gps' from MM's capability list even
though the GPS hardware is still there, so a capability gate
would mistakenly skip GPS for the very modems we're targeting.
- _location_capabilities() filters MM-managed sources so a single
unsupported flag (e.g. CDMA on an LTE-only modem) doesn't fail
the whole batched call. Sources the modem doesn't support are
silently skipped; a warning is logged only if the user's YANG
config explicitly lists one.
- Subprocess fan-out collapsed: agps-msa, agps-msb, 3gpp and cdma
flags share a single batched mmcli invocation.
prepare_location() drops from 5 subprocess calls to 1 (unknown
vendor) or 2 (known vendor, AT + batched MM).
- Stringly-typed if/elif source dispatch replaced with a
dict-driven table (LOCATION_MM_FLAGS).
- Two helpers eliminate the ['mmcli', '-m', self.path, ...]
boilerplate at ~30 ModemThread call sites:
self._mmcli(*args, check=True) # runcmd wrapper
self._mmclij(*args) # runcmdj wrapper
build (package/feature-modem/Config.in):
- Select BR2_PACKAGE_MODEM_MANAGER_ATVIADBUS so ModemManager
accepts raw AT commands over D-Bus without being started in
--debug mode. Required by the AT path above; without it
'mmcli --command' is rejected with MM_CORE_ERROR_UNAUTHORIZED.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>