use defmt::info; use embassy_stm32::exti::ExtiInput; use embassy_time::{Duration, Timer}; 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>, bit_time: Duration) -> u8 { let mut byte = 0u8; for _ in 0..8 { let bit = if pin.is_high() { 1 } else { 0 }; byte = (byte << 1) | bit; Timer::after(bit_time).await; } byte } #[embassy_executor::task] pub async fn bit_receive_and_decode(mut pin: ExtiInput<'static>) { 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); Timer::after(bit_time / 2).await; let mut start_byte = 0u8; for _ in 0..7 { let bit = if pin.is_high() { 1 } else { 0 }; start_byte = (start_byte << 1) | bit; Timer::after(bit_time).await; } if start_byte != START { info!("start fail: 0x{:02X}", start_byte); continue; } // len let len = sample_byte(&mut pin, 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, bit_time).await; } // crc let crc_recv = sample_byte(&mut pin, bit_time).await; // parita let parity_recv = if pin.is_high() { 1 } else { 0 }; Timer::after(bit_time).await; // stop let stop = sample_byte(&mut pin, 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); } } }