pub(crate) mod sys;
use std::collections::VecDeque;
use std::io;
use std::sync::atomic::AtomicU8;
use std::sync::atomic::Ordering;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::TryRecvError;
use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
use anyhow::Context;
use base::error;
use base::warn;
use base::Event;
use base::EventToken;
use base::Result;
use base::WaitContext;
use base::WorkerThread;
use serde::Deserialize;
use serde::Serialize;
use snapshot::AnySnapshot;
use crate::bus::BusAccessInfo;
use crate::pci::CrosvmDeviceId;
use crate::serial_device::SerialInput;
use crate::suspendable::DeviceState;
use crate::suspendable::Suspendable;
use crate::BusDevice;
use crate::DeviceId;
const LOOP_SIZE: usize = 0x40;
const DATA: u8 = 0;
const IER: u8 = 1;
const IIR: u8 = 2;
const LCR: u8 = 3;
const MCR: u8 = 4;
const LSR: u8 = 5;
const MSR: u8 = 6;
const SCR: u8 = 7;
const DLAB_LOW: u8 = 0;
const DLAB_HIGH: u8 = 1;
const IER_RECV_BIT: u8 = 0x1;
const IER_THR_BIT: u8 = 0x2;
const IER_FIFO_BITS: u8 = 0x0f;
const IIR_FIFO_BITS: u8 = 0xc0;
const IIR_NONE_BIT: u8 = 0x1;
const IIR_THR_BIT: u8 = 0x2;
const IIR_RECV_BIT: u8 = 0x4;
const LSR_DATA_BIT: u8 = 0x1;
const LSR_EMPTY_BIT: u8 = 0x20;
const LSR_IDLE_BIT: u8 = 0x40;
const MCR_DTR_BIT: u8 = 0x01; const MCR_RTS_BIT: u8 = 0x02; const MCR_OUT1_BIT: u8 = 0x04;
const MCR_OUT2_BIT: u8 = 0x08;
const MCR_LOOP_BIT: u8 = 0x10;
const MSR_CTS_BIT: u8 = 0x10; const MSR_DSR_BIT: u8 = 0x20; const MSR_RI_BIT: u8 = 0x40; const MSR_DCD_BIT: u8 = 0x80; const DEFAULT_INTERRUPT_IDENTIFICATION: u8 = IIR_NONE_BIT; const DEFAULT_LINE_STATUS: u8 = LSR_EMPTY_BIT | LSR_IDLE_BIT; const DEFAULT_LINE_CONTROL: u8 = 0x3; const DEFAULT_MODEM_CONTROL: u8 = MCR_OUT2_BIT;
const DEFAULT_MODEM_STATUS: u8 = MSR_DSR_BIT | MSR_CTS_BIT | MSR_DCD_BIT;
const DEFAULT_BAUD_DIVISOR: u16 = 12; const TIMESTAMP_PREFIX_FMT: &str = "[ %F %T%.9f ]: ";
pub struct Serial {
    interrupt_enable: Arc<AtomicU8>,
    interrupt_identification: u8,
    interrupt_evt: Event,
    line_control: u8,
    line_status: u8,
    modem_control: u8,
    modem_status: u8,
    scratch: u8,
    baud_divisor: u16,
    in_buffer: VecDeque<u8>,
    in_channel: Option<Receiver<u8>>,
    input: Option<Box<dyn SerialInput>>,
    out: Option<Box<dyn io::Write + Send>>,
    out_timestamp: bool,
    last_write_was_newline: bool,
    #[cfg(windows)]
    pub system_params: sys::windows::SystemSerialParams,
    device_state: DeviceState,
    worker: Option<WorkerThread<Box<dyn SerialInput>>>,
}
impl Serial {
    fn new_common(
        interrupt_evt: Event,
        input: Option<Box<dyn SerialInput>>,
        out: Option<Box<dyn io::Write + Send>>,
        out_timestamp: bool,
        #[cfg(windows)] system_params: sys::windows::SystemSerialParams,
    ) -> Serial {
        Serial {
            interrupt_enable: Default::default(),
            interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
            interrupt_evt,
            line_control: DEFAULT_LINE_CONTROL,
            line_status: DEFAULT_LINE_STATUS,
            modem_control: DEFAULT_MODEM_CONTROL,
            modem_status: DEFAULT_MODEM_STATUS,
            scratch: 0,
            baud_divisor: DEFAULT_BAUD_DIVISOR,
            in_buffer: Default::default(),
            in_channel: None,
            input,
            out,
            out_timestamp,
            last_write_was_newline: true,
            #[cfg(windows)]
            system_params,
            device_state: DeviceState::Awake,
            worker: None,
        }
    }
    pub fn device_id() -> DeviceId {
        CrosvmDeviceId::Serial.into()
    }
    pub fn debug_label() -> String {
        "serial".to_owned()
    }
    pub fn queue_input_bytes(&mut self, c: &[u8]) -> Result<()> {
        if !c.is_empty() && !self.is_loop() {
            self.in_buffer.extend(c);
            self.set_data_bit();
            self.trigger_recv_interrupt()?;
        }
        Ok(())
    }
    fn spawn_input_thread(&mut self) {
        let mut rx = match self.input.take() {
            Some(input) => input,
            None => return,
        };
        let (send_channel, recv_channel) = channel();
        let interrupt_enable = self.interrupt_enable.clone();
        let interrupt_evt = match self.interrupt_evt.try_clone() {
            Ok(e) => e,
            Err(e) => {
                error!("failed to clone interrupt event: {}", e);
                return;
            }
        };
        self.worker = Some(WorkerThread::start(
            format!("{} input thread", self.debug_label()),
            move |kill_evt| {
                let mut rx_buf = [0u8; 1];
                #[derive(EventToken)]
                enum Token {
                    Kill,
                    SerialEvent,
                }
                let wait_ctx_res: Result<WaitContext<Token>> = WaitContext::build_with(&[
                    (&kill_evt, Token::Kill),
                    (rx.get_read_notifier(), Token::SerialEvent),
                ]);
                let wait_ctx = match wait_ctx_res {
                    Ok(wait_context) => wait_context,
                    Err(e) => {
                        error!("Failed to create wait context. {}", e);
                        return rx;
                    }
                };
                let mut kill_timeout = None;
                loop {
                    let events = match wait_ctx.wait() {
                        Ok(events) => events,
                        Err(e) => {
                            error!("Failed to wait for events. {}", e);
                            return rx;
                        }
                    };
                    for event in events.iter() {
                        match event.token {
                            Token::Kill => {
                                if events.iter().all(|e| matches!(e.token, Token::Kill)) {
                                    return rx;
                                }
                                const TIMEOUT_DURATION: Duration = Duration::from_millis(500);
                                match kill_timeout {
                                    None => {
                                        kill_timeout = Some(Instant::now() + TIMEOUT_DURATION);
                                    }
                                    Some(t) => {
                                        if Instant::now() >= t {
                                            error!(
                                                "failed to drain serial input within {:?}, giving up",
                                                TIMEOUT_DURATION
                                            );
                                            return rx;
                                        }
                                    }
                                }
                            }
                            Token::SerialEvent => {
                                match rx.read(&mut rx_buf) {
                                    Ok(0) => {
                                        return rx;
                                    }
                                    Ok(_n) => {
                                        if send_channel.send(rx_buf[0]).is_err() {
                                            return rx;
                                        }
                                        if (interrupt_enable.load(Ordering::SeqCst) & IER_RECV_BIT)
                                            != 0
                                        {
                                            interrupt_evt.signal().unwrap();
                                        }
                                    }
                                    Err(e) => {
                                        if e.kind() != io::ErrorKind::Interrupted {
                                            error!(
                                                "failed to read for bytes to queue into serial device: {}",
                                                e
                                            );
                                            return rx;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
        ));
        self.in_channel = Some(recv_channel);
    }
    fn drain_in_channel(&mut self) {
        loop {
            let in_channel = match self.in_channel.as_ref() {
                Some(v) => v,
                None => return,
            };
            match in_channel.try_recv() {
                Ok(byte) => {
                    self.queue_input_bytes(&[byte]).unwrap();
                }
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => {
                    self.in_channel = None;
                    return;
                }
            }
        }
    }
    pub fn interrupt_event(&self) -> &Event {
        &self.interrupt_evt
    }
    fn is_dlab_set(&self) -> bool {
        (self.line_control & 0x80) != 0
    }
    fn is_recv_intr_enabled(&self) -> bool {
        (self.interrupt_enable.load(Ordering::SeqCst) & IER_RECV_BIT) != 0
    }
    fn is_thr_intr_enabled(&self) -> bool {
        (self.interrupt_enable.load(Ordering::SeqCst) & IER_THR_BIT) != 0
    }
    fn is_thr_intr_changed(&self, bit: u8) -> bool {
        (self.interrupt_enable.load(Ordering::SeqCst) ^ bit) & IER_FIFO_BITS != 0
    }
    fn is_loop(&self) -> bool {
        (self.modem_control & MCR_LOOP_BIT) != 0
    }
    fn add_intr_bit(&mut self, bit: u8) {
        self.interrupt_identification &= !IIR_NONE_BIT;
        self.interrupt_identification |= bit;
    }
    fn del_intr_bit(&mut self, bit: u8) {
        self.interrupt_identification &= !bit;
        if self.interrupt_identification == 0x0 {
            self.interrupt_identification = IIR_NONE_BIT;
        }
    }
    fn trigger_thr_empty(&mut self) -> Result<()> {
        if self.is_thr_intr_enabled() {
            self.add_intr_bit(IIR_THR_BIT);
            self.trigger_interrupt()?
        }
        Ok(())
    }
    fn trigger_recv_interrupt(&mut self) -> Result<()> {
        if self.is_recv_intr_enabled() {
            if self.interrupt_identification & IIR_RECV_BIT == 0 {
                self.add_intr_bit(IIR_RECV_BIT);
                self.trigger_interrupt()?
            }
        }
        Ok(())
    }
    fn trigger_interrupt(&mut self) -> Result<()> {
        self.interrupt_evt.signal()
    }
    fn set_data_bit(&mut self) {
        self.line_status |= LSR_DATA_BIT;
    }
    fn is_data_avaiable(&self) -> bool {
        (self.line_status & LSR_DATA_BIT) != 0
    }
    fn iir_reset(&mut self) {
        self.interrupt_identification = DEFAULT_INTERRUPT_IDENTIFICATION;
    }
    fn handle_write(&mut self, offset: u8, v: u8) -> Result<()> {
        match offset {
            DLAB_LOW if self.is_dlab_set() => {
                self.baud_divisor = (self.baud_divisor & 0xff00) | v as u16
            }
            DLAB_HIGH if self.is_dlab_set() => {
                self.baud_divisor = (self.baud_divisor & 0x00ff) | ((v as u16) << 8)
            }
            DATA => {
                if self.is_loop() {
                    if self.in_buffer.len() < LOOP_SIZE {
                        self.in_buffer.push_back(v);
                        self.set_data_bit();
                        self.trigger_recv_interrupt()?;
                    }
                } else {
                    self.handle_write_data(v)?;
                    self.trigger_thr_empty()?;
                }
            }
            IER => {
                let tx_changed = self.is_thr_intr_changed(v);
                self.interrupt_enable
                    .store(v & IER_FIFO_BITS, Ordering::SeqCst);
                if self.is_data_avaiable() {
                    self.trigger_recv_interrupt()?;
                }
                if tx_changed {
                    self.trigger_thr_empty()?;
                }
            }
            LCR => self.line_control = v,
            MCR => self.modem_control = v,
            SCR => self.scratch = v,
            _ => {}
        }
        Ok(())
    }
    fn handle_write_data(&mut self, v: u8) -> Result<()> {
        let out = match self.out.as_mut() {
            Some(out) => out,
            None => return Ok(()),
        };
        if self.out_timestamp && self.last_write_was_newline {
            write!(out, "{}", chrono::Utc::now().format(TIMESTAMP_PREFIX_FMT))?;
        }
        self.last_write_was_newline = v == b'\n';
        out.write_all(&[v])?;
        out.flush()?;
        Ok(())
    }
}
impl BusDevice for Serial {
    fn device_id(&self) -> DeviceId {
        CrosvmDeviceId::Serial.into()
    }
    fn debug_label(&self) -> String {
        "serial".to_owned()
    }
    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        if matches!(self.device_state, DeviceState::Sleep) {
            panic!("Unexpected action: Attempt to write to serial when device is in sleep mode");
        }
        if data.len() != 1 {
            return;
        }
        #[cfg(windows)]
        self.handle_sync_thread();
        if let Err(e) = self.handle_write(info.offset as u8, data[0]) {
            error!("serial failed write: {}", e);
        }
    }
    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        if matches!(self.device_state, DeviceState::Sleep) {
            panic!("Unexpected action: Attempt to write to serial when device is in sleep mode");
        }
        if data.len() != 1 {
            return;
        }
        if self.input.is_some() {
            self.spawn_input_thread();
        }
        self.drain_in_channel();
        data[0] = match info.offset as u8 {
            DLAB_LOW if self.is_dlab_set() => self.baud_divisor as u8,
            DLAB_HIGH if self.is_dlab_set() => (self.baud_divisor >> 8) as u8,
            DATA => {
                self.del_intr_bit(IIR_RECV_BIT);
                if self.in_buffer.len() <= 1 {
                    self.line_status &= !LSR_DATA_BIT;
                }
                self.in_buffer.pop_front().unwrap_or_default()
            }
            IER => self.interrupt_enable.load(Ordering::SeqCst),
            IIR => {
                let v = self.interrupt_identification | IIR_FIFO_BITS;
                self.iir_reset();
                v
            }
            LCR => self.line_control,
            MCR => self.modem_control,
            LSR => self.line_status,
            MSR => {
                if self.is_loop() {
                    let mut msr =
                        self.modem_status & !(MSR_DSR_BIT | MSR_CTS_BIT | MSR_RI_BIT | MSR_DCD_BIT);
                    if self.modem_control & MCR_DTR_BIT != 0 {
                        msr |= MSR_DSR_BIT;
                    }
                    if self.modem_control & MCR_RTS_BIT != 0 {
                        msr |= MSR_CTS_BIT;
                    }
                    if self.modem_control & MCR_OUT1_BIT != 0 {
                        msr |= MSR_RI_BIT;
                    }
                    if self.modem_control & MCR_OUT2_BIT != 0 {
                        msr |= MSR_DCD_BIT;
                    }
                    msr
                } else {
                    self.modem_status
                }
            }
            SCR => self.scratch,
            _ => 0,
        };
    }
}
#[derive(Serialize, Deserialize)]
struct SerialSnapshot {
    interrupt_enable: u8,
    interrupt_identification: u8,
    line_control: u8,
    line_status: u8,
    modem_control: u8,
    modem_status: u8,
    scratch: u8,
    baud_divisor: u16,
    in_buffer: VecDeque<u8>,
    has_input: bool,
    has_output: bool,
    last_write_was_newline: bool,
}
impl Suspendable for Serial {
    fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
        self.spawn_input_thread();
        if let Some(worker) = self.worker.take() {
            self.input = Some(worker.stop());
        }
        self.drain_in_channel();
        let snap = SerialSnapshot {
            interrupt_enable: self.interrupt_enable.load(Ordering::SeqCst),
            interrupt_identification: self.interrupt_identification,
            line_control: self.line_control,
            line_status: self.line_status,
            modem_control: self.modem_control,
            modem_status: self.modem_status,
            scratch: self.scratch,
            baud_divisor: self.baud_divisor,
            in_buffer: self.in_buffer.clone(),
            has_input: self.input.is_some(),
            has_output: self.out.is_some(),
            last_write_was_newline: self.last_write_was_newline,
        };
        let serialized = AnySnapshot::to_any(snap).context("error serializing")?;
        Ok(serialized)
    }
    fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
        let serial_snapshot: SerialSnapshot =
            AnySnapshot::from_any(data).context("error deserializing")?;
        self.interrupt_enable = Arc::new(AtomicU8::new(serial_snapshot.interrupt_enable));
        self.interrupt_identification = serial_snapshot.interrupt_identification;
        self.line_control = serial_snapshot.line_control;
        self.line_status = serial_snapshot.line_status;
        self.modem_control = serial_snapshot.modem_control;
        self.modem_status = serial_snapshot.modem_status;
        self.scratch = serial_snapshot.scratch;
        self.baud_divisor = serial_snapshot.baud_divisor;
        self.in_buffer = serial_snapshot.in_buffer;
        if serial_snapshot.has_input && self.input.is_none() {
            warn!("Restore serial input missing when restore expected an input");
        }
        if serial_snapshot.has_output && self.out.is_none() {
            warn!("Restore serial out missing when restore expected an out");
        }
        self.last_write_was_newline = serial_snapshot.last_write_was_newline;
        Ok(())
    }
    fn sleep(&mut self) -> anyhow::Result<()> {
        if !matches!(self.device_state, DeviceState::Sleep) {
            self.device_state = DeviceState::Sleep;
            if let Some(worker) = self.worker.take() {
                self.input = Some(worker.stop());
            }
            self.drain_in_channel();
            self.in_channel = None;
        }
        Ok(())
    }
    fn wake(&mut self) -> anyhow::Result<()> {
        if !matches!(self.device_state, DeviceState::Awake) {
            self.device_state = DeviceState::Awake;
            if self.input.is_some() {
                self.spawn_input_thread();
            }
        }
        Ok(())
    }
}
#[cfg(test)]
mod tests {
    use std::io;
    use std::sync::Arc;
    use hypervisor::ProtectionType;
    use sync::Mutex;
    use super::*;
    use crate::serial_device::SerialOptions;
    use crate::suspendable_tests;
    pub use crate::sys::serial_device::SerialDevice;
    #[derive(Clone)]
    pub(super) struct SharedBuffer {
        pub(super) buf: Arc<Mutex<Vec<u8>>>,
    }
    impl Serial {
        pub fn clear_in_buffer(&mut self) {
            self.in_buffer.clear()
        }
    }
    impl SharedBuffer {
        pub(super) fn new() -> SharedBuffer {
            SharedBuffer {
                buf: Arc::new(Mutex::new(Vec::new())),
            }
        }
    }
    impl io::Write for SharedBuffer {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            self.buf.lock().write(buf)
        }
        fn flush(&mut self) -> io::Result<()> {
            self.buf.lock().flush()
        }
    }
    pub(super) fn serial_bus_address(offset: u8) -> BusAccessInfo {
        BusAccessInfo {
            offset: offset as u64,
            address: 0,
            id: 0,
        }
    }
    #[test]
    fn serial_output() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt,
            None,
            Some(Box::new(serial_out.clone())),
            None,
            Default::default(),
            Vec::new(),
        );
        serial.write(serial_bus_address(DATA), b"a");
        serial.write(serial_bus_address(DATA), b"b");
        serial.write(serial_bus_address(DATA), b"c");
        assert_eq!(serial_out.buf.lock().as_slice(), b"abc");
    }
    #[test]
    fn serial_input() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt.try_clone().unwrap(),
            None,
            Some(Box::new(serial_out)),
            None,
            Default::default(),
            Vec::new(),
        );
        serial.write(serial_bus_address(IER), &[IER_RECV_BIT]);
        serial.queue_input_bytes(b"abc").unwrap();
        assert_eq!(intr_evt.wait(), Ok(()));
        let mut data = [0u8; 1];
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'a');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'c');
    }
    #[test]
    fn serial_input_sleep_snapshot_restore_wake() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt.try_clone().unwrap(),
            None,
            Some(Box::new(serial_out)),
            None,
            Default::default(),
            Vec::new(),
        );
        serial.write(serial_bus_address(IER), &[IER_RECV_BIT]);
        serial.queue_input_bytes(b"abc").unwrap();
        assert_eq!(intr_evt.wait(), Ok(()));
        let mut data = [0u8; 1];
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'a');
        let sleep_res = serial.sleep();
        match sleep_res {
            Ok(_res) => (),
            Err(e) => println!("{}", e),
        }
        let snap_res = serial.snapshot();
        match snap_res {
            Ok(snap) => {
                let restore_res = serial.restore(snap);
                match restore_res {
                    Ok(_rest) => (),
                    Err(e) => println!("{}", e),
                }
            }
            Err(e) => println!("{}", e),
        }
        let wake_res = serial.wake();
        match wake_res {
            Ok(_res) => (),
            Err(e) => println!("{}", e),
        }
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'c');
    }
    #[test]
    fn serial_input_snapshot_restore() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt.try_clone().unwrap(),
            None,
            Some(Box::new(serial_out)),
            None,
            Default::default(),
            Vec::new(),
        );
        serial.write(serial_bus_address(IER), &[IER_RECV_BIT]);
        serial.queue_input_bytes(b"abc").unwrap();
        assert_eq!(intr_evt.wait(), Ok(()));
        let mut data = [0u8; 1];
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'a');
        let snap = serial.snapshot().expect("failed to snapshot serial");
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
        let restore_res = serial.restore(snap);
        match restore_res {
            Ok(()) => (),
            Err(e) => println!("Error: {}", e),
        }
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'c');
    }
    #[test]
    fn serial_input_snapshot_write_restore() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt.try_clone().unwrap(),
            None,
            Some(Box::new(serial_out)),
            None,
            Default::default(),
            Vec::new(),
        );
        serial.write(serial_bus_address(IER), &[IER_RECV_BIT]);
        serial.queue_input_bytes(b"abc").unwrap();
        assert_eq!(intr_evt.wait(), Ok(()));
        let mut data = [0u8; 1];
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'a');
        let snap = serial.snapshot().expect("failed to snapshot serial");
        serial.clear_in_buffer();
        serial.queue_input_bytes(b"abc").unwrap();
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'a');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'c');
        let restore_res = serial.restore(snap);
        match restore_res {
            Ok(()) => (),
            Err(e) => println!("Error: {}", e),
        }
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'c');
    }
    #[test]
    #[should_panic]
    fn serial_input_sleep_read_panic() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt.try_clone().unwrap(),
            None,
            Some(Box::new(serial_out)),
            None,
            Default::default(),
            Vec::new(),
        );
        serial.write(serial_bus_address(IER), &[IER_RECV_BIT]);
        serial.queue_input_bytes(b"abc").unwrap();
        assert_eq!(intr_evt.wait(), Ok(()));
        let mut data = [0u8; 1];
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'a');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
        let sleep_res = serial.sleep();
        match sleep_res {
            Ok(_res) => (),
            Err(e) => println!("{}", e),
        }
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
    }
    #[test]
    #[should_panic]
    fn serial_input_sleep_write_panic() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt.try_clone().unwrap(),
            None,
            Some(Box::new(serial_out)),
            None,
            Default::default(),
            Vec::new(),
        );
        let sleep_res = serial.sleep();
        match sleep_res {
            Ok(_res) => (),
            Err(e) => println!("{}", e),
        }
        serial.write(serial_bus_address(IER), &[IER_RECV_BIT]);
    }
    #[test]
    fn serial_input_sleep_wake() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt.try_clone().unwrap(),
            None,
            Some(Box::new(serial_out)),
            None,
            Default::default(),
            Vec::new(),
        );
        serial.write(serial_bus_address(IER), &[IER_RECV_BIT]);
        serial.queue_input_bytes(b"abc").unwrap();
        assert_eq!(intr_evt.wait(), Ok(()));
        let mut data = [0u8; 1];
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'a');
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'b');
        let sleep_res = serial.sleep();
        match sleep_res {
            Ok(_res) => (),
            Err(e) => println!("{}", e),
        }
        let wake_res = serial.wake();
        match wake_res {
            Ok(_res) => (),
            Err(e) => println!("{}", e),
        }
        serial.read(serial_bus_address(DATA), &mut data[..]);
        assert_eq!(data[0], b'c');
    }
    fn modify_device(serial: &mut Serial) {
        serial.clear_in_buffer();
        serial.queue_input_bytes(b"abc").unwrap();
    }
    suspendable_tests!(
        serial,
        Serial::new(
            ProtectionType::Unprotected,
            Event::new().unwrap(),
            None,
            Some(Box::new(SharedBuffer::new())),
            None,
            Default::default(),
            Vec::new(),
        ),
        modify_device
    );
    fn assert_timestamp_is_present(data: &[u8], serial_message: &str) {
        const TIMESTAMP_START: &str = "[";
        const TIMESTAMP_END: &str = "]: ";
        let data_str = std::str::from_utf8(data).unwrap();
        let timestamp_bracket = data_str
            .find(TIMESTAMP_END)
            .expect("missing timestamp end bracket");
        let (timestamp, message) = data_str.split_at(timestamp_bracket + TIMESTAMP_END.len());
        assert!(timestamp.starts_with(TIMESTAMP_START));
        assert!(timestamp.ends_with(TIMESTAMP_END));
        assert_eq!(message.trim_end(), serial_message);
    }
    #[test]
    fn serial_output_timestamp() {
        let intr_evt = Event::new().unwrap();
        let serial_out = SharedBuffer::new();
        let mut serial = Serial::new(
            ProtectionType::Unprotected,
            intr_evt,
            None,
            Some(Box::new(serial_out.clone())),
            None,
            SerialOptions {
                out_timestamp: true,
                ..Default::default()
            },
            Vec::new(),
        );
        serial.write(serial_bus_address(DATA), b"a");
        serial.write(serial_bus_address(DATA), b"\n");
        assert_timestamp_is_present(serial_out.buf.lock().as_slice(), "a");
        serial_out.buf.lock().clear();
        serial.write(serial_bus_address(DATA), b"b");
        serial.write(serial_bus_address(DATA), b"\n");
        assert_timestamp_is_present(serial_out.buf.lock().as_slice(), "b");
        serial_out.buf.lock().clear();
        serial.write(serial_bus_address(DATA), b"c");
        serial.write(serial_bus_address(DATA), b"\n");
        assert_timestamp_is_present(serial_out.buf.lock().as_slice(), "c");
        serial_out.buf.lock().clear();
    }
}