Autonomní Stratum 1 NTP server na Raspberry Pi: chrony s DCF77 a GPS PPS v roce 2026
Na Raspberry Pi OS Bookworm/Trixie staré návody na NTP servery nefungují kvůli libgpiod v2, přechodu na chrony a změnám v GPIO čipech. Implementace v C++20 využívá DCF77 přijímač RC8000 na GPIO 17 a GPS modul ublox NEO-M8T s PPS na GPIO 18. Server zajišťuje přesnost <1 µs bez internetu, s nezávislou kontrolou časových zdrojů.
Problémy zastaralých implementací
libgpiod v2 rozbíjí GPIO kód
libgpiod v2 odstranila API v1 bez zpětné kompatibility. Starý kód s gpiod_chip_open_by_name a gpiod_chip_get_line se nezkompiluje:
// libgpiod v1 — NEKOMPILUJE se s v2
struct gpiod_chip *chip = gpiod_chip_open_by_name("gpiochip0");
struct gpiod_line *line = gpiod_chip_get_line(chip, 17);
gpiod_line_request_both_edges_events(line, "dcf77");
Nové API vyžaduje gpiod_line_settings_new() a gpiod_line_config_new():
// libgpiod v2 — správný přístup
const SettingsPtr settings(gpiod_line_settings_new());
gpiod_line_settings_set_edge_detection(settings.get(), GPIOD_LINE_EDGE_BOTH);
gpiod_line_settings_set_event_clock(settings.get(), GPIOD_LINE_CLOCK_REALTIME);
const LineCfgPtr line_cfg(gpiod_line_config_new());
gpiod_line_config_add_line_settings(line_cfg.get(), &offset, 1, settings.get());
const RequestPtr request(gpiod_chip_request_lines(chip.get(), req_cfg.get(), line_cfg.get()));
Klíčová výhoda — GPIOD_LINE_CLOCK_REALTIME: události získají časové značky od jádra v přerušení, jitter klesá z 40 ms na <5 ms.
Přechod z ntpd na chrony
ntpd byl nahrazen chrony v Bookworm. Srovnání:
| Parametr | ntpd | chrony |
|----------|------|--------|
| Konvergence | minuty | sekundy (makestep 0.5 3) |
| Ztráta signálu | degradace | holdover (local stratum 10) |
| PPS | patche | nativní refclock PPS |
| Přesnost PPS | ~100 µs | <1 µs |
Oba podporují NTP SHM pro výměnu dat přes sdílenou paměť.
GPIO čip na RPi 5
gpiochip0 je zastaralý. Na RPi 5/Trixie je potřeba gpiochip4 (ověřit gpiodetect).
Architektura systému
Dva zdroje času:
- GPS NEO-M8T: PPS (/dev/pps0) + NMEA přes gpsd (NTP SHM #0)
- DCF77 RC8000: GPIO 17 → dekodér → NTP SHM #2
- chrony: stratum 1 s prefer PPS
- Webový monitor: chronyc + journald na :8080
Konfigurace chrony:
refclock PPS /dev/pps0 refid PPS precision 1e-9 poll 0 dpoll -2 lock NMEA prefer
refclock SHM 0 refid NMEA precision 1e-3 poll 0 dpoll -2 offset 0.0 delay 0.2 noselect
refclock SHM 2 refid DCF7 precision 1e-2 offset 0.0 delay 0.008 poll 6 dpoll 5
local stratum 10
DCF77 slouží jako záložní zdroj a detektor GPS spoofingu (odchylka >několik sekund).
Dekodér DCF77
Timestamp od jádra
GPIOD_LINE_CLOCK_REALTIME poskytuje značku přerušení, nikoli userspace. StdDev v SHM: <5 ms.
NTP SHM pro 64-bit
Struktura s paddingem:
struct NtpShmTime {
int32_t mode;
int32_t count;
int64_t clockTimeStampSec;
int32_t clockTimeStampUSec;
int32_t _pad;
int64_t receiveTimeStampSec;
int32_t receiveTimeStampUSec;
int32_t leap;
int32_t precision;
int32_t nsamples;
int32_t valid;
};
volatile NtpShmTime *shm_ = nullptr;
Protokol DCF77
59 bitů/minutu v BCD s paritou:
- 100 ms HIGH → bit 0
- 200 ms HIGH → bit 1
- Pauza >1,5 s → značka minuty
Validace: 3 skupiny parity + timegm(). Bootstrap: 2 snímky s rozdílem 60 s.
Nastavení NEO-M8T
- Firmware TIM: RAIM, nízký PPS jitter
- dynModel=Stationary: jitter 5–10 ns
- antCableDelay=50 ns: kompenzace kabelu
- 4 konstelace: 20–30 satelitů
- lpMode=Continuous: bez úspory energie
Webový monitor a nasazení
dcf77_web: HTTP :8080, chronyc v JSON, UI v binárce. API: /api/status, /api/prefer (pouze localhost).
Sestavení vcpkg + CMake:
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
Ansible nasazení s systemd hardening.
Výsledky
chronyc tracking:
- Stratum: 1
- Systémový čas: +42 ns
- RMS offset: 51 ns
- Root dispersion: 15 ns
DCF77: ~3 ms.
Co je důležité
- libgpiod v2 vyžaduje nový objektový model s
GPIOD_LINE_CLOCK_REALTIME - chrony překonává ntpd v přesnosti PPS (<1 µs) a holdover
- NTP SHM na 64-bit potřebuje explicitní padding pod
int64_t - NEO-M8T TIM + Stationary: PPS jitter 5–10 ns
- DCF77 validuje GPS proti spoofingu
— Editorial Team
Zatím žádné komentáře.