use defmt::info; use embassy_stm32::exti::ExtiInput; use embassy_time::{Ticker, Timer}; use crate::{Encoding, bit_for_level, level_for_bit}; const START: u8 = 0x7E; const STOP: u8 = 0x81; const MAX_PAYLOAD: usize = 64; fn crc8(crc: u8, byte: u8) -> u8 { let mut c = crc ^ byte; for _ in 0..8 { c = if c & 0x80 != 0 { (c << 1) ^ 0x07 } else { c << 1 }; } c } async fn sample_byte( pin: &mut ExtiInput<'static>, encoding: Encoding, ticker: &mut Ticker, last_physical_level: &mut bool, bit_time: embassy_time::Duration, ) -> u8 { let mut byte = 0u8; for _ in 0..8 { let current_level = pin.is_high(); let bit = match encoding { Encoding::Nrz => { let bit = bit_for_level(pin.is_high()); ticker.next().await; bit } Encoding::Nrzi => { let bit = if current_level != *last_physical_level { 1 } else { 0 }; *last_physical_level = current_level; ticker.next().await; bit } Encoding::Manchester => { Timer::after(bit_time / 4).await; let first_half = pin.is_high(); Timer::after(bit_time / 2).await; let second_half = pin.is_high(); Timer::after(bit_time / 4).await; if first_half == level_for_bit(1) && second_half == level_for_bit(0) { 1 } else { 0 } } }; byte = (byte << 1) | bit; } byte } #[embassy_executor::task] pub async fn bit_receive_and_decode(mut pin: ExtiInput<'static>, encoding: Encoding) { loop { pin.wait_for_falling_edge().await; let t1 = embassy_time::Instant::now(); pin.wait_for_rising_edge().await; let bit_time = embassy_time::Instant::now().duration_since(t1); // stred data bitu if encoding != Encoding::Manchester { Timer::after(bit_time / 2).await; } let mut ticker = Ticker::every(bit_time); let mut last_level = level_for_bit(1); let mut start_byte = 0u8; for _ in 0..7 { let bit = match encoding { Encoding::Nrz => { let bit = bit_for_level(pin.is_high()); ticker.next().await; bit } Encoding::Nrzi => { let current_level = pin.is_high(); let b = if current_level != last_level { 1 } else { 0 }; last_level = current_level; ticker.next().await; b } Encoding::Manchester => { Timer::after(bit_time / 4).await; let first_pol = pin.is_high(); Timer::after(bit_time / 2).await; let second_pol = pin.is_high(); Timer::after(bit_time / 4).await; if first_pol == level_for_bit(1) && second_pol == level_for_bit(0) { 1 } else { 0 } } }; start_byte = (start_byte << 1) | bit; } if start_byte != START { info!("start fail: 0x{:02X}", start_byte); continue; } // len let len = sample_byte(&mut pin, encoding, &mut ticker, &mut last_level, bit_time).await; if len as usize > MAX_PAYLOAD { info!("bad len {}", len); continue; } // payload let mut payload = [0u8; MAX_PAYLOAD]; for i in 0..(len as usize) { payload[i] = sample_byte(&mut pin, encoding, &mut ticker, &mut last_level, bit_time).await; } // crc let crc_recv = sample_byte(&mut pin, encoding, &mut ticker, &mut last_level, bit_time).await; // parita let parity_recv = match encoding { Encoding::Nrz => { let bit = bit_for_level(pin.is_high()); ticker.next().await; bit } Encoding::Nrzi => { let current_p = pin.is_high(); let b = if current_p != last_level { 1 } else { 0 }; last_level = current_p; ticker.next().await; b } Encoding::Manchester => { Timer::after(bit_time / 4).await; let f = pin.is_high(); Timer::after(bit_time / 2).await; let s = pin.is_high(); Timer::after(bit_time / 4).await; if f == level_for_bit(1) && s == level_for_bit(0) { 1 } else { 0 } } }; // stop let stop = sample_byte(&mut pin, encoding, &mut ticker, &mut last_level, bit_time).await; if stop != STOP { info!("bad stop 0x{:02X}", stop); continue; } // verify CRC let mut crc_calc = crc8(0, len); for i in 0..(len as usize) { crc_calc = crc8(crc_calc, payload[i]); } if crc_calc != crc_recv { info!("crc nesedi 0x{:02X} ma byt 0x{:02X}", crc_recv, crc_calc); continue; } // verify parity let mut ones = len.count_ones() + crc_recv.count_ones(); for i in 0..(len as usize) { ones += payload[i].count_ones(); } if (ones as u8 & 1) != parity_recv { info!("nesedi parita"); continue; } if let Ok(s) = core::str::from_utf8(&payload[..len as usize]) { info!("RX OK: \"{}\"", s); } else { info!("RX OK: {} bytes", len); } } }