From ef5648301649e04ebabd21959a1b9c3519bf2e3d Mon Sep 17 00:00:00 2001 From: Priec Date: Wed, 19 Nov 2025 20:40:13 +0100 Subject: [PATCH] improved parsing of software uart --- .../src/software_uart/uart_emulation.rs | 78 +++++++++++++------ 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/semestralka_1i_rx_dma/src/software_uart/uart_emulation.rs b/semestralka_1i_rx_dma/src/software_uart/uart_emulation.rs index 8e46e74..51ca7d9 100644 --- a/semestralka_1i_rx_dma/src/software_uart/uart_emulation.rs +++ b/semestralka_1i_rx_dma/src/software_uart/uart_emulation.rs @@ -115,53 +115,85 @@ pub fn decode_uart_samples( let frame_bits = 1 + nbits + parity_bits + stop_bits_count; let frame_len = frame_bits * ovs; + // Helper: Majority vote over 3 samples centered at `i` + let get_bit = |i: usize| -> u8 { + let mut votes = 0; + // Check i-1, i, i+1. Saturating sub/add handles boundaries roughly. + if i > 0 && samples.get(i - 1).map_or(true, |&x| x != 0) { + votes += 1; + } + if samples.get(i).map_or(true, |&x| x != 0) { + votes += 1; + } + if samples.get(i + 1).map_or(true, |&x| x != 0) { + votes += 1; + } + + if votes >= 2 { + 1 + } else { + 0 + } + }; + // We loop while we have enough remaining samples for a full frame while idx + frame_len <= samples.len() { // Wait for falling edge (High -> Low) // samples[idx] == 1 (Idle/Stop) && samples[idx+1] == 0 (Start) if samples[idx] != 0 && samples[idx + 1] == 0 { - // Align to center of START bit // Start bit begins at idx+1. Center is at idx + 1 + (ovs/2) let center_offset = 1 + (ovs / 2); let mut scan_idx = idx + center_offset; - // Sanity check: is the middle of the start bit actually 0? - if samples.get(scan_idx).copied().unwrap_or(1) != 0 { - idx += 1; + // 1. Validate Start Bit (Must be 0) + if get_bit(scan_idx) != 0 { + idx += 1; // False start (noise), move on continue; } // Move to center of first data bit scan_idx += ovs; - // Sample data bits + // 2. Read Data Bits let mut data: u8 = 0; for bit in 0..nbits { - let bit_val = samples - .get(scan_idx) - .map(|&b| if b != 0 { 1u8 } else { 0u8 }) - .unwrap_or(1); // Default to high if out of bounds (shouldn't happen) - data |= bit_val << bit; + if get_bit(scan_idx) == 1 { + data |= 1 << bit; + } scan_idx += ovs; } - // Parity: skip - match cfg.parity { - Parity::None => {} - Parity::Even | Parity::Odd => { - scan_idx += ovs; - } + // 3. Skip Parity (if any) + if cfg.parity != Parity::None { + scan_idx += ovs; } - // We successfully read a byte. - // Advance main `idx` past this frame. - // We processed `frame_len` samples starting from `idx` (which was the idle bit before start). - // Actually, to be precise, we should advance by roughly the frame length. - idx += frame_len; - - // If overflow happens in push (unlikely given 256 limit), ignore + // 4. Validate Stop Bit (Must be 1) + // If stop bit is 0, it's a framing error. We reject the whole byte. + if get_bit(scan_idx) == 0 { + idx += 1; // Try to find a real start bit on the next sample + continue; + } + + // 5. Byte is valid let _ = out.push(data); + + // 6. Active Resync: Fast-forward through the stop bit(s) and idle time + // scan_idx is currently at the center of the Stop bit. + idx = scan_idx; + // Advance while we are reading High (1). + // As soon as we see Low (0), we stop. That 0 is the beginning of the NEXT start bit. + // The outer loop expects `idx` to be the High *before* the start bit, so we will handle that. + while idx < samples.len() && samples[idx] != 0 { + idx += 1; + } + // Back up one step. + // The outer loop logic is: `if samples[idx] != 0 && samples[idx+1] == 0`. + // If we stopped at `idx` because it was 0, then `idx-1` was the last 1 (Idle). + if idx > 0 { + idx -= 1; + } } else { // No start bit detected here, move to next sample idx += 1;