// src/software_uart/uart_emulation.rs use heapless::Vec; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Parity { None, Even, Odd, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum StopBits { One, Two, } #[derive(Clone, Copy, Debug)] pub struct UartConfig { pub data_bits: u8, pub parity: Parity, pub stop_bits: StopBits, } impl Default for UartConfig { fn default() -> Self { Self { data_bits: 8, parity: Parity::None, stop_bits: StopBits::One, } } } /// Encodes one byte into a sequence of GPIO BSRR words pub fn encode_uart_byte_cfg( pin_bit: u8, data: u8, cfg: &UartConfig, out: &mut [u32; 12], ) -> usize { // GPIOx_BSRR register str. 636 kap. 13.4.7 let set_high = |bit: u8| -> u32 { 1u32 << bit }; let set_low = |bit: u8| -> u32 { 0 }; // let set_low = |bit: u8| -> u32 { 1u32 << (bit as u32 + 16) }; let mut idx = 0usize; // START bit (LOW) out[idx] = set_low(pin_bit); idx += 1; // Data bits, LSB-first let nbits = cfg.data_bits.clamp(5, 8); for i in 0..nbits { let one = ((data >> i) & 1) != 0; out[idx] = if one { set_high(pin_bit) } else { set_low(pin_bit) }; idx += 1; } // Parity match cfg.parity { Parity::None => {} Parity::Even | Parity::Odd => { let mask: u8 = if nbits == 8 { 0xFF } else { (1u16 << nbits) as u8 - 1 }; let ones = (data & mask).count_ones() & 1; let par_bit_is_one = match cfg.parity { Parity::Even => ones == 1, Parity::Odd => ones == 0, _ => false, }; out[idx] = if par_bit_is_one { set_high(pin_bit) } else { set_low(pin_bit) }; idx += 1; } } // STOP bits (HIGH) let stop_ticks = match cfg.stop_bits { StopBits::One => 1usize, StopBits::Two => 2usize, }; for _ in 0..stop_ticks { out[idx] = set_high(pin_bit); idx += 1; } idx } /// Decode an oversampled stream of logic levels into UART bytes. pub fn decode_uart_samples( samples: &[u8], oversample: u16, cfg: &UartConfig, ) -> heapless::Vec { let mut out = Vec::::new(); let mut idx = 0usize; let nbits = cfg.data_bits as usize; while idx + (oversample as usize * (nbits + 3)) < samples.len() { // Wait for start bit (falling edge: high -> low) if samples[idx] != 0 && samples[idx + 1] == 0 { // Align to middle of start bit idx += (oversample / 2) as usize; // Sanity check start bit really low if samples.get(idx).copied().unwrap_or(1) != 0 { idx += 1; continue; } // Sample data bits let mut data: u8 = 0; for bit in 0..nbits { idx += oversample as usize; let bit_val = samples .get(idx) .map(|&b| if b != 0 { 1u8 } else { 0u8 }) .unwrap_or(1); data |= bit_val << bit; } // Parity: skip / verify match cfg.parity { Parity::None => {} Parity::Even | Parity::Odd => { idx += oversample as usize; // You can optionally add parity check here if needed } } // Move past stop bits let stop_skip = match cfg.stop_bits { StopBits::One => oversample as usize, StopBits::Two => (oversample * 2) as usize, }; idx += stop_skip; // Push decoded byte let _ = out.push(data); } else { idx += 1; } } out }