Chrony with GPS fallback; robust antenna supply; all GNSS constellations
Time: chrony replaces timesyncd, with NICT/JP-pool NTP primary and gpsd SHM as an offline-only refclock; makestep any time and fake-hwclock cover the battery-less RTC. Antenna: the modem cleared the supply again after the service set it, so the service is now idempotent, configurable (ANTENNA=active|passive, passive keeps it off) and re-checked by a 30 s timer. gpsd: a gpsdctl udev hook spawned a stray gpsd without -n at boot that blocked the real service; gpsd.service now binds to the NMEA device. GNSS: CGNSSMODE=15 (GLONASS, BeiDou, Galileo, QZSS) and all supported NMEA sentences; both persist across a modem reset. Adds sim7600-at. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -135,8 +135,8 @@ brief NM connectivity-check penalty (`+20000`) after WiFi returns.
|
|||||||
- ModemManager location is **not** used. gpsd owns the NMEA port; ModemManager only labels it `(gps)` and leaves it unopened.
|
- ModemManager location is **not** used. gpsd owns the NMEA port; ModemManager only labels it `(gps)` and leaves it unopened.
|
||||||
- Stable device names, `/etc/udev/rules.d/99-sim7600-gps.rules`:
|
- Stable device names, `/etc/udev/rules.d/99-sim7600-gps.rules`:
|
||||||
```
|
```
|
||||||
# if01: NMEA. Re-attach gpsd on every appearance (USBAUTO is off, so gpsd would otherwise lose it after a modem reset).
|
# if01: NMEA. gpsd.service follows this device (drop-in BindsTo), so it restarts with a fresh handle after a modem reset.
|
||||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{ID_USB_INTERFACE_NUM}=="01", SYMLINK+="sim7600-gps", RUN+="/usr/sbin/gpsdctl add /dev/sim7600-gps"
|
SUBSYSTEM=="tty", ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{ID_USB_INTERFACE_NUM}=="01", SYMLINK+="sim7600-gps", TAG+="systemd", ENV{SYSTEMD_WANTS}+="gpsd.service"
|
||||||
# if03: spare AT port, reserved for us (ModemManager keeps if02). Powers the active GNSS antenna on every modem start.
|
# if03: spare AT port, reserved for us (ModemManager keeps if02). Powers the active GNSS antenna on every modem start.
|
||||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{ID_USB_INTERFACE_NUM}=="03", SYMLINK+="sim7600-at", ENV{ID_MM_PORT_IGNORE}="1", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sim7600-gnss-antenna.service"
|
SUBSYSTEM=="tty", ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{ID_USB_INTERFACE_NUM}=="03", SYMLINK+="sim7600-at", ENV{ID_MM_PORT_IGNORE}="1", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sim7600-gnss-antenna.service"
|
||||||
```
|
```
|
||||||
@@ -147,6 +147,10 @@ brief NM connectivity-check penalty (`+20000`) after WiFi returns.
|
|||||||
USBAUTO="false" # hotplug would let gpsd probe the modem's AT ports and conflict with ModemManager
|
USBAUTO="false" # hotplug would let gpsd probe the modem's AT ports and conflict with ModemManager
|
||||||
```
|
```
|
||||||
- `systemctl enable --now gpsd.socket gpsd`
|
- `systemctl enable --now gpsd.socket gpsd`
|
||||||
|
- `/etc/systemd/system/gpsd.service.d/10-sim7600.conf`: `BindsTo=` / `After=dev-sim7600\x2dgps.device`. gpsd stops when the NMEA port
|
||||||
|
vanishes (modem reset, unplug) and the udev rule starts it again when the port returns. An earlier `RUN+="gpsdctl add …"` hook was
|
||||||
|
dropped: at boot it fired before `gpsd.service`, so `gpsdctl` spawned its own gpsd **without `-n`**, which then held port 2947 and kept
|
||||||
|
the real service from ever starting.
|
||||||
|
|
||||||
Check: `cgps` or `gpspipe -w -n 10`. On 2026-10-07, tested indoors, gpsd saw `nSat: 10, uSat: 0`, `mode: 1` (no fix).
|
Check: `cgps` or `gpspipe -w -n 10`. On 2026-10-07, tested indoors, gpsd saw `nSat: 10, uSat: 0`, `mode: 1` (no fix).
|
||||||
Next: test with the GNSS antenna (IPEX, labeled GNSS on the HAT) with a clear view of the sky. A cold start can take a few minutes.
|
Next: test with the GNSS antenna (IPEX, labeled GNSS on the HAT) with a clear view of the sky. A cold start can take a few minutes.
|
||||||
@@ -169,19 +173,42 @@ AT+CVAUXS=1 # switch the supply on → fix back within 1 s
|
|||||||
| Satellites used | 6.3 avg (max 7) | 6.5 avg (max 7) |
|
| Satellites used | 6.3 avg (max 7) | 6.5 avg (max 7) |
|
||||||
| Signal of used satellites | 31.3 dB-Hz | **36.8 dB-Hz** (peaks 43–47) |
|
| Signal of used satellites | 31.3 dB-Hz | **36.8 dB-Hz** (peaks 43–47) |
|
||||||
|
|
||||||
Satellites used barely change; that count looks limited by which constellations are enabled (GPS and GLONASS in use; BeiDou visible in
|
Satellites used barely change; that count looks limited by which constellations are enabled (see below). The gain is ~5.5 dB of margin,
|
||||||
NMEA; QZSS/Galileo not checked yet). The gain is ~5.5 dB of margin, which is what matters under trees and between buildings.
|
which is what matters under trees and between buildings.
|
||||||
|
|
||||||
**Both settings are volatile.** They reset to off/1.7 V on every modem restart (`AT+CRESET` tested), and `AT&W` does not save them. So:
|
**Both settings are volatile.** They reset to off/1.7 V on every modem restart (`AT+CRESET` tested), and `AT&W` does not save them. So:
|
||||||
|
|
||||||
- `/usr/local/sbin/sim7600-gnss-antenna` sends them over `/dev/sim7600-at` (retrying while the modem boots) and verifies them;
|
- `/etc/default/sim7600-gnss-antenna`: `ANTENNA=active|passive`, `CVAUXV_MV=3050`.
|
||||||
- `sim7600-gnss-antenna.service` (oneshot, `BindsTo=dev-sim7600\x2dat.device`) runs it, started by the udev rule above whenever
|
- `/usr/local/sbin/sim7600-gnss-antenna` reads the modem's state over `/dev/sim7600-at` and writes only if it differs from the config
|
||||||
interface 03 appears: boot, hot-plug, modem reset.
|
(`passive` keeps the supply **off**). It logs only actual changes.
|
||||||
|
- `sim7600-gnss-antenna.service` (oneshot, `LogLevelMax=notice`) runs it when interface 03 appears (udev), **and**
|
||||||
|
`sim7600-gnss-antenna.timer` re-runs it every 30 s.
|
||||||
|
|
||||||
Verified with `mmcli -m any --reset` while everything was running: the antenna supply was re-applied as soon as the ports returned,
|
The timer is needed: one modem reset showed the modem clearing the supply again **after** the service had set and verified it
|
||||||
LTE reconnected ~50 s after the reset, and gpsd re-attached via `gpsdctl` with a 3D fix.
|
(most likely ModemManager bringing the radio up). With the timer, any reset is corrected within ~30 s (tested: supply switched off by
|
||||||
|
hand at 19:13:59, restored 19:14:34). Full recovery after `mmcli -m any --reset` (tested twice): LTE back in ~30–50 s, antenna supply
|
||||||
|
back on, gpsd restarted with the port.
|
||||||
|
|
||||||
With a **passive** antenna the supply does no harm, but it can be turned off by disabling the service.
|
⚠ **Passive antenna: set `ANTENNA=passive` before connecting it**, then `sudo systemctl start sim7600-gnss-antenna`. Many passive GNSS
|
||||||
|
antennas are a DC short to ground (inductive or shorted-patch feeds), and `CVAUX` is a general-purpose modem output, not a dedicated
|
||||||
|
antenna supply with documented short-circuit protection. With nothing connected the supply is harmless.
|
||||||
|
|
||||||
|
#### Constellations (2026-10-09)
|
||||||
|
|
||||||
|
`AT+CGNSSMODE=<0-15>,<dpo>` sets the satellite systems on top of GPS. The default `3` is GPS+GLONASS+BeiDou (per SIMCom's GNSS
|
||||||
|
application note), which fits bit 0 = GLONASS, bit 1 = BeiDou. The note lists Galileo and QZSS next, so bits 2–3 are most likely those,
|
||||||
|
but it doesn't define the bits explicitly.
|
||||||
|
|
||||||
|
```
|
||||||
|
AT+CGPS=0
|
||||||
|
AT+CGNSSMODE=15,1 # all four: GLONASS, BeiDou, Galileo, QZSS (Japan's regional system, "Michibiki")
|
||||||
|
AT+CGPSNMEA=262143 # all NMEA sentence types; the modem keeps only those it supports: reads back 198143
|
||||||
|
AT+CGPS=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Both settings **persist across a modem reset** (checked), unlike the antenna supply. **Not yet verified on sky:** whether Galileo/QZSS
|
||||||
|
satellites actually appear (look for Galileo/QZSS PRNs in `gpspipe -w` SKY, or `GA`/`GQ` NMEA talkers). Indoors with no antenna nothing is
|
||||||
|
tracked. No AT command for SBAS/MSAS (Japan's augmentation service) appears in the application note.
|
||||||
|
|
||||||
## Rebuilding qmi_wwan after a kernel update
|
## Rebuilding qmi_wwan after a kernel update
|
||||||
|
|
||||||
@@ -198,7 +225,7 @@ sudo modprobe qmi_wwan && sudo systemctl restart ModemManager
|
|||||||
|
|
||||||
## Useful one-offs
|
## Useful one-offs
|
||||||
|
|
||||||
- Talk to the modem directly: use **`/dev/sim7600-at`**. ModemManager ignores it, so there's no need to stop anything
|
- Talk to the modem directly: use **`/dev/sim7600-at`**. ModemManager ignores it, so there's no need to stop anything.
|
||||||
(e.g. `picocom -b 115200 /dev/sim7600-at`, or `minicom -D /dev/sim7600-at`). Don't send commands that change the data
|
One-shot: `sudo sim7600-at 'AT+CGPS?' 'AT+CVAUXS?'` (`/usr/local/sbin/sim7600-at`; filters NMEA noise). Interactive:
|
||||||
connection behind ModemManager's back.
|
`picocom -b 115200 /dev/sim7600-at`. Don't send commands that change the data connection behind ModemManager's back.
|
||||||
- Verbose ModemManager log incl. AT traffic: `sudo mmcli -G debug` then `journalctl -u ModemManager -f` (resets on restart).
|
- Verbose ModemManager log incl. AT traffic: `sudo mmcli -G debug` then `journalctl -u ModemManager -f` (resets on restart).
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ date: 2026-10-08
|
|||||||
|
|
||||||
| Item | State |
|
| Item | State |
|
||||||
|------|-------|
|
|------|-------|
|
||||||
| Network time | `systemd-timesyncd`, primary `ntp.nict.jp` (stratum 1), synced over whichever uplink holds the default route (Ethernet / WiFi / LTE) |
|
| Network time | **chrony** (since 2026-10-09; was `systemd-timesyncd`), primary `ntp.nict.jp` (stratum 1) + JP pool + Ubuntu pools, over whichever uplink holds the default route |
|
||||||
| Timezone | `Asia/Tokyo` (was `Asia/Yakutsk`: same +09:00 and no DST either, but the wrong place) |
|
| Timezone | `Asia/Tokyo` (was `Asia/Yakutsk`: same +09:00 and no DST either, but the wrong place) |
|
||||||
| Clock across power-off | **Not kept.** The RTC has no backup battery (see below) |
|
| Clock across power-off | **Not kept.** The RTC has no backup battery (see below) |
|
||||||
| GPS time | Not yet. Waiting on a GNSS fix (see [SIM7600 report](SIM7600-SETUP.md)) |
|
| GPS time | chrony refclock `GPS` (gpsd SHM 0), fallback only; used when offline with a fix |
|
||||||
|
| Boot clock without network | `fake-hwclock` restores the last saved time (replaces timesyncd's saved timestamp) |
|
||||||
|
|
||||||
## RTC loses time when powered off
|
## RTC loses time when powered off
|
||||||
|
|
||||||
@@ -41,11 +42,33 @@ FallbackNTP=ntp.ubuntu.com 0.jp.pool.ntp.org 1.jp.pool.ntp.org 2.jp.pool.ntp.org
|
|||||||
|
|
||||||
`sudo systemctl restart systemd-timesyncd`, then check with `timedatectl timesync-status` (server, stratum, offset).
|
`sudo systemctl restart systemd-timesyncd`, then check with `timedatectl timesync-status` (server, stratum, offset).
|
||||||
|
|
||||||
## Later: GPS as a time source
|
## Chrony with GPS fallback (2026-10-09)
|
||||||
|
|
||||||
timesyncd only speaks NTP. Once GNSS has a fix, replace it with `chrony`, configured with:
|
Replaced `systemd-timesyncd` (removed by the `chrony` package) so GPS can serve as an offline time source.
|
||||||
|
|
||||||
- the same NTP servers as above, which remain the default whenever any uplink exists, and
|
```
|
||||||
- a gpsd refclock (`refclock SHM 0`), which takes over when offline.
|
sudo apt install chrony fake-hwclock
|
||||||
|
```
|
||||||
|
|
||||||
NMEA over the USB serial port carries no PPS signal, so GPS time alone is only good to tens of milliseconds. That is plenty for log timestamps.
|
`/etc/chrony/conf.d/10-yukart.conf`:
|
||||||
|
|
||||||
|
```
|
||||||
|
server ntp.nict.jp iburst prefer
|
||||||
|
pool 2.jp.pool.ntp.org iburst maxsources 2
|
||||||
|
refclock SHM 0 refid GPS precision 1e-1 offset 0.0 delay 0.5 poll 3
|
||||||
|
```
|
||||||
|
|
||||||
|
- **NTP stays primary.** The GPS refclock's generous `precision`/`delay` give it a large root distance, so any reachable NTP server wins.
|
||||||
|
It steers the clock only offline with a fix. NMEA over USB has no PPS, so GPS time is good to ~tens of ms, plenty for log timestamps.
|
||||||
|
- **`offset 0.0` is a placeholder.** Tune it once NTP and a GNSS fix are both available: `chronyc sourcestats` shows the GPS offset
|
||||||
|
against NTP.
|
||||||
|
- **`makestep 1 -1`** in `/etc/chrony/chrony.conf` (was `1 3`): step the clock whenever it's > 1 s off, not only in the first three
|
||||||
|
updates, because with no RTC battery a stale clock may only meet its first source (a late GPS fix) well into an offline drive.
|
||||||
|
chrony's config format has no inline comments; the explanation sits on its own line above.
|
||||||
|
- **`fake-hwclock`** saves the time hourly and at shutdown and restores it at boot, so an offline boot starts near the last shutdown
|
||||||
|
instead of the RTC's reset date. This replaces what timesyncd's `/var/lib/systemd/timesync/clock` did.
|
||||||
|
- gpsd must run with **`-n`** to feed SHM without a client. See the SIM7600 report: a stray gpsd started by a `gpsdctl` udev hook ran
|
||||||
|
without it, now fixed.
|
||||||
|
|
||||||
|
Check: `chronyc -n sources` (`^*` = selected NTP server, `#` = GPS refclock), `chronyc tracking`.
|
||||||
|
At setup: synced to `ntp-a3.nict.go.jp` (stratum 1); `GPS` listed with no samples (antenna detached indoors).
|
||||||
|
|||||||
Reference in New Issue
Block a user