1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
//! Driver for the pl011 UARTs in the QEMU implementation
//!
//! This crate provides basic drivers for the UARTS exposed by
//! QEMU. You can see the implementation of these uarts
//! [here](https://github.com/qemu/qemu/blob/master/hw/arm/stellaris.c)
//!
//! The QEMU target actually exposes 4 different UARTS, that can each
//! be redirected to arbitary character devices or files. This crate
//! allows those UARTS to be accessed in order to support more
//! complicated use cases than can be provided by
//! [cortex_m_semihosting](https://crates.io/crates/cortex-m-semihosting).

#![deny(missing_docs)]
#![no_std]
use core::fmt;
use core::marker::PhantomData;
use core::ops::Deref;
use cortex_m::interrupt;
use embedded_hal::serial;
use nb;
use volatile_register::{RO, RW, WO};

/// Struct representing PL011 registers. Not intended to be directly
/// used
#[repr(C)]
pub struct PL011_Regs {
    /// Data Register
    pub uartdr: RW<u32>,
    /// receive status / error clear
    pub uartrsr: RW<u32>,
    reserved0: [u32; 4],
    /// flag register
    pub uartfr: RO<u32>,
    reserved1: u32,
    /// IrDA Low power counter register
    pub uartilpr: RW<u32>,
    /// integer baud rate
    pub uartibrd: RW<u32>,
    /// fractional baud rate
    pub uartfbrd: RW<u32>,
    /// line control
    pub uartlcr_h: RW<u32>,
    /// control
    pub uartcr: RW<u32>,
    /// interrupt fifo level select
    pub uartifls: RW<u32>,
    /// interrupt mask set/clear
    pub uartimsc: RW<u32>,
    /// raw interrupt status
    pub uartris: RO<u32>,
    /// masked interrupt status
    pub uartmis: RO<u32>,
    /// interrupt clear
    pub uarticr: WO<u32>,
    /// dma control
    pub uartdmacr: RW<u32>,
    reserved2: [u32; 997],
    /// UART Periph ID0
    pub uartperiphid0: RO<u32>,
    /// UART Periph ID1
    pub uartperiphid1: RO<u32>,
    /// UART Periph ID2
    pub uartperiphid2: RO<u32>,
    /// UART Periph ID3
    pub uartperiphid3: RO<u32>,
    /// UART PCell ID0
    pub uartpcellid0: RO<u32>,
    /// UART PCell ID1
    pub uartpcellid1: RO<u32>,
    /// UART PCell ID2
    pub uartpcellid2: RO<u32>,
    /// UART PCell ID3
    pub uartpcellid3: RO<u32>,
}

/// Error type necessary for embedded_hal usage. No errors supported
pub struct Error;

/// Struct representing the actual driver.
///
/// Notice that there are no silly ideas like setting the baud rate,
/// or assigning GPIO pins to the driver: the qemu implementation
/// doesnt need any of that, we can just write to the registers
/// directly.
///
/// Implements embedded_hal::serial as well as core::fmt::Write
///
/// # Examples
///
/// ```
/// use pl011_qemu;
/// // build a driver for UART1
/// let mut uart = pl011_qemu::PL011::new(pl011_qemu::UART1::take().unwrap());
/// ```
pub struct PL011<UART> {
    /// owned copy of the underlying uart registers.
    ///
    ///Since they are moved into this struct, no one else can access them after the driver is initialized
    pub regs: UART,
    rx: Rx<UART>,
    tx: Tx<UART>,
}
/// Represents read half of UART.
pub struct Rx<UART> {
    _uart: PhantomData<UART>
}
/// Represents write half of UART
pub struct Tx<UART> {
    _uart: PhantomData<UART>
}



impl<T> Rx<T>
where
    T: detail::ConstRegBlockPtr<PL011_Regs>,
{
    /// reads a single byte out the uart
    ///
    /// spins until a byte is available in the fifo
    pub fn read_byte(&self) -> u8 {
        // loop while RXFE is set
        loop {
            // atomic read of register is side effect free
            let uartfr = unsafe { (*T::ptr()).uartfr.read() };
            if uartfr & 0x10 == 0 {
                break
            }
        }
        // read the data register. Atomic read is side effect free
        let data = unsafe {(*T::ptr()).uartdr.read() & 0xff};
        data as u8
    }    
}

impl<T> Tx<T>
where
    T: detail::ConstRegBlockPtr<PL011_Regs>,
{
    /// writes a single byte out the uart
    ///
    /// spins until space is available in the fifo
    pub fn write_byte(&self, data: u8) {
        loop {
            // atomic read of register is side effect free
            let uartfr = unsafe { (*T::ptr()).uartfr.read() };
            // if TXFF is not set
            if uartfr & 0x20 == 0 {
                break
            }
        }
        unsafe {(*T::ptr()).uartdr.write(data as u32)};
    }
}


impl<T> serial::Read<u8> for Rx<T>
    where
    T: detail::ConstRegBlockPtr<PL011_Regs>,
{
    type Error = Error;
    fn read(&mut self) -> nb::Result<u8, Self::Error> {
        // atomic read of register is side effect free
        let uartfr = unsafe { (*T::ptr()).uartfr.read() };
        // if RXFE is set (rx fifo is empty)
        if uartfr & 0x10 > 0 {
            Err(nb::Error::WouldBlock)
        } else {
            Ok(unsafe {(*T::ptr()).uartdr.read() & 0xff} as u8)
        }
    }
}

impl<T> serial::Write<u8> for Tx<T>
    where
    T: detail::ConstRegBlockPtr<PL011_Regs>,
{
    type Error = Error;
    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
        self.flush()?;
        unsafe {(*T::ptr()).uartdr.write(word as u32)};
        Ok(())
    }
    fn flush(&mut self) -> nb::Result<(), Self::Error> {
        // atomic read of register is side effect free
        let uartfr = unsafe { (*T::ptr()).uartfr.read() };
        // if TXFF is set (transmit fifo full)
        if uartfr & 0x20 > 0 {
            Err(nb::Error::WouldBlock)
        } else {
            Ok(())
        }
    }
}

impl<T> fmt::Write for Tx<T>
    where
    Tx<T>: serial::Write<u8>,
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        use embedded_hal::serial::Write;
        for b in s.as_bytes().iter() {
            if nb::block!(self.write(*b)).is_err() {
                return Err(fmt::Error);
            }
        }
        Ok(())
    }
}


impl<T> PL011<T>
    where
    T: detail::ConstRegBlockPtr<PL011_Regs>,
{
    /// Initialize a UART driver. Needs a UART struct to be passed in
    pub fn new(uart: T) -> Self {
        let pl011 = PL011 { regs: uart, tx: Tx{_uart:PhantomData}, rx: Rx{_uart:PhantomData} };
        pl011
    }
    /// splits a single PL011 uart object into separate Rx and Tx streams.
    ///
    /// Useful when you want to separate the two different halves of
    /// the UART and use them in different parts of the application
    ///
    /// Note that the Rx and Tx structs do not contain a reference to
    /// the underlying UART, this is because once you split the UART
    /// in half, it is no longer possible to interact with the uart
    /// hardware directly, since the other half (rx or tx) might be
    /// using it at the same time.
    pub fn split(self) -> (Tx<T>,Rx<T>) {
        (self.tx, self.rx)
    }
    /// writes a single byte out the uart
    ///
    /// spins until space is available in the fifo
    pub fn write_byte(&self, data: u8) {
        self.tx.write_byte(data);
    }
    /// reads a single byte out the uart
    ///
    /// spins until a byte is available in the fifo
    pub fn read_byte(&self) -> u8 {
        self.rx.read_byte()
    }
}

impl<T> fmt::Write for PL011<T>
    where
    Tx<T>: fmt::Write,
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.tx.write_str(s)
    }
}

impl<T> serial::Read<u8> for PL011<T>
    where
    Rx<T>: serial::Read<u8, Error=Error>,
{
    type Error = Error;
    fn read(&mut self) -> nb::Result<u8, Self::Error> {
        self.rx.read()
    }
}


impl<T> serial::Write<u8> for PL011<T>
    where
    Tx<T>: serial::Write<u8, Error=Error>,
{
    type Error = Error;
    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
        self.tx.write(word)
    }
    fn flush(&mut self) -> nb::Result<(), Self::Error> {
        self.tx.flush()
    }
}

macro_rules! create_uart {
    (
        $(#[$attr:meta])* struct $uart:ident,
        $global:ident,
        $addr:literal
    ) => {
        $(#[$attr])*
            pub struct $uart {
                _marker: PhantomData<*const ()>,
            }
        impl detail::ConstRegBlockPtr<PL011_Regs> for $uart {
            /// returns a pointer to the register block
            fn ptr() -> *const PL011_Regs {
                $addr as *const _
            }
        }
        unsafe impl Send for $uart {}
        impl Deref for $uart {
            type Target = PL011_Regs;
            #[inline(always)]
            fn deref(&self) -> &Self::Target {
                use crate::detail::ConstRegBlockPtr;
                unsafe {&* $uart::ptr()}
            }
        }
        static mut $global : bool = false;
        impl $uart {
            /// takes the UART HW
            ///
            /// Can only be taken once. If taken again returns None
            pub fn take() -> Option<Self> {
                    interrupt::free(|_| {
                        if unsafe {$global} {
                            None
                        } else {
                            Some(unsafe {$uart::steal()})
                        }
                    })
            }
            /// Unsafe function to steal hardware resources.
            ///
            /// Should not be needed if properly passing around the uart
            pub unsafe fn steal() -> Self {
                $global = true;
                $uart {_marker : PhantomData}
            }
        }
    }
}
create_uart!(
    /// Hardware Singleton for UART1 
    struct UART1,
    UART1_TAKEN, 0x4000_c000);
create_uart!(
    /// Hardware Singleton for UART2
    struct UART2,
    UART2_TAKEN, 0x4000_d000);
create_uart!(
    /// Hardware Singleton for UART3
    struct UART3,
    UART3_TAKEN, 0x4000_e000);
create_uart!(
    /// Hardware Singleton for UART4
    struct UART4,
    UART4_TAKEN, 0x4000_f000);

mod detail {
    /// Trait to indicate that the following type always points to a fixed hardware resource
    ///
    /// This trait is used since there is a uniqe type for each UART
    /// hardware component. If you have access to that type, you can
    /// access the registers of its underlying hardware through the
    /// type
    pub trait ConstRegBlockPtr<R> {
        /// returns a pointer to the fixed address of the underlying hardware resource  
        fn ptr() -> *const R where Self: Sized;
    }
}