#![allow(dead_code)]
#![allow(unused_unsafe)]
#[repr(u8)]
#[derive(Copy, Clone)]
pub enum Mode {
NormalAsynchronous,
DoubleSpeedAsynchronous,
MasterSynchronous,
}
pub struct USART0 {
_priv: (),
}
static mut USART0_TAKING: bool = false;
use crate::gpio;
use gpio::*;
impl USART0 {
const PRR: *mut u8 = 0x64 as *mut u8; const UBRR0H: *mut u8 = 0xC5 as *mut u8; const UBRR0L: *mut u8 = 0xC4 as *mut u8; const CPU_SPEED: u32 = 16000000; const UCSR0A: *mut u8 = 0xC0 as *mut u8; const UCSR0B: *mut u8 = 0xC1 as *mut u8; const UCSR0C: *mut u8 = 0xC2 as *mut u8; const UDR0: *mut u8 = 0xC6 as *mut u8;
pub fn take() -> Option<Self> {
unsafe {
if USART0_TAKING {
None
} else {
USART0_TAKING = true;
Some(USART0 { _priv: () })
}
}
}
pub fn start(&self) {
unsafe {
let val = core::ptr::read_volatile(Self::PRR);
core::ptr::write_volatile(Self::PRR, val & !(1 << 1 as u8));
}
}
pub fn set_baud_rate(&self, baud_rate: u32, mode: Mode) {
unsafe {
match mode {
Mode::NormalAsynchronous => {
let val = core::ptr::read_volatile(Self::UCSR0A);
let other_val = core::ptr::read_volatile(Self::UCSR0C);
core::ptr::write_volatile(Self::UCSR0A, val & !(1 << 1 as u8));
core::ptr::write_volatile(Self::UCSR0C, other_val & !(1 << 6 as u8) & !(1 << 7 as u8));
let ubrrn = ((Self::CPU_SPEED) / (16 * baud_rate)) - 1;
if ubrrn <= 4095 {
core::ptr::write_volatile(Self::UBRR0H, (ubrrn >> 8) as u8);
core::ptr::write_volatile(Self::UBRR0L, (ubrrn) as u8);
} else {
panic!();
}
}
Mode::DoubleSpeedAsynchronous => {
let val = core::ptr::read_volatile(Self::UCSR0A);
let other_val = core::ptr::read_volatile(Self::UCSR0C);
core::ptr::write_volatile(Self::UCSR0A, val | (1 << 1 as u8));
core::ptr::write_volatile(Self::UCSR0C, other_val & !(1 << 6 as u8) & !(1 << 7 as u8));
let ubrrn = ((Self::CPU_SPEED) / (8 * baud_rate)) - 1;
if ubrrn <= 4095 {
core::ptr::write_volatile(Self::UBRR0H, (ubrrn >> 8) as u8);
core::ptr::write_volatile(Self::UBRR0L, (ubrrn) as u8);
} else {
panic!();
}
}
Mode::MasterSynchronous => {
let xck = PortD::take().unwrap();
let val = core::ptr::read_volatile(Self::UCSR0C);
core::ptr::write_volatile(Self::UCSR0C, val & !(1 << 7 as u8) | (1 << 6 as u8) | (1 << 0 as u8));
xck.set_output(PinD::PD4);
let ubrrn = ((Self::CPU_SPEED) / (2 * baud_rate)) - 1;
if ubrrn <= 4095 {
core::ptr::write_volatile(Self::UBRR0H, (ubrrn >> 8) as u8);
core::ptr::write_volatile(Self::UBRR0L, (ubrrn) as u8);
} else {
panic!();
}
}
}
}
}
pub fn set_frame_format(&self) {
unsafe {
let val = core::ptr::read_volatile(Self::UCSR0B);
let other_val = core::ptr::read_volatile(Self::UCSR0C);
core::ptr::write_volatile(Self::UCSR0B, val & !(1 << 2 as u8));
core::ptr::write_volatile(Self::UCSR0C, other_val & !(1 << 3 as u8) & !(1 << 4 as u8) & !(1 << 5 as u8) | (1 << 1 as u8) | (1 << 2 as u8));
}
}
pub fn enable_tx_rx(&self) {
unsafe {
let val = core::ptr::read_volatile(Self::UCSR0B);
core::ptr::write_volatile(Self::UCSR0B, val | (1 << 3 as u8) | (1 << 4 as u8));
}
}
pub fn transmit_char(&self, character: char) {
unsafe {
while core::ptr::read_volatile(Self::UCSR0A) & (1 << 5 as u8) == 0 {
}
core::ptr::write_volatile(Self::UDR0, character as u8);
}
}
pub fn print_string(&self, string: &str) {
for val in string.as_bytes() {
self.transmit_char(*val as char);
}
}
pub fn send_u16_binary(&self, value: u16) {
unsafe {
let high = (value >> 8) as u8;
self.transmit_char(high as char);
let low = (value) as u8;
self.transmit_char(low as char);
}
}
pub fn print_num(&self, mut num: u16) {
let mut buff = [0u8; 5];
if num == 0 {
self.transmit_char('0');
return;
}
let mut i = 5;
while num > 0 {
i -= 1;
buff[i] = b'0' + (num % 10) as u8;
num /= 10;
}
if let Ok(s) = core::str::from_utf8(&buff[i..]) {
self.print_string(s);
}
}
pub fn usart_receive(&self) -> u8 {
unsafe {
let val = core::ptr::read_volatile(Self::UCSR0B);
core::ptr::write_volatile(Self::UCSR0B, val | (1 << 4 as u8));
while core::ptr::read_volatile(Self::UCSR0A) & (1 << 7 as u8) == 0 {
}
let contents = core::ptr::read_volatile(Self::UDR0);
contents
}
}
}