use crate::atmega2560p::hal::interrupts;
use crate::atmega2560p::hal::port;
use crate::atmega2560p::hal::power;
use crate::delay::delay_ms;
use bit_field::BitField;
use core::ptr::write_volatile;
use core::{f64, u32, u8};
use volatile::Volatile;
const USART0_XCK: u8 = 2;
const USART1_XCK: u8 = 5;
const USART2_XCK: u8 = 2;
const USART3_XCK: u8 = 2;
const F_OSC: f64 = 1.0000;
const MULTIPLY: f64 = 1000000.00;
#[derive(Clone, Copy)]
pub enum UsartNum {
Usart0,
Usart1,
Usart2,
Usart3,
}
#[derive(Clone, Copy)]
pub enum UsartModes {
Normasync,
Douasync,
Mastersync,
Slavesync,
}
#[derive(Clone, Copy)]
pub enum UsartParity {
No,
Even,
Odd,
}
#[derive(Clone, Copy)]
pub enum UsartDataSize {
Five,
Six,
Seven,
Eight,
Nine,
}
#[derive(Clone, Copy)]
pub enum UsartStop {
One,
Two,
}
#[derive(Clone, Copy)]
pub enum UsartPolarity {
Outputrise,
Inputrise,
}
#[repr(C, packed)]
pub struct Usart {
pub ucsra: Volatile<u8>,
pub ucsrb: Volatile<u8>,
pub ucsrc: Volatile<u8>,
_pad: u8, pub ubrrl: Volatile<u8>,
pub ubrrh: Volatile<u8>,
pub udr: Volatile<u8>,
}
#[repr(C, packed)]
pub struct UsartObject {
pub usart: *mut Usart,
pub name: UsartNum,
}
impl Usart {
pub unsafe fn new(num: UsartNum) -> &'static mut Usart {
match num {
UsartNum::Usart0 => &mut *(0xC0 as *mut Usart),
UsartNum::Usart1 => &mut *(0xC8 as *mut Usart),
UsartNum::Usart2 => &mut *(0xD0 as *mut Usart),
UsartNum::Usart3 => &mut *(0x130 as *mut Usart),
}
}
pub fn name(&self) -> UsartNum {
let address = (self as *const Usart) as usize; match address {
0xC0 => UsartNum::Usart0,
0xC8 => UsartNum::Usart1,
0xD0 => UsartNum::Usart2,
0x130 => UsartNum::Usart3,
_ => unreachable!(),
}
}
pub fn create_object(&mut self) -> UsartObject {
UsartObject {
usart: self,
name: self.name(),
}
}
}
impl UsartObject {
pub unsafe fn new(num: UsartNum) -> UsartObject {
Usart::new(num).create_object()
}
}
impl UsartObject {
pub fn disable(&self) {
unsafe {
interrupts::Interrupt::disable(&mut interrupts::Interrupt::new());
}
}
pub fn enable(&self) {
unsafe {
interrupts::Interrupt::enable(&mut interrupts::Interrupt::new());
}
}
fn get_port_xck(&mut self) -> (&mut port::Port, u8) {
let num: UsartNum = unsafe { (*self.usart).name() };
match num {
UsartNum::Usart0 => (port::Port::new(port::PortName::E), USART0_XCK),
UsartNum::Usart1 => (port::Port::new(port::PortName::D), USART1_XCK),
UsartNum::Usart2 => (port::Port::new(port::PortName::H), USART2_XCK),
UsartNum::Usart3 => (port::Port::new(port::PortName::J), USART3_XCK),
}
}
fn get_mode(&mut self) -> bool {
let mut src = unsafe { (*self.usart).ucsrc.read() };
src = src & (1 << 6);
if src == 0 {
return false;
} else {
return true;
}
}
pub unsafe fn set_polarity(&mut self, mode: UsartPolarity) {
if self.get_mode() == false {
(*self.usart).ucsrc.update(|src| {
src.set_bit(0, false);
});
} else {
match mode {
UsartPolarity::Outputrise => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(0, false);
});
}
UsartPolarity::Inputrise => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(0, true);
});
}
}
}
}
pub unsafe fn mode_select(&mut self, mode: UsartModes) {
match mode {
UsartModes::Normasync | UsartModes::Douasync => {
(*self.usart).ucsrc.update( |src| {
src.set_bit(6,false);
src.set_bit(7,false);
});
},
UsartModes::Mastersync
| UsartModes::Slavesync => { (*self.usart).ucsrc.update( |src| {
src.set_bit(6,true);
src.set_bit(7,false);
});
(*self.usart).ucsra.update( |sra| {
sra.set_bit(1,false);
});
},
}
match mode {
UsartModes::Normasync => {
(*self.usart).ucsra.update(|sra| {
sra.set_bit(1, false);
});
}
UsartModes::Douasync => {
(*self.usart).ucsra.update(|sra| {
sra.set_bit(1, true);
});
}
UsartModes::Mastersync => {
let (port, xck) = self.get_port_xck();
write_volatile(&mut port.ddr, port.ddr | 1 << xck);
}
UsartModes::Slavesync => {
let (port, xck) = self.get_port_xck();
write_volatile(&mut port.ddr, port.ddr & !(1 << xck));
}
}
}
pub fn set_power(&mut self, num: UsartNum) {
let pow: &mut power::Power;
unsafe {
pow = power::Power::new();
}
match num {
UsartNum::Usart0 => {
unsafe {
write_volatile(&mut pow.prr0, pow.prr0 & !(1 << 1));
}
}
UsartNum::Usart1 => {
unsafe {
write_volatile(&mut pow.prr1, pow.prr1 & !(1));
}
}
UsartNum::Usart2 => {
unsafe {
write_volatile(&mut pow.prr1, pow.prr1 & !(1 << 1));
}
}
UsartNum::Usart3 => {
unsafe {
write_volatile(&mut pow.prr1, pow.prr1 & !(1 << 2));
}
}
}
}
unsafe fn _check(&mut self) {
(*self.usart).ucsrb.update(|srb| {
srb.set_bit(6, true);
srb.set_bit(7, true);
});
}
unsafe fn check_ongoing(&self) -> bool {
let ucsra = (*self.usart).ucsra.read();
if ucsra.get_bit(6) == false && ucsra.get_bit(7) == false {
true
} else {
false
}
}
pub unsafe fn set_txn(&mut self) {
(*self.usart).ucsra.update(|sra| {
sra.set_bit(6, true);
});
}
pub unsafe fn reset(&mut self) {
let sra: u8 = 0x00;
(*self.usart).ucsra.write(sra);
}
fn set_clock(&mut self, baud: i64, mode: UsartModes) {
let ubrr: u32;
match mode {
UsartModes::Normasync => {
ubrr = (((F_OSC * MULTIPLY) / (16.00 * baud as f64)) - 1.00) as u32;
}
UsartModes::Douasync => {
ubrr = (((F_OSC * MULTIPLY) / (8.00 * baud as f64)) - 1.00) as u32;
}
UsartModes::Mastersync => {
ubrr = (((F_OSC * MULTIPLY) / (2.00 * baud as f64)) - 1.00) as u32;
}
_ => unreachable!(),
}
unsafe {
(*self.usart).ubrrl.update(|ubrrl| {
for i in 0..8 {
ubrrl.set_bit(i, ubrr.get_bit(i));
}
});
(*self.usart).ubrrh.update(|ubrrh| {
for i in 0..4 {
ubrrh.set_bit(i, ubrr.get_bit(i + 8));
}
});
}
}
unsafe fn set_size(&mut self, size: UsartDataSize) {
match size {
UsartDataSize::Five
| UsartDataSize::Six
| UsartDataSize::Seven
| UsartDataSize::Eight => {
(*self.usart).ucsrb.update(|srb| {
srb.set_bit(2, false);
});
}
UsartDataSize::Nine => {
(*self.usart).ucsrb.update(|srb| {
srb.set_bit(2, true);
});
}
}
match size {
UsartDataSize::Five | UsartDataSize::Six => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(2, false);
});
}
UsartDataSize::Nine | UsartDataSize::Seven | UsartDataSize::Eight => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(2, true);
});
}
}
match size {
UsartDataSize::Five | UsartDataSize::Seven => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(1, false);
});
}
UsartDataSize::Nine | UsartDataSize::Six | UsartDataSize::Eight => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(1, true);
});
}
}
}
unsafe fn set_parity(&mut self, parity: UsartParity) {
match parity {
UsartParity::No => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(4, false);
src.set_bit(5, false);
});
}
UsartParity::Even => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(4, false);
src.set_bit(5, true);
});
}
UsartParity::Odd => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(4, true);
src.set_bit(5, true);
});
}
}
}
unsafe fn set_stop(&mut self, stop: UsartStop) {
match stop {
UsartStop::One => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(3, false);
});
}
UsartStop::Two => {
(*self.usart).ucsrc.update(|src| {
src.set_bit(3, true);
});
}
}
}
unsafe fn set_frame(&mut self, stop: UsartStop, size: UsartDataSize, parity: UsartParity) {
self.set_size(size);
self.set_parity(parity);
self.set_stop(stop);
}
pub unsafe fn initialize(
&mut self,
mode: UsartModes,
baud: i64,
stop: UsartStop,
size: UsartDataSize,
parity: UsartParity,
) {
let mut i: i32 = 100;
while self.check_ongoing() == false {
if i != 0 {
delay_ms(1000);
i = i - 1;
} else {
unreachable!()
}
}
let num: UsartNum = (*self.usart).name();
self.set_power(num); self.reset();
self.mode_select(mode);
match mode {
UsartModes::Slavesync => {}
UsartModes::Normasync | UsartModes::Douasync | UsartModes::Mastersync => {
self.set_clock(baud, mode);
}
}
self.set_frame(stop, size, parity);
}
}