diff --git a/serial-settings/src/interface.rs b/serial-settings/src/interface.rs new file mode 100644 index 000000000..167833203 --- /dev/null +++ b/serial-settings/src/interface.rs @@ -0,0 +1,66 @@ +/// Wrapper type for a "best effort" serial interface. +/// +/// # Note +/// Overflows of the output are silently ignored. +pub struct BestEffortInterface(T); + +impl BestEffortInterface +where + T: embedded_io::Write + + embedded_io::WriteReady + + embedded_io::Read + + embedded_io::ReadReady, +{ + /// Construct an interface where overflows and errors when writing on the output are silently + /// ignored. + pub fn new(interface: T) -> Self { + Self(interface) + } + + /// Get access to the inner (wrapped) interface + pub fn inner(&self) -> &T { + &self.0 + } + + /// Get mutable access to the inner (wrapped) interface + pub fn inner_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl core::fmt::Write for BestEffortInterface +where + T: embedded_io::Write + embedded_io::WriteReady, +{ + fn write_str(&mut self, s: &str) -> core::fmt::Result { + if let Ok(true) = self.0.write_ready() { + self.0.write(s.as_bytes()).ok(); + } + Ok(()) + } +} + +impl embedded_io::ErrorType for BestEffortInterface +where + T: embedded_io::ErrorType, +{ + type Error = ::Error; +} + +impl embedded_io::Read for BestEffortInterface +where + T: embedded_io::Read, +{ + fn read(&mut self, buf: &mut [u8]) -> Result { + self.0.read(buf) + } +} + +impl embedded_io::ReadReady for BestEffortInterface +where + T: embedded_io::ReadReady, +{ + fn read_ready(&mut self) -> Result { + self.0.read_ready() + } +} diff --git a/serial-settings/src/lib.rs b/serial-settings/src/lib.rs index 7039a4c61..cb188feaf 100644 --- a/serial-settings/src/lib.rs +++ b/serial-settings/src/lib.rs @@ -49,9 +49,13 @@ #![no_std] use core::fmt::Write; -use embedded_io::{Read, ReadReady, Write as EioWrite, WriteReady}; +use embedded_io::{Read, ReadReady}; use miniconf::{JsonCoreSlash, TreeKey}; +mod interface; + +pub use interface::BestEffortInterface; + /// Specifies the API required for objects that are used as settings with the serial terminal /// interface. pub trait Settings: for<'a> JsonCoreSlash<'a> + Clone { @@ -63,8 +67,7 @@ pub trait Platform: Sized { /// This type specifies the interface to the user, for example, a USB CDC-ACM serial port. type Interface: embedded_io::Read + embedded_io::ReadReady - + embedded_io::Write - + embedded_io::WriteReady; + + core::fmt::Write; /// Specifies the settings that are used on the device. type Settings: Settings; @@ -128,7 +131,7 @@ impl<'a, P: Platform> Context<'a, P> { continue; } Ok(len) => write!( - Writer(&mut context.platform.interface_mut()), + &mut context.platform.interface_mut(), "{path}: {}", core::str::from_utf8(&context.buffer[..len]) .unwrap() @@ -142,7 +145,7 @@ impl<'a, P: Platform> Context<'a, P> { "[default serialization error: {e}]" ), Ok(len) => writeln!( - Writer(&mut context.platform.interface_mut()), + &mut context.platform.interface_mut(), " [default: {}]", core::str::from_utf8(&context.buffer[..len]) .unwrap() @@ -185,7 +188,7 @@ impl<'a, P: Platform> Context<'a, P> { } Ok(len) => { writeln!( - Writer(&mut context.platform.interface_mut()), + &mut context.platform.interface_mut(), "{key}: {}", core::str::from_utf8(&context.buffer[..len]).unwrap() ) @@ -295,26 +298,8 @@ impl<'a, P: Platform> Context<'a, P> { } impl<'a, P: Platform> core::fmt::Write for Context<'a, P> { - /// Write data to the serial terminal. - /// - /// # Note - /// The terminal uses an internal buffer. Overflows of the output buffer are silently ignored. - fn write_str(&mut self, s: &str) -> core::fmt::Result { - let mut writer = Writer(self.platform.interface_mut()); - writer.write_str(s) - } -} - -struct Writer<'a, T: WriteReady + EioWrite>(&'a mut T); - -impl<'a, T: embedded_io::WriteReady + embedded_io::Write> core::fmt::Write - for Writer<'a, T> -{ fn write_str(&mut self, s: &str) -> core::fmt::Result { - if let Ok(true) = self.0.write_ready() { - self.0.write(s.as_bytes()).ok(); - } - Ok(()) + self.platform.interface_mut().write_str(s) } } diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index bdd44215d..92a973f82 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -471,7 +471,7 @@ mod app { fn usb(mut c: usb::Context) { // Handle the USB serial terminal. c.shared.usb.lock(|usb| { - usb.poll(&mut [c.local.usb_terminal.interface_mut()]); + usb.poll(&mut [c.local.usb_terminal.interface_mut().inner_mut()]); }); c.local.usb_terminal.process().unwrap(); diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs index d052d8936..7959c5af9 100644 --- a/src/bin/lockin.rs +++ b/src/bin/lockin.rs @@ -522,7 +522,7 @@ mod app { fn usb(mut c: usb::Context) { // Handle the USB serial terminal. c.shared.usb.lock(|usb| { - usb.poll(&mut [c.local.usb_terminal.interface_mut()]); + usb.poll(&mut [c.local.usb_terminal.interface_mut().inner_mut()]); }); c.local.usb_terminal.process().unwrap(); diff --git a/src/hardware/flash.rs b/src/hardware/flash.rs index c780c7250..0e69b312f 100644 --- a/src/hardware/flash.rs +++ b/src/hardware/flash.rs @@ -1,7 +1,6 @@ use core::fmt::Write; use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use stm32h7xx_hal::flash::LockedFlashBank; -use usbd_serial::embedded_io::Write as EioWrite; #[derive(Clone, serde::Serialize, serde::Deserialize, miniconf::Tree)] pub struct Settings { @@ -96,7 +95,9 @@ impl From for Error { pub struct SerialSettingsPlatform { /// The interface to read/write data to/from serially (via text) to the user. - pub interface: usbd_serial::SerialPort<'static, super::UsbBus>, + pub interface: serial_settings::BestEffortInterface< + usbd_serial::SerialPort<'static, super::UsbBus>, + >, /// The Settings structure. pub settings: Settings, /// The storage mechanism used to persist settings to between boots. @@ -104,7 +105,9 @@ pub struct SerialSettingsPlatform { } impl serial_settings::Platform for SerialSettingsPlatform { - type Interface = usbd_serial::SerialPort<'static, super::UsbBus>; + type Interface = serial_settings::BestEffortInterface< + usbd_serial::SerialPort<'static, super::UsbBus>, + >; type Settings = Settings; type Error = Error<::Error>; diff --git a/src/hardware/setup.rs b/src/hardware/setup.rs index 5b0147eec..72b09a4b9 100644 --- a/src/hardware/setup.rs +++ b/src/hardware/setup.rs @@ -1088,7 +1088,9 @@ pub fn setup( serial_settings::Runner::new( super::flash::SerialSettingsPlatform { - interface: usb_serial, + interface: serial_settings::BestEffortInterface::new( + usb_serial, + ), storage, settings, },