Controlador
Ahora vamos a utilizar la nueva estructura de Registers en nuestro controlador.
/// Controlador para un UART PL011.
#[derive(Debug)]
pub struct Uart {
registers: *mut Registers,
}
impl Uart {
/// Construye una instancia nueva del controlador de UART para un dispositivo PL011 en la
/// dirección base proporcionada.
///
/// # Seguridad
///
/// La dirección base debe apuntar a los 8 registros de control MMIO de un
/// dispositivo PL011, que debe asignarse al espacio de direcciones del proceso
/// como memoria del dispositivo y no tener ningún otro alias.
pub unsafe fn new(base_address: *mut u32) -> Self {
Self { registers: base_address as *mut Registers }
}
/// Escribe un solo byte en el UART.
pub fn write_byte(&self, byte: u8) {
// Espera hasta que haya espacio en el búfer de TX.
while self.read_flag_register().contains(Flags::TXFF) {}
// SAFETY: We know that self.registers points to the control registers
// of a PL011 device which is appropriately mapped.
unsafe {
// Escribe en el búfer de TX.
addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
}
// Espera hasta que el UART esté libre.
while self.read_flag_register().contains(Flags::BUSY) {}
}
/// Lee y devuelve un byte pendiente o `None` si no se ha recibido nada
///.
pub fn read_byte(&self) -> Option<u8> {
if self.read_flag_register().contains(Flags::RXFE) {
None
} else {
// SAFETY: We know that self.registers points to the control
// registers of a PL011 device which is appropriately mapped.
let data = unsafe { addr_of!((*self.registers).dr).read_volatile() };
// TAREA: Comprueba si hay condiciones de error en los bits 8 a 11.
Some(data as u8)
}
}
fn read_flag_register(&self) -> Flags {
// SAFETY: We know that self.registers points to the control registers
// of a PL011 device which is appropriately mapped.
unsafe { addr_of!((*self.registers).fr).read_volatile() }
}
}
- Fíjate en el uso de
addr_of!yaddr_of_mut!para llevar punteros a campos individuales sin crear una referencia intermedia. Sería una acción insegura.