Conductor

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! y addr_of_mut! para llevar punteros a campos individuales sin crear una referencia intermedia. Sería una acción insegura.