// SPDX-License-Identifier: MIT OR Apache-2.0 // Copyright 2024 René Ladan use radio_datetime_utils::{ DST_ANNOUNCED, DST_PROCESSED, DST_SUMMER, LEAP_ANNOUNCED, LEAP_MISSING, LEAP_PROCESSED, }; use dcf77_utils::DCF77Utils; // quick and dirty parsing function fn parse_dst(dst: Option) -> String { if dst.is_none() { return String::from("*"); } let mut res = String::from(""); let s_dst = dst.unwrap(); if s_dst & DST_ANNOUNCED != 0 { res += "announced "; } if s_dst & DST_PROCESSED != 0 { res += "processed "; } if s_dst & DST_SUMMER != 0 { res += "summer"; } else { res += "winter"; } res } fn str_weekday(day: Option) -> String { String::from(match day { Some(0) => "?", Some(1) => "Monday", Some(2) => "Tuesday", Some(3) => "Wednesday", Some(4) => "Thursday", Some(5) => "Friday", Some(6) => "Saturday", Some(7) => "Sunday", None => "None", _ => "", }) } fn parse_leapsecond(ls: Option, is_one: Option) -> String { if ls.is_none() { return String::from("*"); } let mut res = String::from(""); let s_ls = ls.unwrap(); if s_ls & LEAP_ANNOUNCED != 0 { res += "announced "; } if s_ls & LEAP_PROCESSED != 0 { res += "processed "; res += match is_one { Some(true) => " 1-instead-of-0 ", Some(false) => "", None => "*", } } if s_ls & LEAP_MISSING != 0 { res += "missing"; } res } fn main() { // Pretend to do live decoding, e.g. by detecting the time differences in microseconds from // edges read from a GPIO pin. Samples need to be in absolute time since some point, not in // relative time to each other. Format is (time-in-us-since-some-point, edge-becomes-high). // The boolean value is the inverse of the radio signal (see // https://en.wikipedia.org/wiki/DCF77#/media/File:DCF77_code.svg ) const SAMPLES: [(u32, bool); 122] = [ (419878222, true), (419994127, false), (421879420, true), (421993909, false), (422878486, true), (423096680, false), (423878635, true), (423996148, false), (424879214, true), (424995340, false), (425879677, true), (426096537, false), (426879389, true), (427098425, false), (427879069, true), (428098592, false), (428878142, true), (429097255, false), (429880457, true), (430094647, false), (430878441, true), (431101211, false), (431879863, true), (431995444, false), (432880438, true), (433094660, false), (433880659, true), (434097586, false), (434878947, true), (434994297, false), (435879906, true), (436095402, false), (436879753, true), (436993732, false), (437879570, true), (437993803, false), (438879730, true), (438993954, false), (439879587, true), (440097608, false), (440879385, true), (440996300, false), (441879265, true), (442098812, false), (442879414, true), (443097163, false), (443879871, true), (444098379, false), (444879431, true), (445096020, false), (445879087, true), (445995405, false), (446879690, true), (447093251, false), (447879256, true), (447995003, false), (448878561, true), (449095092, false), (449879350, true), (450099078, false), (450879372, true), (450993982, false), (451879342, true), (452098213, false), (452878519, true), (452995944, false), (453878657, true), (453993212, false), (454879919, true), (455097547, false), (455879782, true), (455996723, false), (456879091, true), (456995262, false), (457879629, true), (458096555, false), (458880213, true), (458996974, false), (459879878, true), (460099002, false), (460878999, true), (460996136, false), (461878396, true), (461994434, false), (462880614, true), (462993996, false), (463879321, true), (463994609, false), (464879642, true), (465097262, false), (465878747, true), (466099624, false), (466879199, true), (467097612, false), (467879093, true), (467995798, false), (468879484, true), (468994767, false), (469879145, true), (469997752, false), (470879522, true), (471100802, false), (471878503, true), (471994937, false), (472878993, true), (473099100, false), (473878453, true), (473995742, false), (474879545, true), (474994621, false), (475878401, true), (475994585, false), (476879857, true), (477098616, false), (477879080, true), (477997045, false), (478881025, true), (478994588, false), (479878796, true), (479994936, false), (481878510, true), (481995485, false), ]; let mut dcf77 = DCF77Utils::default(); for s in SAMPLES { dcf77.handle_new_edge(s.1, s.0); if s.1 { println!("{} {:?}", dcf77.get_second(), dcf77.get_current_bit()); if !dcf77.increase_second() { println!("Bad increase_second at second {}", dcf77.get_old_second()); } } if s.0 == 479994936 { // Remember, there is no bit at second 59. However, we still need to call // increase_second() here (halfway the minute marker) to let get_second() // show the correct value and to pass checks in decode_time() println!("* {} {:?}", dcf77.get_second(), dcf77.get_current_bit()); if !dcf77.increase_second() { println!("Bad increase_second at second {}", dcf77.get_old_second()); } } if s.1 && dcf77.is_new_minute() { println!("New minute! Time to decode!"); dcf77.decode_time(true, true); println!("Bit 0={:?}", dcf77.get_bit_0()); println!( "Third party bits (hex)={:x?}", dcf77.get_third_party_buffer() ); println!("Call bit={:?}", dcf77.get_call_bit()); println!("Bit 20={:?}", dcf77.get_bit_20()); println!( "Parities={:?} {:?} {:?}", dcf77.get_parity_1(), dcf77.get_parity_2(), dcf77.get_parity_3() ); let rdt = dcf77.get_radio_datetime(); println!( "Date/time={:?}-{:?}-{:?} {:?}:{:?} {} {} {}", rdt.get_year(), rdt.get_month(), rdt.get_day(), rdt.get_hour(), rdt.get_minute(), str_weekday(rdt.get_weekday()), parse_dst(rdt.get_dst()), parse_leapsecond(rdt.get_leap_second(), dcf77.leap_second_is_one()) ); } } }