From ea39a62cc1e1d86608c506970d35f3b5be6be2a7 Mon Sep 17 00:00:00 2001 From: Nicola Ochsenbein - WSL Date: Thu, 5 Sep 2024 15:45:39 +0200 Subject: [PATCH 1/7] fix data pos overvlow --- Cargo.toml | 3 +++ src/lib.rs | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 77f072a..a532566 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,6 @@ license = "0BSD" name = "dcf77" repository = "https://github.com/therealprof/dcf77" version = "0.1.0" + +[dependencies] +defmt = "0.3" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 49935ee..3ebc7b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,10 @@ #![deny(warnings)] #![no_std] +use defmt::*; + /// A structure to facilitate the decoding of a DCF77 signal which consists of 59 consecutive bits -/// of data +/// of data pub struct DCF77Time(pub u64); impl DCF77Time { @@ -432,13 +434,20 @@ enum SimpleDCF77DecoderState { } /// A structure for a simple timeslot based DCF77 decoder -pub struct SimpleDCF77Decoder { +pub struct SimpleDCF77Decoder { + /// Number of samples since the last phase change scancount: u8, + /// Number of low bits in the current phase lowcount: u8, + /// Number of high bits in the current phase highcount: u8, + /// Number of idle bits after a valid bit was received idlecount: u8, + /// Current state of the decoder state: SimpleDCF77DecoderState, + /// The raw data received from the DCF77 signal data: u64, + /// Current position in the bitstream datapos: usize, } @@ -505,7 +514,9 @@ impl SimpleDCF77Decoder { /// current position and value of the DCF77 signal bitstream pub fn read_bit(&mut self, bit: bool) { self.state = match self.state { - SimpleDCF77DecoderState::EndOfCycle | SimpleDCF77DecoderState::WaitingForPhase | SimpleDCF77DecoderState::FaultyBit => { + SimpleDCF77DecoderState::EndOfCycle + | SimpleDCF77DecoderState::WaitingForPhase + | SimpleDCF77DecoderState::FaultyBit => { if bit { self.lowcount = 1; self.highcount = 0; @@ -543,6 +554,8 @@ impl SimpleDCF77Decoder { SimpleDCF77DecoderState::BitReceived } else { // Bad signal, let's continue with the next bit + println!("Faulty bit at position {}", datapos); + self.datapos = 0; SimpleDCF77DecoderState::FaultyBit } } @@ -556,6 +569,7 @@ impl SimpleDCF77Decoder { if self.idlecount > 10 { self.idlecount = 0; self.scancount = 0; + self.datapos = 0; } SimpleDCF77DecoderState::WaitingForPhase } else { From fc2d4d188cf6a3cd48b548fa87edd7f5ab0b7acf Mon Sep 17 00:00:00 2001 From: Nicola Ochsenbein - WSL Date: Thu, 5 Sep 2024 17:00:53 +0200 Subject: [PATCH 2/7] simplify code --- Cargo.toml | 3 - src/lib.rs | 166 +++++------------------------------------------------ 2 files changed, 15 insertions(+), 154 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a532566..77f072a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,3 @@ license = "0BSD" name = "dcf77" repository = "https://github.com/therealprof/dcf77" version = "0.1.0" - -[dependencies] -defmt = "0.3" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 3ebc7b5..7234f33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,6 @@ #![deny(warnings)] #![no_std] -use defmt::*; - /// A structure to facilitate the decoding of a DCF77 signal which consists of 59 consecutive bits /// of data pub struct DCF77Time(pub u64); @@ -82,43 +80,23 @@ impl DCF77Time { minutes } - /// Return the current minutes of the hour and verify parity and value < 60 - pub fn minutes(&self) -> Result { + fn calculate_parity(&self, start: usize, end: usize) -> bool { let mut parity = false; - if (self.0 & (1 << 21)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 22)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 23)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 24)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 25)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 26)) != 0 { - parity ^= true; + let mut mask: u64 = 1 << start; + for _ in start..=end { + parity ^= (self.0 & mask) != 0; + mask = mask.wrapping_shl(1); } + parity + } - if (self.0 & (1 << 27)) != 0 { - parity ^= true; - } + /// Return the current minutes of the hour and verify parity and value < 60 + pub fn minutes(&self) -> Result { + let parity = self.calculate_parity(21, 27); let minutes = self.minutes_unchecked(); - if minutes > 59 { - return Err(()); - } - if ((self.0 & (1 << 28)) != 0) != parity { + if ((self.0 & (1 << 28)) != 0) != parity || minutes > 59 { Err(()) } else { Ok(minutes) @@ -157,37 +135,11 @@ impl DCF77Time { /// Return the current hours of the day and verify parity and value < 23 pub fn hours(&self) -> Result { - let mut parity = false; - if (self.0 & (1 << 29)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 30)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 31)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 32)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 33)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 34)) != 0 { - parity ^= true; - } + let parity = self.calculate_parity(29, 34); let hours = self.hours_unchecked(); - if hours > 23 { - return Err(()); - } - if ((self.0 & (1 << 35)) != 0) != parity { + if ((self.0 & (1 << 35)) != 0) != parity || hours > 23 { Err(()) } else { Ok(hours) @@ -235,7 +187,7 @@ impl DCF77Time { } /// Return the current day of the week (without verifying the information) - /// 0 meaning Monday + /// 1 meaning Monday ... 7 meaning Sunday pub fn weekday_unchecked(&self) -> u8 { let mut weekday = 0; if (self.0 & (1 << 42)) != 0 { @@ -318,94 +270,7 @@ impl DCF77Time { /// Return a tuple of (year, month, day, weekday) if it passes a parity check pub fn date(&self) -> Result<(u16, u8, u8, u8), ()> { - let mut parity = false; - if (self.0 & (1 << 36)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 37)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 38)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 39)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 40)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 41)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 42)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 43)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 44)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 45)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 46)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 47)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 48)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 49)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 50)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 51)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 52)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 53)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 54)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 55)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 56)) != 0 { - parity ^= true; - } - - if (self.0 & (1 << 57)) != 0 { - parity ^= true; - } + let parity = self.calculate_parity(36, 57); if ((self.0 & (1 << 58)) != 0) != parity { return Err(()); @@ -554,7 +419,6 @@ impl SimpleDCF77Decoder { SimpleDCF77DecoderState::BitReceived } else { // Bad signal, let's continue with the next bit - println!("Faulty bit at position {}", datapos); self.datapos = 0; SimpleDCF77DecoderState::FaultyBit } From 06a091c632e5db7552f3e40c08e6894b3a875561 Mon Sep 17 00:00:00 2001 From: Nicola Ochsenbein - WSL Date: Fri, 6 Sep 2024 09:30:29 +0200 Subject: [PATCH 3/7] remove code duplicates, improve doc --- src/lib.rs | 212 +++++++++++------------------------------------------ 1 file changed, 44 insertions(+), 168 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7234f33..363ffcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,52 +48,12 @@ impl DCF77Time { /// Return the current minutes of the hour (without verifying the information) pub fn minutes_unchecked(&self) -> u8 { - let mut minutes = 0; - if (self.0 & (1 << 21)) != 0 { - minutes += 1; - } - - if (self.0 & (1 << 22)) != 0 { - minutes += 2; - } - - if (self.0 & (1 << 23)) != 0 { - minutes += 4; - } - - if (self.0 & (1 << 24)) != 0 { - minutes += 8; - } - - if (self.0 & (1 << 25)) != 0 { - minutes += 10; - } - - if (self.0 & (1 << 26)) != 0 { - minutes += 20; - } - - if (self.0 & (1 << 27)) != 0 { - minutes += 40; - } - - minutes - } - - fn calculate_parity(&self, start: usize, end: usize) -> bool { - let mut parity = false; - let mut mask: u64 = 1 << start; - for _ in start..=end { - parity ^= (self.0 & mask) != 0; - mask = mask.wrapping_shl(1); - } - parity + self.calculate_2digit_bcd(21, 27) } /// Return the current minutes of the hour and verify parity and value < 60 pub fn minutes(&self) -> Result { let parity = self.calculate_parity(21, 27); - let minutes = self.minutes_unchecked(); if ((self.0 & (1 << 28)) != 0) != parity || minutes > 59 { @@ -105,38 +65,12 @@ impl DCF77Time { /// Return the current hours of the day (without verifying the information) pub fn hours_unchecked(&self) -> u8 { - let mut hours = 0; - if (self.0 & (1 << 29)) != 0 { - hours += 1; - } - - if (self.0 & (1 << 30)) != 0 { - hours += 2; - } - - if (self.0 & (1 << 31)) != 0 { - hours += 4; - } - - if (self.0 & (1 << 32)) != 0 { - hours += 8; - } - - if (self.0 & (1 << 33)) != 0 { - hours += 10; - } - - if (self.0 & (1 << 34)) != 0 { - hours += 20; - } - - hours + self.calculate_2digit_bcd(29, 34) } /// Return the current hours of the day and verify parity and value < 23 pub fn hours(&self) -> Result { let parity = self.calculate_parity(29, 34); - let hours = self.hours_unchecked(); if ((self.0 & (1 << 35)) != 0) != parity || hours > 23 { @@ -148,32 +82,7 @@ impl DCF77Time { /// Return the current day of month (without verifying the information) pub fn day_unchecked(&self) -> u8 { - let mut day = 0; - if (self.0 & (1 << 36)) != 0 { - day += 1; - } - - if (self.0 & (1 << 37)) != 0 { - day += 2; - } - - if (self.0 & (1 << 38)) != 0 { - day += 4; - } - - if (self.0 & (1 << 39)) != 0 { - day += 8; - } - - if (self.0 & (1 << 40)) != 0 { - day += 10; - } - - if (self.0 & (1 << 41)) != 0 { - day += 20; - } - - day + self.calculate_2digit_bcd(36, 41) } /// Return the current day of month and do a basic value check @@ -189,83 +98,18 @@ impl DCF77Time { /// Return the current day of the week (without verifying the information) /// 1 meaning Monday ... 7 meaning Sunday pub fn weekday_unchecked(&self) -> u8 { - let mut weekday = 0; - if (self.0 & (1 << 42)) != 0 { - weekday += 1; - } - - if (self.0 & (1 << 43)) != 0 { - weekday += 2; - } - - if (self.0 & (1 << 44)) != 0 { - weekday += 4; - } - weekday + self.calculate_2digit_bcd(42, 44) } /// Return the current month of the year (without verifying the information) pub fn month_unchecked(&self) -> u8 { - let mut month = 0; - if (self.0 & (1 << 45)) != 0 { - month += 1; - } - - if (self.0 & (1 << 46)) != 0 { - month += 2; - } - - if (self.0 & (1 << 47)) != 0 { - month += 4; - } - - if (self.0 & (1 << 48)) != 0 { - month += 8; - } - - if (self.0 & (1 << 49)) != 0 { - month += 10; - } - - month + self.calculate_2digit_bcd(45, 49) } /// Return the current year (without verifying the information) pub fn year_unchecked(&self) -> u16 { - let mut year = 2000; - if (self.0 & (1 << 50)) != 0 { - year += 1; - } - - if (self.0 & (1 << 51)) != 0 { - year += 2; - } - - if (self.0 & (1 << 52)) != 0 { - year += 4; - } - - if (self.0 & (1 << 53)) != 0 { - year += 8; - } - - if (self.0 & (1 << 54)) != 0 { - year += 10; - } - - if (self.0 & (1 << 55)) != 0 { - year += 20; - } - - if (self.0 & (1 << 56)) != 0 { - year += 40; - } - - if (self.0 & (1 << 57)) != 0 { - year += 80; - } - - year + let century: u16 = 2000; + century + >::into(self.calculate_2digit_bcd(50, 57)) } /// Return a tuple of (year, month, day, weekday) if it passes a parity check @@ -287,6 +131,25 @@ impl DCF77Time { Ok((year, month, day, weekday)) } } + + fn calculate_parity(&self, start: usize, end: usize) -> bool { + let mut parity = false; + let mut mask: u64 = 1 << start; + for _ in start..=end { + parity ^= (self.0 & mask) != 0; + mask = mask.wrapping_shl(1); + } + parity + } + + fn calculate_2digit_bcd(&self, start: usize, end: usize) -> u8 { + let length = end - start + 1; + let mask = (1u64 << length) - 1; + let bcd = (self.0 >> start) & mask; + let high_nibble: u8 = (bcd & 0xF0) as u8 >> 4; + let low_nibble: u8 = bcd as u8 & 0x0F; + high_nibble * 10 + low_nibble + } } enum SimpleDCF77DecoderState { @@ -300,13 +163,13 @@ enum SimpleDCF77DecoderState { /// A structure for a simple timeslot based DCF77 decoder pub struct SimpleDCF77Decoder { - /// Number of samples since the last phase change + /// Number of samples since the last phase change, that always starts with a high signal and is max 2000 ms long scancount: u8, - /// Number of low bits in the current phase + /// Number of high bits during the first 100 ms in the scan phase to check if it might be a transmitted 0 lowcount: u8, - /// Number of high bits in the current phase + /// Number of high bits between 100 and 200 ms in the scan phase to check if it might be a transmitted 1 highcount: u8, - /// Number of idle bits after a valid bit was received + /// Number of idle bits after a valid bit was detected idlecount: u8, /// Current state of the decoder state: SimpleDCF77DecoderState, @@ -319,7 +182,15 @@ pub struct SimpleDCF77Decoder { /// The SimpleDCF77Decoder implements a simple state machine to decode a DCF77 signal from a fed-in /// readout of a GPIO pin connected to a DCF77 receiver. To use this, create the structure, set up /// the GPIO pin the receiver is connected to as an input and call the `read_bit` method every -/// 10ms with a parameter value of `true` for a high signal level or `false` for a low signal level +/// 10ms with a parameter value of `true` for a high signal (low rf amplitude) level or `false` for a low signal level (high rf amplitude). +/// +/// Example Signal of the DCF77 receiver output: +/// +/// ```text +/// 100ms 900ms 200ms 800ms 100ms +/// ___ _______ ___ +/// ... __| |____________________________________| |______________________________| |____ ... +/// ``` impl SimpleDCF77Decoder { /// Create a new decoder state machine pub fn new() -> Self { @@ -379,6 +250,7 @@ impl SimpleDCF77Decoder { /// current position and value of the DCF77 signal bitstream pub fn read_bit(&mut self, bit: bool) { self.state = match self.state { + // wait for the first phase change 0->1 or abort if no phase change is detected within 1800 ms (180 samples) SimpleDCF77DecoderState::EndOfCycle | SimpleDCF77DecoderState::WaitingForPhase | SimpleDCF77DecoderState::FaultyBit => { @@ -398,6 +270,8 @@ impl SimpleDCF77Decoder { } } } + // count the number of high bits in the first 100 ms and the second 100 ms to determine + // if a 0 or 1 was transmitted SimpleDCF77DecoderState::PhaseFound => { if self.scancount < 20 { if bit { @@ -424,6 +298,8 @@ impl SimpleDCF77Decoder { } } } + // wait until the 900 ms of the bit are over and then check if the signal was idle for + // at least 100 ms to start the next bit SimpleDCF77DecoderState::BitReceived | SimpleDCF77DecoderState::Idle => { if bit { self.idlecount += 1; From 03c369aa630ce42906a594c9860ad48b35fd4bf0 Mon Sep 17 00:00:00 2001 From: Nicola Ochsenbein - WSL Date: Fri, 6 Sep 2024 09:56:32 +0200 Subject: [PATCH 4/7] improve doc --- src/lib.rs | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 363ffcc..ac15131 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,13 +163,16 @@ enum SimpleDCF77DecoderState { /// A structure for a simple timeslot based DCF77 decoder pub struct SimpleDCF77Decoder { - /// Number of samples since the last phase change, that always starts with a high signal and is max 2000 ms long + /// Number of samples since the last phase change, that always starts with a high signal and is + /// max 2000 ms long scancount: u8, - /// Number of high bits during the first 100 ms in the scan phase to check if it might be a transmitted 0 + /// Number of high samples during the first 100 ms in the scan phase to check if it might be a + /// transmitted 0 lowcount: u8, - /// Number of high bits between 100 and 200 ms in the scan phase to check if it might be a transmitted 1 + /// Number of high samples between 100 and 200 ms in the scan phase to check if it might be a + /// transmitted 1 highcount: u8, - /// Number of idle bits after a valid bit was detected + /// Number of idle samples after a valid bit was detected idlecount: u8, /// Current state of the decoder state: SimpleDCF77DecoderState, @@ -182,14 +185,24 @@ pub struct SimpleDCF77Decoder { /// The SimpleDCF77Decoder implements a simple state machine to decode a DCF77 signal from a fed-in /// readout of a GPIO pin connected to a DCF77 receiver. To use this, create the structure, set up /// the GPIO pin the receiver is connected to as an input and call the `read_bit` method every -/// 10ms with a parameter value of `true` for a high signal (low rf amplitude) level or `false` for a low signal level (high rf amplitude). -/// -/// Example Signal of the DCF77 receiver output: -/// +/// 10ms with a parameter value of `true` for a high signal (low rf amplitude) level or `false` for +/// a low signal level +/// (high rf amplitude). +/// +/// Example Signal: +/// /// ```text -/// 100ms 900ms 200ms 800ms 100ms -/// ___ _______ ___ -/// ... __| |____________________________________| |______________________________| |____ ... +/// DCF77 RF signal: +/// +/// | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| +/// | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| +/// | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| +/// ...|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||... +/// +/// DCF77 receiver output that can be fed into this state machine: +/// ___ _______ ___ +/// ..._| |____________________________________| |______________________________| |___... +/// 100ms 900ms 200ms 800ms 100ms /// ``` impl SimpleDCF77Decoder { /// Create a new decoder state machine @@ -250,7 +263,9 @@ impl SimpleDCF77Decoder { /// current position and value of the DCF77 signal bitstream pub fn read_bit(&mut self, bit: bool) { self.state = match self.state { - // wait for the first phase change 0->1 or abort if no phase change is detected within 1800 ms (180 samples) + // wait for the first phase change 0->1 or abort if no phase change is detected within + // 1800 ms + // (180 samples) SimpleDCF77DecoderState::EndOfCycle | SimpleDCF77DecoderState::WaitingForPhase | SimpleDCF77DecoderState::FaultyBit => { From 7290a0dd2e3facdac606803047237b38b9a47f0c Mon Sep 17 00:00:00 2001 From: Nicola Ochsenbein - WSL Date: Fri, 6 Sep 2024 10:05:28 +0200 Subject: [PATCH 5/7] move signal wave form from code doc to README --- README.md | 50 +++++++++++++++++++++++++++++++++----------------- src/lib.rs | 19 +------------------ 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 40c5f7d..a26ec7f 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,33 @@ -dcf77 -====== - -_dcf77_ contains a state machine to identify a [DCF77][] signal fed in to a -regular GPIO pin. It also contains a decoder for the received signal into -date/time values. - -The driver is hardware independent and can e.g. be used with microcontrollers and -any implementation of an [embedded-hal][] crate. - -[embedded-hal]: https://github.com/japaric/embedded-hal.git -[DCF77]: https://en.wikipedia.org/wiki/DCF77 - -License -------- - -[0-clause BSD license](LICENSE-0BSD.txt). +dcf77 +====== + +_dcf77_ contains a state machine to identify a [DCF77][] signal fed in to a +regular GPIO pin. It also contains a decoder for the received signal into +date/time values. + +The driver is hardware independent and can e.g. be used with microcontrollers and +any implementation of an [embedded-hal][] crate. + +The input signal of the dcf77 statemachine shall look like this + +```text +DCF77 RF signal: + + | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| + | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| + | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| +...|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||... + +DCF77 receiver output that can be fed into this state machine: + ___ _______ ___ +..._| |____________________________________| |______________________________| |___... + 100ms 900ms 200ms 800ms 100ms +``` + +[embedded-hal]: https://github.com/japaric/embedded-hal.git +[DCF77]: https://en.wikipedia.org/wiki/DCF77 + +License +------- + +[0-clause BSD license](LICENSE-0BSD.txt). diff --git a/src/lib.rs b/src/lib.rs index ac15131..bb2f2c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,24 +186,7 @@ pub struct SimpleDCF77Decoder { /// readout of a GPIO pin connected to a DCF77 receiver. To use this, create the structure, set up /// the GPIO pin the receiver is connected to as an input and call the `read_bit` method every /// 10ms with a parameter value of `true` for a high signal (low rf amplitude) level or `false` for -/// a low signal level -/// (high rf amplitude). -/// -/// Example Signal: -/// -/// ```text -/// DCF77 RF signal: -/// -/// | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| -/// | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| -/// | ||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||| ||| -/// ...|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||... -/// -/// DCF77 receiver output that can be fed into this state machine: -/// ___ _______ ___ -/// ..._| |____________________________________| |______________________________| |___... -/// 100ms 900ms 200ms 800ms 100ms -/// ``` +/// a low signal level (high rf amplitude). impl SimpleDCF77Decoder { /// Create a new decoder state machine pub fn new() -> Self { From 0785b767ad434775b3d5fbb5512ce731fe448e42 Mon Sep 17 00:00:00 2001 From: Nicola Ochsenbein - WSL Date: Fri, 6 Sep 2024 10:14:02 +0200 Subject: [PATCH 6/7] doc format --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bb2f2c9..fa46ccf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,8 +247,7 @@ impl SimpleDCF77Decoder { pub fn read_bit(&mut self, bit: bool) { self.state = match self.state { // wait for the first phase change 0->1 or abort if no phase change is detected within - // 1800 ms - // (180 samples) + // 1800 ms (180 samples) SimpleDCF77DecoderState::EndOfCycle | SimpleDCF77DecoderState::WaitingForPhase | SimpleDCF77DecoderState::FaultyBit => { From 413f92ad16446cbfbfd1c7bed6dc67332c1453c6 Mon Sep 17 00:00:00 2001 From: Nicola Ochsenbein - WSL Date: Fri, 6 Sep 2024 10:42:00 +0200 Subject: [PATCH 7/7] rename symobls to match rust style guide, fix missleading state transition and idle_count name --- src/lib.rs | 86 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fa46ccf..ef8739c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -165,21 +165,21 @@ enum SimpleDCF77DecoderState { pub struct SimpleDCF77Decoder { /// Number of samples since the last phase change, that always starts with a high signal and is /// max 2000 ms long - scancount: u8, + sample_count: u8, /// Number of high samples during the first 100 ms in the scan phase to check if it might be a /// transmitted 0 - lowcount: u8, + zero_bit_count: u8, /// Number of high samples between 100 and 200 ms in the scan phase to check if it might be a /// transmitted 1 - highcount: u8, - /// Number of idle samples after a valid bit was detected - idlecount: u8, + one_bit_count: u8, + /// Number of non-idle samples after a valid bit was detected + non_idle_count: u8, /// Current state of the decoder state: SimpleDCF77DecoderState, /// The raw data received from the DCF77 signal data: u64, /// Current position in the bitstream - datapos: usize, + data_pos: usize, } /// The SimpleDCF77Decoder implements a simple state machine to decode a DCF77 signal from a fed-in @@ -191,13 +191,13 @@ impl SimpleDCF77Decoder { /// Create a new decoder state machine pub fn new() -> Self { Self { - scancount: 0, - lowcount: 0, - highcount: 0, - idlecount: 0, + sample_count: 0, + zero_bit_count: 0, + one_bit_count: 0, + non_idle_count: 0, state: SimpleDCF77DecoderState::WaitingForPhase, data: 0, - datapos: 0, + data_pos: 0, } } @@ -233,13 +233,13 @@ impl SimpleDCF77Decoder { /// Returns the value of the latest received bit. Mainly useful for live display of the /// received bits pub fn latest_bit(&self) -> bool { - (self.data & (1 << (self.datapos - 1))) != 0 + (self.data & (1 << (self.data_pos - 1))) != 0 } /// Return the current position of the bit counter after the latest recognized end of a cycle /// which is identical to the current second of the minute pub fn seconds(&self) -> usize { - self.datapos + self.data_pos } /// Ingest the latest sample of the GPIO input the DCF77 receiver is connected to judge the / @@ -252,15 +252,15 @@ impl SimpleDCF77Decoder { | SimpleDCF77DecoderState::WaitingForPhase | SimpleDCF77DecoderState::FaultyBit => { if bit { - self.lowcount = 1; - self.highcount = 0; - self.scancount = 0; + self.zero_bit_count = 1; + self.one_bit_count = 0; + self.sample_count = 0; + self.non_idle_count = 0; SimpleDCF77DecoderState::PhaseFound } else { - if self.scancount > 180 { - self.datapos = 0; - self.scancount = 0; - + if self.sample_count > 180 { + self.data_pos = 0; + self.sample_count = 0; SimpleDCF77DecoderState::EndOfCycle } else { SimpleDCF77DecoderState::WaitingForPhase @@ -270,51 +270,53 @@ impl SimpleDCF77Decoder { // count the number of high bits in the first 100 ms and the second 100 ms to determine // if a 0 or 1 was transmitted SimpleDCF77DecoderState::PhaseFound => { - if self.scancount < 20 { + if self.sample_count < 20 { if bit { - if self.scancount < 10 { - self.lowcount += 1; + if self.sample_count < 10 { + self.zero_bit_count += 1; } else { - self.highcount += 1; + self.one_bit_count += 1; } } SimpleDCF77DecoderState::PhaseFound } else { - let datapos = self.datapos; - self.datapos += 1; - if self.highcount > 3 { - self.data |= 1 << datapos; + let data_pos = self.data_pos; + self.data_pos += 1; + if self.one_bit_count > 3 { + self.data |= 1 << data_pos; SimpleDCF77DecoderState::BitReceived - } else if self.lowcount > 3 { - self.data &= !(1 << datapos); + } else if self.zero_bit_count > 3 { + self.data &= !(1 << data_pos); SimpleDCF77DecoderState::BitReceived } else { - // Bad signal, let's continue with the next bit - self.datapos = 0; + // Bad signal, let's start over + self.data_pos = 0; SimpleDCF77DecoderState::FaultyBit } } } - // wait until the 900 ms of the bit are over and then check if the signal was idle for - // at least 100 ms to start the next bit + // wait until the 900 ms of the bit are over and then check if the signal was not idle + // for max 10 samples to start the next bit SimpleDCF77DecoderState::BitReceived | SimpleDCF77DecoderState::Idle => { if bit { - self.idlecount += 1; + self.non_idle_count += 1; } - if self.scancount >= 90 { - if self.idlecount > 10 { - self.idlecount = 0; - self.scancount = 0; - self.datapos = 0; + if self.sample_count >= 90 { + if self.non_idle_count < 10 { + SimpleDCF77DecoderState::WaitingForPhase + } + else{ + // Bad signal, let's start over + self.data_pos = 0; + SimpleDCF77DecoderState::FaultyBit } - SimpleDCF77DecoderState::WaitingForPhase } else { SimpleDCF77DecoderState::Idle } } }; - self.scancount += 1; + self.sample_count += 1; } }