use rdif_serial::{
Config, ConfigError, DataBits, IrqRxBatch, Parity, RxErrorFlags, RxFlag, RxSample,
SerialEventSet, SerialIrqEvent, SerialIrqReport, SerialParts, SplitUart, StopBits,
UartEmergencyTx, UartInfo, UartIrq, UartPort,
};
#[test]
fn config_builder_records_requested_serial_mode() {
let config = Config::new()
.baudrate(9_600)
.data_bits(DataBits::Seven)
.stop_bits(StopBits::Two)
.parity(Parity::Even);
assert_eq!(config.baudrate, Some(9_600));
assert_eq!(config.data_bits, Some(DataBits::Seven));
assert_eq!(config.stop_bits, Some(StopBits::Two));
assert_eq!(config.parity, Some(Parity::Even));
}
#[test]
fn event_sets_classify_rx_and_tx_sources() {
let rx = SerialEventSet::RX_DATA | SerialEventSet::RX_TIMEOUT;
assert!(rx.has_rx());
assert!(!rx.has_tx());
let tx = SerialEventSet::TX_SPACE;
assert!(!tx.has_rx());
assert!(tx.has_tx());
let combined = rx | tx | SerialEventSet::FAULT;
assert!(combined.contains(SerialEventSet::FAULT));
assert!(combined.has_rx());
assert!(combined.has_tx());
}
#[test]
fn rx_samples_and_irq_events_keep_normalized_status() {
let sample = RxSample {
byte: Some(b'x'),
flag: RxFlag::Framing,
overrun: true,
};
assert_eq!(sample.byte, Some(b'x'));
assert_eq!(sample.flag, RxFlag::Framing);
assert!(sample.overrun);
let event = SerialIrqEvent {
events: SerialEventSet::RX_STATUS,
rx_errors: RxErrorFlags::FRAMING | RxErrorFlags::OVERRUN,
rearm: SerialEventSet::RX_DATA,
};
assert!(event.events.has_rx());
assert!(event.rx_errors.contains(RxErrorFlags::FRAMING));
assert!(event.rx_errors.contains(RxErrorFlags::OVERRUN));
assert_eq!(event.rearm, SerialEventSet::RX_DATA);
}
struct MockPort {
config: Config,
tx: [u8; 4],
tx_len: usize,
rx: Option<RxSample>,
masked: bool,
}
impl MockPort {
const fn new() -> Self {
Self {
config: Config::new(),
tx: [0; 4],
tx_len: 0,
rx: None,
masked: false,
}
}
}
impl UartPort for MockPort {
fn startup(&mut self, config: &Config) -> Result<(), ConfigError> {
self.config = config.clone();
self.masked = true;
Ok(())
}
fn shutdown(&mut self) {
self.masked = true;
}
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.config = config.clone();
Ok(())
}
fn read_rx(&mut self) -> Option<RxSample> {
self.rx.take()
}
fn discard_rx(&mut self) {
self.rx = None;
}
fn write_tx(&mut self, bytes: &[u8]) -> usize {
let count = bytes.len().min(self.tx.len());
self.tx[..count].copy_from_slice(&bytes[..count]);
self.tx_len = count;
count
}
fn discard_tx(&mut self) -> bool {
self.tx_len = 0;
true
}
fn tx_idle(&mut self) -> bool {
self.tx_len == 0
}
fn mask(&mut self, _sources: SerialEventSet) {
self.masked = true;
}
fn mask_all(&mut self) {
self.masked = true;
}
fn rearm(&mut self, sources: SerialEventSet) -> SerialEventSet {
self.masked = false;
sources & SerialEventSet::RX
}
}
struct MockIrq {
pending: Option<SerialIrqEvent>,
sample: Option<RxSample>,
}
impl UartIrq for MockIrq {
fn mask(&mut self, _sources: SerialEventSet) {}
fn handle(&mut self) -> Option<SerialIrqReport> {
let event = self.pending.take()?;
let mut rx = IrqRxBatch::new();
if let Some(sample) = self.sample.take() {
rx.try_push(sample)
.expect("one mock sample must fit in the IRQ batch");
}
Some(SerialIrqReport::new(event, rx))
}
}
struct MockUart;
struct MockEmergencyTx;
impl UartEmergencyTx for MockEmergencyTx {
unsafe fn mask_interrupts_unlocked(&self) {}
unsafe fn try_write_unlocked(&self, bytes: &[u8]) -> usize {
bytes.len().min(1)
}
}
impl SplitUart for MockUart {
type Control = MockPort;
type Irq = MockIrq;
type EmergencyTx = MockEmergencyTx;
fn runtime_info(&self) -> UartInfo {
UartInfo {
name: "mock-uart",
register_base: 0x1000,
initial_baudrate: 115_200,
}
}
fn split(self) -> SerialParts<Self::Control, Self::Irq, Self::EmergencyTx> {
SerialParts::new(
MockPort::new(),
MockIrq {
pending: Some(SerialIrqEvent {
events: SerialEventSet::RX_DATA,
rx_errors: RxErrorFlags::empty(),
rearm: SerialEventSet::RX_DATA,
}),
sample: Some(RxSample {
byte: Some(b'a'),
flag: RxFlag::Normal,
overrun: false,
}),
},
MockEmergencyTx,
)
}
}
#[test]
fn split_uart_exposes_independent_task_and_irq_endpoints() {
let uart = MockUart;
let info = uart.runtime_info();
assert_eq!(info.name, "mock-uart");
assert_eq!(info.register_base, 0x1000);
assert_eq!(info.initial_baudrate, 115_200);
let SerialParts {
mut control,
mut irq,
emergency_tx: _,
} = uart.split();
let config = Config::new().baudrate(57_600);
assert!(control.startup(&config).is_ok());
assert_eq!(control.config.baudrate, Some(57_600));
assert_eq!(control.write_tx(b"abcdef"), 4);
assert!(!control.tx_idle());
assert_eq!(
control.rearm(SerialEventSet::RX_DATA | SerialEventSet::TX_SPACE),
SerialEventSet::RX_DATA
);
let report = irq.handle().expect("mock IRQ has pending event");
assert_eq!(report.rx.as_slice()[0].byte, Some(b'a'));
assert_eq!(report.event.events, SerialEventSet::RX_DATA);
}