Browse Source

Deduplicate USART driver code

Vadim Kaushan 4 years ago
parent
commit
3b9e709080
1 changed files with 73 additions and 83 deletions
  1. 73 83
      src/serial.rs

+ 73 - 83
src/serial.rs

@@ -40,6 +40,7 @@
 use core::marker::PhantomData;
 use core::ptr;
 use core::sync::atomic::{self, Ordering};
+use core::ops::Deref;
 
 use nb;
 use crate::pac::{USART1, USART2, USART3};
@@ -115,14 +116,73 @@ impl Pins<USART3> for (PD8<Alternate<PushPull>>, PD9<Input<Floating>>) {
 }
 
 /// Internal trait for the serial read / write logic.
-///
-/// Note that reading / writing is done on the USART peripheral, not on the
-/// rx / tx pins!
-trait UsartReadWrite {
-    fn read() -> nb::Result<u8, Error>;
-    fn write(byte: u8) -> nb::Result<(), Infallible>;
-    fn flush() -> nb::Result<(), Infallible>;
+trait UsartReadWrite: Deref<Target=crate::stm32::usart1::RegisterBlock> {
+    fn read(&self) -> nb::Result<u8, Error> {
+        let sr = self.sr.read();
+
+        // Check for any errors
+        let err = if sr.pe().bit_is_set() {
+            Some(Error::Parity)
+        } else if sr.fe().bit_is_set() {
+            Some(Error::Framing)
+        } else if sr.ne().bit_is_set() {
+            Some(Error::Noise)
+        } else if sr.ore().bit_is_set() {
+            Some(Error::Overrun)
+        } else {
+            None
+        };
+
+        if let Some(err) = err {
+            // Some error occured. In order to clear that error flag, you have to
+            // do a read from the sr register followed by a read from the dr
+            // register
+            // NOTE(read_volatile) see `write_volatile` below
+            unsafe {
+                ptr::read_volatile(&self.sr as *const _ as *const _);
+                ptr::read_volatile(&self.dr as *const _ as *const _);
+            }
+            Err(nb::Error::Other(err))
+        } else {
+            // Check if a byte is available
+            if sr.rxne().bit_is_set() {
+                // Read the received byte
+                // NOTE(read_volatile) see `write_volatile` below
+                Ok(unsafe {
+                    ptr::read_volatile(&self.dr as *const _ as *const _)
+                })
+            } else {
+                Err(nb::Error::WouldBlock)
+            }
+        }
+    }
+
+    fn write(&self, byte: u8) -> nb::Result<(), Infallible> {
+        let sr = self.sr.read();
+
+        if sr.txe().bit_is_set() {
+            // NOTE(unsafe) atomic write to stateless register
+            // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
+            unsafe {
+                ptr::write_volatile(&self.dr as *const _ as *mut _, byte)
+            }
+            Ok(())
+        } else {
+            Err(nb::Error::WouldBlock)
+        }
+    }
+
+    fn flush(&self) -> nb::Result<(), Infallible> {
+        let sr = self.sr.read();
+
+        if sr.tc().bit_is_set() {
+            Ok(())
+        } else {
+            Err(nb::Error::WouldBlock)
+        }
+    }
 }
+impl UsartReadWrite for &crate::stm32::usart1::RegisterBlock {}
 
 pub enum Parity {
     ParityNone,
@@ -357,81 +417,11 @@ macro_rules! hal {
                 }
             }
 
-            impl UsartReadWrite for $USARTX {
-                fn read() -> nb::Result<u8, Error> {
-                    // NOTE(unsafe) atomic read with no side effects
-                    let sr = unsafe { (*$USARTX::ptr()).sr.read() };
-
-                    // Check for any errors
-                    let err = if sr.pe().bit_is_set() {
-                        Some(Error::Parity)
-                    } else if sr.fe().bit_is_set() {
-                        Some(Error::Framing)
-                    } else if sr.ne().bit_is_set() {
-                        Some(Error::Noise)
-                    } else if sr.ore().bit_is_set() {
-                        Some(Error::Overrun)
-                    } else {
-                        None
-                    };
-
-                    if let Some(err) = err {
-                        // Some error occured. In order to clear that error flag, you have to
-                        // do a read from the sr register followed by a read from the dr
-                        // register
-                        // NOTE(read_volatile) see `write_volatile` below
-                        unsafe {
-                            ptr::read_volatile(&(*$USARTX::ptr()).sr as *const _ as *const _);
-                            ptr::read_volatile(&(*$USARTX::ptr()).dr as *const _ as *const _);
-                        }
-                        Err(nb::Error::Other(err))
-                    } else {
-                        // Check if a byte is available
-                        if sr.rxne().bit_is_set() {
-                            // Read the received byte
-                            // NOTE(read_volatile) see `write_volatile` below
-                            Ok(unsafe {
-                                ptr::read_volatile(&(*$USARTX::ptr()).dr as *const _ as *const _)
-                            })
-                        } else {
-                            Err(nb::Error::WouldBlock)
-                        }
-                    }
-                }
-
-                fn write(byte: u8) -> nb::Result<(), Infallible> {
-                    // NOTE(unsafe) atomic read with no side effects
-                    let sr = unsafe { (*$USARTX::ptr()).sr.read() };
-
-                    if sr.txe().bit_is_set() {
-                        // NOTE(unsafe) atomic write to stateless register
-                        // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
-                        unsafe {
-                            ptr::write_volatile(&(*$USARTX::ptr()).dr as *const _ as *mut _, byte)
-                        }
-                        Ok(())
-                    } else {
-                        Err(nb::Error::WouldBlock)
-                    }
-                }
-
-                fn flush() -> nb::Result<(), Infallible> {
-                    // NOTE(unsafe) atomic read with no side effects
-                    let sr = unsafe { (*$USARTX::ptr()).sr.read() };
-
-                    if sr.tc().bit_is_set() {
-                        Ok(())
-                    } else {
-                        Err(nb::Error::WouldBlock)
-                    }
-                }
-            }
-
             impl crate::hal::serial::Read<u8> for Rx<$USARTX> {
                 type Error = Error;
 
                 fn read(&mut self) -> nb::Result<u8, Error> {
-                    $USARTX::read()
+                    unsafe { &*$USARTX::ptr() }.read()
                 }
             }
 
@@ -439,10 +429,10 @@ macro_rules! hal {
                 type Error = Infallible;
 
                 fn flush(&mut self) -> nb::Result<(), Self::Error> {
-                    $USARTX::flush()
+                    unsafe { &*$USARTX::ptr() }.flush()
                 }
                 fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
-                    $USARTX::write(byte)
+                    unsafe { &*$USARTX::ptr() }.write(byte)
                 }
             }
 
@@ -450,7 +440,7 @@ macro_rules! hal {
                 type Error = Error;
 
                 fn read(&mut self) -> nb::Result<u8, Error> {
-                    $USARTX::read()
+                    self.usart.deref().read()
                 }
             }
 
@@ -458,11 +448,11 @@ macro_rules! hal {
                 type Error = Infallible;
 
                 fn flush(&mut self) -> nb::Result<(), Self::Error> {
-                    $USARTX::flush()
+                    self.usart.deref().flush()
                 }
 
                 fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
-                    $USARTX::write(byte)
+                    self.usart.deref().write(byte)
                 }
             }