Documentation
¶
Overview ¶
Package dcf77 decodes DCF77 time-signal frames — the long-wave (77.5 kHz) radio broadcast from Mainflingen, Germany, that carries the current Central European time + date. Pure offline parser; no transport, no hardware.
Wrap-vs-native judgement: the DCF77 frame format is a fully public spec (PTB / "Time signal and frequency standard DCF77", ETSI EN 300 220-1). The walker is bit-level decoding over a 60-bit frame with BCD-weighted time/date fields and three parity bits. Wrapping a FAP for this would require an SD-card install + a firmware-fork dependency for a pure parser. Native delivers offline analysis — operators paste a 60-bit DCF77 bit-stream captured by their SDR (rtl_sdr → gnuradio DCF77 block) or consumer radio-clock test pin and decode the time without running a fresh capture.
What this package covers:
- 60-bit frame walker: header (start-of-minute marker, weather, antenna-switch announcement, DST-change announcement, CET/CEST indicator, leap-second announcement), time field (start marker + 7-bit BCD minutes + parity + 6-bit BCD hours + parity), date field (6-bit BCD day-of-month + 3-bit BCD day-of-week + 5-bit BCD month + 8-bit BCD year + parity)
- BCD weighting per the official table (1+2+4+8+10+20+40+80)
- Even-parity validity checks for minutes / hours / date
- DST flag interpretation (CET vs CEST = UTC+1 vs UTC+2)
- Day-of-week mapping (1=Monday through 7=Sunday)
What this package does NOT cover (deliberately out of scope):
- The first 14 bits (weather data) — encrypted by PTB, surfaced as raw hex for cross-reference
- Demodulation / sync detection (operators bring the pre-aligned 60-bit frame)
- Year-rollover detection (the 2-digit year wraps every century — we surface the raw decode and let the caller decide what century to apply)
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Synth ¶ added in v0.375.0
func Synth(in SynthInput) (string, error)
Synth builds the 60-bit DCF77 minute telegram for the given time, with correct BCD fields and the three even-parity bits, exactly as Decode expects it (round-trip inverse of Decode). It is the offline telegram generator behind a DCF77 clock-spoof payload — it does NOT transmit; operators feed the returned bit-string to a Sub-GHz/long-wave TX stage.
Wrap-vs-native judgement ¶
Native, and the inverse of the existing Decode. The DCF77 frame format is fully public (PTB DCF77 spec / ETSI EN 300 220-1) and the encoding is pure bit-level BCD + even parity over a fixed 60-bit frame — no crypto, no state, no hardware. Correctness is verifiable three ways: round-trip against Decode, hand-computed BCD/parity, and the published spec.
Bit 0 is the start-of-minute marker (0); bit 20 is the start-of-time marker (1); bit 59 is the (untransmitted) minute mark, left 0. Weather bits (1–14) and the announcement bits are left 0 — the telegram carries a clean time/date with no warnings.
Types ¶
type Frame ¶
type Frame struct {
// StartOfMinute is bit 0 — must be 0 per spec. Surfaced so
// callers can flag malformed inputs.
StartOfMinute bool `json:"start_of_minute_marker"`
// WeatherDataHex is bits 1..14 — encrypted by PTB, surfaced
// as 14-bit binary string for cross-reference.
WeatherDataBits string `json:"weather_data_bits"`
// AntennaSwitchAnnouncement (bit 15) — set when DCF77 is
// about to switch from main to backup antenna in the next
// hour.
AntennaSwitchAnnouncement bool `json:"antenna_switch_announcement"`
// DSTChangeAnnouncement (bit 16) — set when CET/CEST
// transition will occur in the next hour.
DSTChangeAnnouncement bool `json:"dst_change_announcement"`
// CESTActive (bits 17..18) — true when CEST (UTC+2) is in
// effect, false when CET (UTC+1).
CESTActive bool `json:"cest_active"`
// TimezoneOffsetHours is +1 for CET, +2 for CEST.
TimezoneOffsetHours int `json:"timezone_offset_hours"`
// LeapSecondAnnouncement (bit 19) — set when a leap second
// will be inserted at end of the next hour.
LeapSecondAnnouncement bool `json:"leap_second_announcement"`
// StartOfTime (bit 20) — must be 1 per spec.
StartOfTime bool `json:"start_of_time_marker"`
// Minute (bits 21..27): 0-59.
Minute int `json:"minute"`
// MinuteParityValid — even parity over bits 21..27 (bit 28).
MinuteParityValid bool `json:"minute_parity_valid"`
// Hour (bits 29..34): 0-23.
Hour int `json:"hour"`
// HourParityValid — even parity over bits 29..34 (bit 35).
HourParityValid bool `json:"hour_parity_valid"`
// DayOfMonth (bits 36..41): 1-31.
DayOfMonth int `json:"day_of_month"`
// DayOfWeek (bits 42..44): 1=Mon, 2=Tue, ..., 7=Sun.
DayOfWeek int `json:"day_of_week"`
DayOfWeekName string `json:"day_of_week_name"`
// Month (bits 45..49): 1-12.
Month int `json:"month"`
// Year (bits 50..57): 0-99 (the caller chooses the century).
Year int `json:"year"`
// DateParityValid — even parity over bits 36..57 (bit 58).
DateParityValid bool `json:"date_parity_valid"`
// FormattedTime renders the decoded time as "HH:MM" for
// quick reads.
FormattedTime string `json:"formatted_time"`
// FormattedDate renders the decoded date as "YYYY-MM-DD"
// using a 20YY century assumption (covers DCF77's current
// operating window 2000-2099).
FormattedDate string `json:"formatted_date"`
// AllParityValid is the AND of MinuteParityValid +
// HourParityValid + DateParityValid. Convenience flag for
// callers that want a single "frame integrity" indicator.
AllParityValid bool `json:"all_parity_valid"`
}
Frame is the top-level decoded DCF77 frame.
type SynthInput ¶ added in v0.375.0
type SynthInput struct {
Minute int `json:"minute"`
Hour int `json:"hour"`
DayOfMonth int `json:"day_of_month"`
DayOfWeek int `json:"day_of_week"`
Month int `json:"month"`
Year int `json:"year"`
CEST bool `json:"cest"`
}
SynthInput is the wall-clock time + timezone to encode into a DCF77 minute telegram. Fields use the same conventions Decode reports: DayOfWeek is ISO (1=Monday … 7=Sunday), Year is the two-digit year-within-century (0–99), CEST selects summer time (UTC+2) vs CET (UTC+1).