opentitanlib/test_utils/bitbanging/
uart.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::{Result, bail};
6use serde::{Deserialize, Serialize};
7use serialport::Parity;
8use thiserror::Error;
9
10// The number of stop bits used for UART bitbanging.
11#[derive(Clone, Copy, Debug, PartialEq)]
12pub enum UartStopBits {
13    Stop1,
14    Stop1_5,
15    Stop2,
16}
17
18/// UART frame configuration to use for UART bitbanging. Assumes LSB first.
19#[derive(Clone, Debug)]
20pub struct UartBitbangConfig {
21    pub data_bits: u8,           // Assumes <= 8 data bits
22    pub stop_bits: UartStopBits, // 1.5 bits is not currently supported
23    // The number of character cycles for which RX is held low during
24    // transmission of a break character
25    pub break_char_cycles: u8,
26    pub parity: Parity,
27}
28
29impl UartBitbangConfig {
30    pub fn new(
31        data_bits: u8,
32        stop_bits: UartStopBits,
33        break_char_cycles: u8,
34        parity: Parity,
35    ) -> Result<UartBitbangConfig> {
36        if !(5..=8).contains(&data_bits) {
37            bail!("UART bitbanging only supports between 5 and 8 bit data.");
38        }
39        if stop_bits == UartStopBits::Stop1_5 {
40            bail!("UART bitbanging only supports 1 or 2 stop bits.");
41        }
42        Ok(Self {
43            data_bits,
44            stop_bits,
45            break_char_cycles,
46            parity,
47        })
48    }
49
50    // The number of cycles to hold high for stop bits
51    fn stop_bit_time(&self) -> u8 {
52        match self.stop_bits {
53            UartStopBits::Stop1 => 1,
54            _ => 2,
55        }
56    }
57
58    /// The amount of samples (bit transmissions) in one frame.
59    pub fn bit_time_per_frame(&self) -> u32 {
60        let start_bit = 1;
61        let parity_bits = (self.parity != Parity::None) as u8;
62        let stop_bits = self.stop_bit_time();
63        (start_bit + self.data_bits + parity_bits + stop_bits).into()
64    }
65
66    /// For a break, hold logic low for (frame bit time) * break cycles
67    pub fn break_bit_time(&self) -> u32 {
68        self.bit_time_per_frame() * self.break_char_cycles as u32
69    }
70}
71
72/// Count the number of 1s in the data (& an optional parity bit).
73/// Return `true` if there is an even number of 1s, and `false` otherwise.
74#[inline]
75pub fn compute_parity(data: u8, parity_bit: Option<bool>) -> bool {
76    let data_parity = !data.count_ones().is_multiple_of(2);
77    if let Some(bit) = parity_bit {
78        data_parity ^ bit
79    } else {
80        data_parity
81    }
82}
83
84#[derive(Debug, PartialEq)]
85pub enum UartTransfer {
86    // Assumes <= 8 data bits.
87    Byte {
88        data: u8,
89    },
90    Broken {
91        data: u8,
92        parity: Option<bool>,
93        error: UartTransferDecodeError,
94    },
95    Break,
96}
97
98/// An encoder for creating UART bitbanging samples for transmission. `TX` is
99/// the bit in the output sample bitfield to use for TX transmissions.
100pub struct UartBitbangEncoder {
101    pub config: UartBitbangConfig,
102}
103
104impl UartBitbangEncoder {
105    pub fn new(config: UartBitbangConfig) -> Self {
106        Self { config }
107    }
108
109    /// Encode the transmission of a UART break condition into a bitbanging
110    /// sample, to be used on the TX pin.
111    pub fn encode_break(&self, samples: &mut Vec<u8>) {
112        let break_bits = self.config.break_bit_time() as usize;
113        let stop_bits = self.config.stop_bit_time() as usize;
114        samples.extend(std::iter::repeat_n(0x00, break_bits));
115        samples.extend(std::iter::repeat_n(0x01, stop_bits));
116    }
117
118    /// Encode the transmission of a character into UART bitbanging samples, to
119    /// be used on the TX pin. When configured to use X data bits, only the X
120    // LSBs of `data` will be used.
121    pub fn encode_character(&self, data: u8, samples: &mut Vec<u8>) {
122        samples.reserve(self.config.bit_time_per_frame() as usize);
123        // Start bit
124        samples.push(0x00);
125        // Data bits
126        for bit_index in 0..self.config.data_bits {
127            let bit = (data >> bit_index) & 0x01;
128            samples.push(bit);
129        }
130        // Parity bit (if applicable)
131        let parity = compute_parity(data, None);
132        match self.config.parity {
133            Parity::Even => samples.push(parity as u8),
134            Parity::Odd => samples.push(!parity as u8),
135            Parity::None => (),
136        }
137        // Stop bits
138        for _ in 0..self.config.stop_bit_time() {
139            samples.push(0x01);
140        }
141    }
142
143    /// Helper function to encode multiple characters into UART bitbanging
144    /// samples in one call.
145    pub fn encode_characters(&self, chars: &[u8], samples: &mut Vec<u8>) {
146        for char in chars {
147            self.encode_character(*char, samples);
148        }
149    }
150
151    /// Encode a UART transmission (data / break) into UART bitbanging samples,
152    // to be used on the TX pin.
153    pub fn encode_transfer(&self, transfer: &UartTransfer, samples: &mut Vec<u8>) -> Result<()> {
154        match *transfer {
155            UartTransfer::Broken { .. } => bail!("Cannot encode a broken UART transfer"),
156            UartTransfer::Break => self.encode_break(samples),
157            UartTransfer::Byte { data } => self.encode_character(data, samples),
158        }
159        Ok(())
160    }
161
162    /// Helper function to encode multiple UART transfers into UART bitbanging
163    /// samples in one call.
164    pub fn encode_transfers(
165        &self,
166        transfers: &[UartTransfer],
167        samples: &mut Vec<u8>,
168    ) -> Result<()> {
169        for transfer in transfers {
170            self.encode_transfer(transfer, samples)?;
171        }
172        Ok(())
173    }
174}
175
176#[derive(Error, Debug, PartialEq, Serialize, Deserialize)]
177pub enum UartTransferDecodeError {
178    #[error("Computed parity does not match expected parity")]
179    ParityMismatch,
180    #[error("Stop was not held high for the full stop time")]
181    InvalidStop,
182    #[error(
183        "RX held low too long for a valid transmission, but not long enough for a break condition"
184    )]
185    InvalidBreak,
186}
187
188/// Possible states for the decoder state machine to be in.
189#[derive(Debug, PartialEq)]
190enum DecodingState {
191    Idle,
192    Data {
193        data: u8, // Data encountered so far
194        bits: u8, // Number of data bits read so far
195    },
196    Parity {
197        data: u8, // Previously decoded data
198    },
199    Stop {
200        data: u8,             // Previously decoded data
201        parity: Option<bool>, // Previously decoded parity
202        stop_data: u8,        // Stop bit data encountered so far
203        stop_bits: u8,        // Number of stop bits read so far
204    },
205    Break {
206        bits: u32, // Logic low bits encountered so far
207    },
208}
209
210/// A decoder for decoding UART samples. `RX` is the bit in the input sample
211/// bitfield to use for RX transmissions.
212pub struct UartBitbangDecoder {
213    pub config: UartBitbangConfig,
214    state: DecodingState,
215}
216
217impl UartBitbangDecoder {
218    pub fn new(config: UartBitbangConfig) -> Self {
219        Self {
220            config,
221            state: DecodingState::Idle,
222        }
223    }
224
225    /// Finishes decoding a break transmission in the current UART transfer
226    fn get_decoded_break(&mut self) -> Result<UartTransfer> {
227        let DecodingState::Break { bits } = self.state else {
228            bail!("`get_decoded_break` called before decoding a break");
229        };
230        if bits < self.config.break_bit_time() {
231            let parity = if self.config.parity != Parity::None {
232                Some(false)
233            } else {
234                None
235            };
236            Ok(UartTransfer::Broken {
237                data: 0x00,
238                parity,
239                error: UartTransferDecodeError::InvalidBreak,
240            })
241        } else {
242            Ok(UartTransfer::Break)
243        }
244    }
245
246    /// Finishes decoding the current UART transfer.
247    fn get_decoded_character(&mut self) -> Result<UartTransfer> {
248        // Detect we've fully stopped, and handle invalid stop signals.
249        let DecodingState::Stop {
250            data,
251            parity,
252            stop_data,
253            stop_bits,
254        } = self.state
255        else {
256            bail!("`get_decoded_character` called before the end of a transmission");
257        };
258        if stop_bits != self.config.stop_bit_time() {
259            bail!("`get_decoded_character` called before reading all stop bits");
260        }
261        if stop_data.count_ones() as u8 != stop_bits {
262            return Ok(UartTransfer::Broken {
263                data,
264                parity,
265                error: UartTransferDecodeError::InvalidStop,
266            });
267        }
268
269        // If configured to use parity, check and report single parity errors.
270        if self.config.parity != Parity::None {
271            let decoded_parity = compute_parity(data, parity);
272            let expected_parity = self.config.parity != Parity::Even;
273            if expected_parity != decoded_parity {
274                return Ok(UartTransfer::Broken {
275                    data,
276                    parity,
277                    error: UartTransferDecodeError::ParityMismatch,
278                });
279            }
280        }
281
282        Ok(UartTransfer::Byte { data })
283    }
284
285    /// Given a sampled waveform (where bit RX is the UART RX), advance the
286    /// UART decoder state based on the contents of the sample. If the sample
287    /// is the final stop bit, return the decoded UART transfer.
288    pub fn decode_sample(&mut self, sample: u8) -> Result<Option<UartTransfer>> {
289        let rx = sample & 0x1;
290        match self.state {
291            DecodingState::Idle => {
292                if rx == 0 {
293                    self.state = DecodingState::Data {
294                        data: 0x00,
295                        bits: 0,
296                    };
297                }
298            }
299            DecodingState::Data { mut data, mut bits } => {
300                data |= rx << bits;
301                bits += 1;
302                self.state = if bits >= self.config.data_bits {
303                    if self.config.parity == Parity::None {
304                        DecodingState::Stop {
305                            data,
306                            parity: None,
307                            stop_data: 0x00,
308                            stop_bits: 0,
309                        }
310                    } else {
311                        DecodingState::Parity { data }
312                    }
313                } else {
314                    DecodingState::Data { data, bits }
315                }
316            }
317            DecodingState::Parity { data } => {
318                self.state = DecodingState::Stop {
319                    data,
320                    parity: Some(rx != 0),
321                    stop_data: 0x00,
322                    stop_bits: 0,
323                };
324            }
325            DecodingState::Stop {
326                data,
327                parity,
328                mut stop_data,
329                mut stop_bits,
330            } => {
331                stop_data |= rx << stop_bits;
332                stop_bits += 1;
333                self.state = DecodingState::Stop {
334                    data,
335                    parity,
336                    stop_data,
337                    stop_bits,
338                };
339                if stop_bits >= self.config.stop_bit_time() {
340                    if data != 0x00 || parity == Some(true) || stop_data != 0x00 {
341                        let decoded = self.get_decoded_character()?;
342                        self.state = DecodingState::Idle;
343                        return Ok(Some(decoded));
344                    }
345                    self.state = DecodingState::Break {
346                        bits: self.config.bit_time_per_frame(),
347                    }
348                }
349            }
350            DecodingState::Break { bits } => {
351                if rx != 0 {
352                    let decoded = self.get_decoded_break()?;
353                    self.state = DecodingState::Idle;
354                    return Ok(Some(decoded));
355                }
356                self.state = DecodingState::Break { bits: bits + 1 };
357            }
358        }
359        Ok(None)
360    }
361
362    /// A helper function to decode a sequence of UART waveform samples,
363    /// advancing the decoder based on the contents. If the sample contains
364    /// any final stop bits, the decoded UART transfers are returned.
365    pub fn decode_samples(&mut self, samples: &Vec<u8>) -> Result<Vec<UartTransfer>> {
366        let mut transfers = vec![];
367        for sample in samples {
368            if let Some(transfer) = self.decode_sample(*sample)? {
369                transfers.push(transfer);
370            }
371        }
372        Ok(transfers)
373    }
374
375    /// Check if the decoder is currently in the idle state or not
376    pub fn is_idle(&self) -> bool {
377        self.state == DecodingState::Idle
378    }
379
380    /// Reset the state of decoder
381    pub fn reset(&mut self) {
382        self.state = DecodingState::Idle;
383    }
384}
385
386#[cfg(test)]
387mod test {
388    use super::*;
389
390    fn compare_decoded_result(received: &[UartTransfer], expected: &[u8]) -> Result<()> {
391        assert_eq!(received.len(), expected.len());
392        for (transfer, expected) in received.iter().zip(expected.iter()) {
393            match transfer {
394                UartTransfer::Byte { data } => {
395                    assert_eq!(data, expected);
396                }
397                _ => bail!("Only expected to decode bytes"),
398            }
399        }
400        Ok(())
401    }
402
403    fn uart_encode_decode(config: UartBitbangConfig, message: Option<&[u8]>) -> Result<()> {
404        let encoder = UartBitbangEncoder::new(config.clone());
405        let mut decoder = UartBitbangDecoder::new(config);
406        let msg = message.unwrap_or(b"Hello, this is a simple UART test message.");
407        let mut samples = Vec::new();
408        encoder.encode_characters(msg, &mut samples);
409        assert!(!samples.is_empty());
410        let decoded = decoder
411            .decode_samples(&samples)
412            .expect("Should have decoded the bitbanged message");
413        assert!(decoder.is_idle());
414        compare_decoded_result(&decoded, msg)
415    }
416
417    #[test]
418    fn smoke() -> Result<()> {
419        // Encode and decode some test strings
420        let config = UartBitbangConfig::new(8, UartStopBits::Stop2, 1, Parity::None)?;
421        uart_encode_decode(config.clone(), None)?;
422        uart_encode_decode(config.clone(), Some(b"abc def ghi jkl"))?;
423        uart_encode_decode(config.clone(), Some(b"12345"))?;
424
425        // Check bitbang encoding against a known sample.
426        let encoder = UartBitbangEncoder::new(config);
427        let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];
428        let mut samples = Vec::new();
429        encoder.encode_characters(&bytes, &mut samples);
430        let expected = [
431            0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0,
432            1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1,
433            0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1,
434            1,
435        ];
436        assert_eq!(samples, expected);
437        Ok(())
438    }
439
440    #[test]
441    fn data_bits() -> Result<()> {
442        // Check invalid configurations
443        assert!(UartBitbangConfig::new(4, UartStopBits::Stop2, 1, Parity::None).is_err());
444        assert!(UartBitbangConfig::new(9, UartStopBits::Stop2, 1, Parity::None).is_err());
445        // Check all valid configurations of 5-8 data bits
446        let test_msg = b"data_bits TEST STRING";
447        for data_bits in 5..=8 {
448            let data_mask = ((0x1u16 << data_bits) - 1) as u8;
449            let msg = test_msg.iter().map(|b| b & data_mask).collect::<Vec<_>>();
450            uart_encode_decode(
451                UartBitbangConfig::new(data_bits, UartStopBits::Stop2, 1, Parity::None)?,
452                Some(&msg),
453            )?;
454        }
455        Ok(())
456    }
457
458    #[test]
459    fn stop_bits() -> Result<()> {
460        // Check invalid configurations
461        assert!(UartBitbangConfig::new(8, UartStopBits::Stop1_5, 1, Parity::None).is_err());
462        // Check valid configurations
463        for stop_bits in [UartStopBits::Stop1, UartStopBits::Stop2] {
464            uart_encode_decode(
465                UartBitbangConfig::new(8, stop_bits, 1, Parity::None)?,
466                Some(b"hello from the `stop_bits()` test!"),
467            )?;
468        }
469        // Check stop bits are being applied correctly
470        let mut samples = Vec::new();
471        UartBitbangEncoder::new(UartBitbangConfig::new(
472            8,
473            UartStopBits::Stop1,
474            1,
475            Parity::None,
476        )?)
477        .encode_character(0xA5, &mut samples);
478        assert_eq!(&samples, &[0, 1, 0, 1, 0, 0, 1, 0, 1, 1]);
479        samples.clear();
480        UartBitbangEncoder::new(UartBitbangConfig::new(
481            8,
482            UartStopBits::Stop2,
483            1,
484            Parity::None,
485        )?)
486        .encode_character(0xA5, &mut samples);
487        assert_eq!(&samples, &[0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1]);
488        // Check error on incorrect number of stop bits
489        assert_eq!(
490            UartBitbangDecoder::new(UartBitbangConfig::new(
491                8,
492                UartStopBits::Stop2,
493                1,
494                Parity::None
495            )?)
496            .decode_samples(&vec![0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0])?,
497            vec![UartTransfer::Broken {
498                data: 0xA5,
499                parity: None,
500                error: UartTransferDecodeError::InvalidStop,
501            }]
502        );
503        Ok(())
504    }
505
506    #[test]
507    fn parity_bits() -> Result<()> {
508        let tests = [
509            (Parity::None, vec![0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1]),
510            (Parity::Odd, vec![0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1]),
511            (Parity::Even, vec![0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1]),
512        ];
513        for (parity, expected) in tests {
514            // Basic encode/decode smoke test for the parity
515            uart_encode_decode(
516                UartBitbangConfig::new(8, UartStopBits::Stop2, 1, parity)?,
517                Some(b"this string is used for testing parity"),
518            )?;
519            // Check the parity bit is calculated correctly
520            let config = UartBitbangConfig::new(8, UartStopBits::Stop2, 1, parity)?;
521            let mut samples = Vec::new();
522            UartBitbangEncoder::new(config.clone()).encode_character(0xA5, &mut samples);
523            assert_eq!(&samples, &expected);
524            // Check single parity errors are caught by the decoder.
525            if parity == Parity::None {
526                continue;
527            }
528            let mut decoder = UartBitbangDecoder::new(config.clone());
529            let mut invalid_samples = expected.clone();
530            // Introduce an error on the parity bit
531            invalid_samples[9] = !invalid_samples[9] & 0x01;
532            assert_eq!(
533                decoder.decode_samples(&invalid_samples)?,
534                vec![UartTransfer::Broken {
535                    data: 0xA5,
536                    parity: Some(invalid_samples[9] != 0),
537                    error: UartTransferDecodeError::ParityMismatch,
538                }]
539            );
540            decoder.reset();
541            // Introduce an error on a single data bit
542            for data_bit in 0..8 {
543                invalid_samples = expected.clone();
544                invalid_samples[1 + data_bit] = !expected[1 + data_bit] & 0x01;
545                assert_eq!(
546                    decoder.decode_samples(&invalid_samples)?,
547                    vec![UartTransfer::Broken {
548                        data: 0xA5 ^ (0x1 << data_bit),
549                        parity: Some(expected[9] != 0),
550                        error: UartTransferDecodeError::ParityMismatch,
551                    }]
552                );
553                decoder.reset();
554            }
555        }
556        Ok(())
557    }
558
559    #[test]
560    fn breaks() -> Result<()> {
561        // Encode/decode tests for a variety of break times
562        let break_transfer = [
563            UartTransfer::Byte { data: 0x12 },
564            UartTransfer::Byte { data: 0x34 },
565            UartTransfer::Break,
566            UartTransfer::Byte { data: 0x56 },
567            UartTransfer::Byte { data: 0x78 },
568        ];
569        for break_cycles in 1..=5 {
570            let config =
571                UartBitbangConfig::new(8, UartStopBits::Stop2, break_cycles, Parity::None)?;
572            let encoder = UartBitbangEncoder::new(config.clone());
573            let mut decoder = UartBitbangDecoder::new(config.clone());
574            let mut samples = Vec::new();
575            encoder.encode_transfers(&break_transfer, &mut samples)?;
576            assert!(
577                samples.len() > (config.bit_time_per_frame() as usize) * (break_cycles as usize)
578            );
579            let decoded = decoder
580                .decode_samples(&samples)
581                .expect("Should have decoded the bitbanged transmission");
582            assert!(decoder.is_idle());
583            assert_eq!(&break_transfer, &decoded[..]);
584        }
585        // Check error on incorrect break time when decoding
586        assert_eq!(
587            UartBitbangDecoder::new(UartBitbangConfig::new(
588                8,
589                UartStopBits::Stop2,
590                2,
591                Parity::None
592            )?)
593            .decode_samples(&vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])?,
594            vec![UartTransfer::Broken {
595                data: 0x00,
596                parity: None,
597                error: UartTransferDecodeError::InvalidBreak,
598            }]
599        );
600        Ok(())
601    }
602
603    #[test]
604    fn partial_transfers() -> Result<()> {
605        // Check that the UART decoder is stateful, and correctly handles
606        // input samples of partial UART transfers.
607        let mut decoder = UartBitbangDecoder::new(UartBitbangConfig::new(
608            8,
609            UartStopBits::Stop2,
610            1,
611            Parity::None,
612        )?);
613        assert!(decoder.is_idle());
614        for sample in [0, 1, 0, 1, 0, 0, 1, 0, 1, 1] {
615            assert!(decoder.decode_samples(&vec![sample])?.is_empty());
616            assert!(!decoder.is_idle());
617        }
618        assert_eq!(
619            decoder.decode_samples(&vec![1])?,
620            vec![UartTransfer::Byte { data: 0xA5 }]
621        );
622        assert!(decoder.is_idle());
623        Ok(())
624    }
625}