#![allow(clippy::not_unsafe_ptr_arg_deref)]
use bit_field::BitField;
use core::{arch::asm, ptr::read_volatile};
#[repr(C)]
pub struct UartControls {
pub txdata: u32,
pub rxdata: u32,
pub txctl: u32,
pub rxctl: u32,
pub ie: u32,
pub ip: u32,
pub div: u32,
phantom: (),
}
macro_rules! bit_write {
($( ( #[$outer:meta], $name:ident, $field:ident, $index:expr, $value:expr ) ),+) => {$(
#[inline]
#[$outer]
pub fn $name (uart: *mut UartControls) {
unsafe { (*uart).$field.set_bit($index, $value) };
}
)*}
}
macro_rules! bit_read {
($( ( #[$outer:meta], $name:ident, $field:ident, $index:expr ) ),+) => {$(
#[inline]
#[$outer]
pub fn $name (uart: *const UartControls) -> bool {
unsafe { read_volatile(&(*uart).$field) }.get_bit($index)
}
)*}
}
impl UartControls {
#[inline]
pub fn poll_read_byte(uart: *const UartControls) -> Option<u8> {
let x = unsafe { read_volatile(&(*uart).rxctl) };
if x.get_bit(31) {
Some(x as u8)
} else {
None
}
}
#[inline]
pub fn poll_write_byte(uart: *const UartControls, byte: u8) -> Option<()> {
let temp: usize = byte as usize;
let mut result: usize;
let address: *const u32 = unsafe { &(*uart).txdata };
unsafe {
asm!("amoor.w {0} {1} {2}",
lateout(reg) result,
in(reg) address,
in(reg) temp);
}
if result == 0 {
Some(())
} else {
None
}
}
#[inline]
pub fn set_baud_rate_divisor(uart: *mut UartControls, value: u16) {
unsafe {
(*uart).div.set_bits(0..16, value as u32);
}
}
bit_read!(
(
#[doc = "Returns true if there's a pending interrupt for the transmit queue length going below the watermark."],
transmit_interrupt_pending,
ip,
0
),
(
#[doc = "Returns true if there's a pending interrupt for the receive queue length going above the watermark."],
receive_interrupt_pending,
ip,
1
),
(
#[doc = "Returns true if interrupts are enabled for the transmit queue length going below the watermark."],
transmit_interrupt_enable,
txctl,
0
),
(
#[doc = "Returns true if interrupts are enabled for the receive queue length going above the watermark."],
receive_interrupt_enable,
rxctl,
0
),
(
#[doc = "Returns true if the transmit queue is full."],
transmit_queue_full,
txdata,
31
)
);
bit_write!(
(
#[doc = "Enable interrupts for the receive queue length going above the watermark."],
receive_enable_interrupts,
ip,
1,
true
),
(
#[doc = "Disable interrupts for the receive queue length going above the watermark."],
receive_disable_interrupts,
ip,
1,
false
),
(
#[doc = "Enable interrupts for the transmit queue length going below the watermark."],
transmit_enable_interrupts,
ip,
0,
true
),
(
#[doc = "Disable interrupts for the transmit queue length going below the watermark."],
transmit_disable_interrupts,
ip,
0,
false
),
(
#[doc = "Set to true for two stop bits, set to false for one stop bit."],
set_num_stop_bits,
txctl,
1,
false
),
(
#[doc = "Enable receiving data from this UART."],
receive_enable,
rxctl,
0,
true
),
(
#[doc = "Disable receiving data from this UART."],
receive_disable,
rxctl,
0,
false
),
(
#[doc = "Enable transmitting data from this UART."],
transmit_enable,
txctl,
0,
true
),
(
#[doc = "Disable transmitting data from this UART."],
transmit_disable,
txctl,
0,
false
)
);
}
pub const UART0: *mut UartControls = 0x10013000 as *mut UartControls;
pub const UART1: *mut UartControls = 0x10023000 as *mut UartControls;