improved parsing of software uart
This commit is contained in:
@@ -115,53 +115,85 @@ pub fn decode_uart_samples(
|
|||||||
let frame_bits = 1 + nbits + parity_bits + stop_bits_count;
|
let frame_bits = 1 + nbits + parity_bits + stop_bits_count;
|
||||||
let frame_len = frame_bits * ovs;
|
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
|
// We loop while we have enough remaining samples for a full frame
|
||||||
while idx + frame_len <= samples.len() {
|
while idx + frame_len <= samples.len() {
|
||||||
// Wait for falling edge (High -> Low)
|
// Wait for falling edge (High -> Low)
|
||||||
// samples[idx] == 1 (Idle/Stop) && samples[idx+1] == 0 (Start)
|
// samples[idx] == 1 (Idle/Stop) && samples[idx+1] == 0 (Start)
|
||||||
if samples[idx] != 0 && samples[idx + 1] == 0 {
|
if samples[idx] != 0 && samples[idx + 1] == 0 {
|
||||||
|
|
||||||
// Align to center of START bit
|
// Align to center of START bit
|
||||||
// Start bit begins at idx+1. Center is at idx + 1 + (ovs/2)
|
// Start bit begins at idx+1. Center is at idx + 1 + (ovs/2)
|
||||||
let center_offset = 1 + (ovs / 2);
|
let center_offset = 1 + (ovs / 2);
|
||||||
let mut scan_idx = idx + center_offset;
|
let mut scan_idx = idx + center_offset;
|
||||||
|
|
||||||
// Sanity check: is the middle of the start bit actually 0?
|
// 1. Validate Start Bit (Must be 0)
|
||||||
if samples.get(scan_idx).copied().unwrap_or(1) != 0 {
|
if get_bit(scan_idx) != 0 {
|
||||||
idx += 1;
|
idx += 1; // False start (noise), move on
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move to center of first data bit
|
// Move to center of first data bit
|
||||||
scan_idx += ovs;
|
scan_idx += ovs;
|
||||||
|
|
||||||
// Sample data bits
|
// 2. Read Data Bits
|
||||||
let mut data: u8 = 0;
|
let mut data: u8 = 0;
|
||||||
for bit in 0..nbits {
|
for bit in 0..nbits {
|
||||||
let bit_val = samples
|
if get_bit(scan_idx) == 1 {
|
||||||
.get(scan_idx)
|
data |= 1 << bit;
|
||||||
.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;
|
|
||||||
scan_idx += ovs;
|
scan_idx += ovs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parity: skip
|
// 3. Skip Parity (if any)
|
||||||
match cfg.parity {
|
if cfg.parity != Parity::None {
|
||||||
Parity::None => {}
|
scan_idx += ovs;
|
||||||
Parity::Even | Parity::Odd => {
|
|
||||||
scan_idx += ovs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We successfully read a byte.
|
// 4. Validate Stop Bit (Must be 1)
|
||||||
// Advance main `idx` past this frame.
|
// If stop bit is 0, it's a framing error. We reject the whole byte.
|
||||||
// We processed `frame_len` samples starting from `idx` (which was the idle bit before start).
|
if get_bit(scan_idx) == 0 {
|
||||||
// Actually, to be precise, we should advance by roughly the frame length.
|
idx += 1; // Try to find a real start bit on the next sample
|
||||||
idx += frame_len;
|
continue;
|
||||||
|
}
|
||||||
// If overflow happens in push (unlikely given 256 limit), ignore
|
|
||||||
|
// 5. Byte is valid
|
||||||
let _ = out.push(data);
|
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 {
|
} else {
|
||||||
// No start bit detected here, move to next sample
|
// No start bit detected here, move to next sample
|
||||||
idx += 1;
|
idx += 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user