use core::any::Any;
use crate::hal::generic::callback::IsrCallback;
#[derive(Clone,Copy,PartialEq,Eq)]
pub enum SerialPortIdentity {
Usart0,
Usart1,
Usart2,
Usart3
}
pub enum BaudRate {
Baud300,
Baud600,
Baud1200,
Baud2400,
Baud4800,
Baud9600,
Baud14400,
Baud19200,
Baud28800,
Baud38400,
Baud57600,
Baud76800,
Baud115200,
Auto
}
pub enum SynchronousMode {
Master(BaudRate),
Slave
}
pub enum DataBits {
Bits5,
Bits6,
Bits7,
Bits8,
Bits9LE,
Bits9HE
}
pub enum Parity {
None,
Even,
Odd
}
pub enum StopBits {
Bits1,
Bits2
}
pub enum SerialPortMode {
Asynch(BaudRate,DataBits,Parity,StopBits),
Synch(SynchronousMode)
}
pub enum SerialError {
BufferOverflow,
FrameError,
ParityError,
AutoBaudDetectFail,
Break
}
#[derive(Copy,Clone,Debug)]
pub enum ReadHandlerResult<T> {
Buffer(T),
Discard
}
pub type SerialReadEventHandlerFunction = fn(SerialPortIdentity, u8, Option<*const dyn Any>) ->ReadHandlerResult<u8>;
pub type SerialReadEventCallback = IsrCallback<SerialReadEventHandlerFunction,ReadHandlerResult<u8>>;
pub type SerialErrorEventHandlerFunction = fn(SerialPortIdentity, SerialError, Option<*const dyn Any>) ->();
pub type SerialErrorEventCallback = IsrCallback<SerialErrorEventHandlerFunction,()>;
pub type SerialWriteEventHandlerFunction = fn(SerialPortIdentity, Option<*const dyn Any>) ->();
pub type SerialWriteEventCallback = IsrCallback<SerialWriteEventHandlerFunction,()>;
pub trait SerialRxTx {
fn mode(&mut self, mode:SerialPortMode) -> &mut Self;
fn enable_rxtx(&mut self, enable: bool) -> &mut Self;
fn set_write_complete_callback(&self, handler: SerialWriteEventCallback);
fn set_error_callback(&self, handler: SerialErrorEventCallback);
fn set_read_callback(&self, handler: SerialReadEventCallback);
fn write_u8(&mut self, byte: u8);
fn flush(&mut self);
fn read_u8(&mut self) -> u8;
fn try_read_u8(&mut self) -> Option<u8>;
}
pub(crate) trait SerialNoInterruptTx {
fn blocking_write_u8(&mut self, byte: u8);
fn blocking_write_slice(&mut self, bytes: &[u8]){
for byte in bytes {
self.blocking_write_u8(*byte);
}
}
}
#[allow(dead_code)]
impl BaudRate {
pub fn to_bps(&self) -> u32 {
match self {
BaudRate::Baud300 => 300,
BaudRate::Baud600 => 600,
BaudRate::Baud1200 => 1200,
BaudRate::Baud2400 => 2400,
BaudRate::Baud4800 => 4800,
BaudRate::Baud9600 => 9600,
BaudRate::Baud14400 => 14400,
BaudRate::Baud19200 => 19200,
BaudRate::Baud28800 => 28800,
BaudRate::Baud38400 => 38400,
BaudRate::Baud57600 => 57600,
BaudRate::Baud76800 => 76800,
BaudRate::Baud115200 => 115200,
BaudRate::Auto => 1
}
}
#[cfg(not(feature="32BitDiv"))]
pub(crate) fn baud_clock_table_index(&self) -> usize {
match self {
BaudRate::Baud300 => 1,
BaudRate::Baud600 => 2,
BaudRate::Baud1200 => 3,
BaudRate::Baud2400 => 4,
BaudRate::Baud4800 => 5,
BaudRate::Baud9600 => 6,
BaudRate::Baud14400 => 7,
BaudRate::Baud19200 => 8,
BaudRate::Baud28800 => 9,
BaudRate::Baud38400 => 10,
BaudRate::Baud57600 => 11,
BaudRate::Baud76800 => 12,
BaudRate::Baud115200 => 13,
BaudRate::Auto => 0
}
}
}
#[cfg(target_arch="avr")]
pub mod base {
pub mod usart {
use core::any::Any;
use core::cell::Cell;
use crate::{v_read, v_write};
use crate::hal::generic::serial::{SerialPortMode, SerialPortIdentity, SynchronousMode, BaudRate, Parity, StopBits, DataBits, SerialRxTx, ReadHandlerResult, SerialNoInterruptTx, SerialReadEventCallback, SerialWriteEventCallback, SerialErrorEventCallback};
use crate::deviceconsts::clock::{MASTER_CLOCK_HZ, MASTER_CLOCK_PRESCALER};
use core::marker::PhantomData;
use crate::private::ringq::RingQ;
#[repr(C)]
pub struct AtmelUsartControl {
pub(crate) rxdatal: u8,
pub(crate) rxdatah: u8,
pub(crate) txdatal: u8,
pub(crate) txdatah: u8,
pub(crate) status: u8,
pub(crate) ctrla: u8,
pub(crate) ctrlb: u8,
pub(crate) ctrlc: u8,
pub(crate) baud: u16,
pub(crate) ctrld: u8,
pub(crate) dbgctrl: u8,
pub(crate) evctrl: u8,
pub(crate) txplctrl: u8,
pub(crate) rxplctrl: u8
}
pub trait MuxControl {
fn route(&self);
}
pub struct AtmelUsart<M,const BUF_SIZE: usize>
where
M: MuxControl
{
pub(crate) control: &'static mut AtmelUsartControl,
pub(crate) read_handler: Cell<SerialReadEventCallback>,
pub(crate) write_complete_handler: Cell<SerialWriteEventCallback>,
pub(crate) error_handler: Cell<SerialErrorEventCallback>,
pub(crate) phantom: PhantomData<M>,
pub(crate) rx_buf: RingQ<u8,BUF_SIZE>,
pub(crate) tx_buf: RingQ<u8,BUF_SIZE>
}
#[inline(never)]
pub(crate) fn read_nop_handler(_src: SerialPortIdentity, byte: u8, _udata: Option<*const dyn Any>) -> ReadHandlerResult<u8> {
ReadHandlerResult::Buffer(byte)
}
impl<M,const BUF_SIZE:usize> AtmelUsart<M,BUF_SIZE>
where
M: MuxControl
{
pub fn mux(&mut self, mux: M) -> &mut Self {
mux.route();
self
}
#[inline(always)]
pub(crate) unsafe fn dre_int_enable(&mut self, enabled: bool) {
let ctrla = v_read!(u8, self.control.ctrla);
match enabled {
true => v_write!(u8, self.control.ctrla, ctrla | 0b00100000),
false => v_write!(u8, self.control.ctrla, ctrla & 0b11011111),
};
}
#[inline(always)]
pub(crate) unsafe fn isr_try_send_u8_from_buffer(&mut self) -> bool {
let byte = self.tx_buf.consume_nolock();
match byte {
Some(byte) => {
v_write!(u8, self.control.txdatah, 0x00);
v_write!(u8, self.control.txdatal, byte);
true
},
None => {
false
}
}
}
#[inline(always)]
pub(crate) unsafe fn isr_try_receive_u8_to_buffer(&mut self, byte: u8) -> bool {
self.rx_buf.append_nolock(byte).is_ok()
}
}
#[cfg(not(feature="32BitDiv"))]
const SER_ASYNCH_CLOCK_RATES: [u16; 14] = [
0,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 300u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 600u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 1200u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 2400u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 4800u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 9600u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 14400u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 19200u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 28800u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 38400u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 57600u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 76800u32)) + 1) as u16,
((((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) * 64u32) / (16u32 * 115200u32)) + 1) as u16,
];
#[cfg(not(feature="32BitDiv"))]
const SER_SYNCH_CLOCK_RATES: [u16; 14] = [
0,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 300u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 600u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 1200u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 2400u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 4800u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 9600u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 14400u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 19200u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 28800u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 38400u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 57600u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 76800u32)) + 1) as u16,
(((MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32) / (2u32 * 115200u32)) + 1) as u16,
];
impl SerialPortMode {
#[cfg(feature="32BitDiv")]
pub fn avr_baud_register_value(&self) -> u16 {
let integer_clk_per = MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32;
match self {
SerialPortMode::Asynch(baud, _, _, _) => {
let integer_baud_clock = (integer_clk_per * 64u32) / (16u32 * baud.to_bps() as u32)+1;
integer_baud_clock as u16
},
SerialPortMode::Synch(mode) => {
match mode {
SynchronousMode::Master(baud) => {
let integer_baud_clock = (integer_clk_per / (2u32 * baud.to_bps() as u32)) + 1;
(integer_baud_clock as u16) << 6
}
SynchronousMode::Slave => {
0
}
}
}
}
}
#[cfg(not(feature="32BitDiv"))]
pub fn avr_baud_register_value(&self) -> u16 {
match self {
SerialPortMode::Asynch(baud, _, _, _) => {
SER_ASYNCH_CLOCK_RATES[baud.baud_clock_table_index()]
},
SerialPortMode::Synch(mode) => {
match mode {
SynchronousMode::Master(baud) => {
SER_SYNCH_CLOCK_RATES[baud.baud_clock_table_index()] << 6
}
SynchronousMode::Slave => {
0
}
}
}
}
}
pub fn avr_ctrlb_rxmode(&self) -> u8 {
match self {
SerialPortMode::Asynch(baud, _, _, _) => {
match baud {
BaudRate::Auto => 0x02 << 1,
_ => 0x00
}
},
SerialPortMode::Synch(_) => 0x00
}
}
#[allow(clippy::unusual_byte_groupings)]
pub fn avr_ctrlc(&self) -> u8 {
match self {
SerialPortMode::Asynch(_baud, dbits, parity, sbits) => {
let mut ctrlc: u8 = 0b00_000000; ctrlc |= match parity {
Parity::None => 0b00_00_0000,
Parity::Even => 0b00_10_0000,
Parity::Odd => 0b00_11_0000
};
ctrlc |= match sbits {
StopBits::Bits1 => 0b0000_0_000,
StopBits::Bits2 => 0b0000_1_000
};
ctrlc |= match dbits {
DataBits::Bits5 => 0x00,
DataBits::Bits6 => 0x01,
DataBits::Bits7 => 0x02,
DataBits::Bits8 => 0x03,
DataBits::Bits9LE => 0x06,
DataBits::Bits9HE => 0x07
};
ctrlc
},
SerialPortMode::Synch(_) => {
let ctrlc: u8 = 0b01_000000; ctrlc
}
}
}
}
impl<M,const BUF_SIZE:usize> SerialRxTx for AtmelUsart<M,BUF_SIZE>
where
M: MuxControl
{
fn mode(&mut self, mode: SerialPortMode) -> &mut Self {
unsafe {
crate::hal::concurrency::interrupt::isolated(||{
v_write!(u8, self.control.ctrla, 0x00);
while (v_read!(u8, self.control.status) & 0b00100000) == 0 {
#![allow(deprecated)] llvm_asm!("nop" :::: "volatile" )
}
v_write!(u8, self.control.ctrlb, 0x00);
let _discard = v_read!(u8, self.control.rxdatah);
let _discard = v_read!(u8, self.control.rxdatal);
v_write!(u16, self.control.baud, mode.avr_baud_register_value());
v_write!(u8, self.control.ctrlc, mode.avr_ctrlc());
v_write!(u8, self.control.ctrld, 0b11000000);
v_write!(u8, self.control.ctrla, 0b11000000);
});
}
self
}
fn enable_rxtx(&mut self, enable: bool) -> &mut Self {
unsafe {
let ctrlb = v_read!(u8, self.control.ctrlb);
match enable {
true => v_write!(u8, self.control.ctrlb, 0b11000000 | ctrlb),
false => v_write!(u8, self.control.ctrlb, 0b00111111 & ctrlb),
}
}
self
}
fn set_write_complete_callback(&self, callback: SerialWriteEventCallback) {
crate::hal::concurrency::interrupt::isolated(||{
self.write_complete_handler.replace(callback);
});
}
fn set_read_callback(&self, callback: SerialReadEventCallback) {
crate::hal::concurrency::interrupt::isolated(||{
self.read_handler.replace(callback);
});
}
fn set_error_callback(&self, callback: SerialErrorEventCallback) {
crate::hal::concurrency::interrupt::isolated(||{
self.error_handler.replace(callback);
});
}
fn write_u8(&mut self, byte: u8) {
match self.tx_buf.append_nolock(byte) {
Ok(()) => {
}
Err(_e) => {
self.flush();
self.tx_buf.append_blocking_nolock(byte);
}
}
}
fn flush(&mut self) {
unsafe {
self.dre_int_enable(true);
}
}
fn read_u8(&mut self) -> u8 {
todo!()
}
fn try_read_u8(&mut self) -> Option<u8> {
todo!()
}
}
impl<M,const BUF_SIZE:usize> SerialNoInterruptTx for AtmelUsart<M,BUF_SIZE>
where
M: MuxControl
{
fn blocking_write_u8(&mut self, byte: u8) {
unsafe {
while (v_read!(u8, self.control.status) & 0b00100000) == 0 {
#![allow(deprecated)] llvm_asm!("nop" :::: "volatile" )
}
v_write!(u8, self.control.txdatah, 0);
v_write!(u8, self.control.txdatal, byte);
}
}
}
#[macro_export]
macro_rules! atmel_usart_tpl {
($usartref:expr, $srcref:expr, $muxtype:ty, $rxtxbufsize:expr, $isr_rx:ident, $isr_tx:ident, $isr_dre:ident) => {
use crate::hal::generic::serial::{SerialError, ReadHandlerResult,SerialReadEventCallback,SerialWriteEventCallback,SerialErrorEventCallback};
use crate::hal::generic::serial::base::usart::{ AtmelUsart, read_nop_handler };
use crate::{mut_singleton,v_read,isr_cb_invoke};
use crate::private::ringq::RingQ;
use core::marker::PhantomData;
use core::cell::Cell;
pub type SerialImpl = AtmelUsart<$muxtype,$rxtxbufsize>;
mut_singleton!(
AtmelUsart<$muxtype,$rxtxbufsize>,
INSTANCE,
instance,
AtmelUsart {
control: core::mem::transmute($usartref),
read_handler: Cell::new(SerialReadEventCallback::Function(read_nop_handler)),
write_complete_handler: Cell::new(SerialWriteEventCallback::Nop(())),
error_handler: Cell::new(SerialErrorEventCallback::Nop(())),
phantom: PhantomData::default(),
rx_buf: RingQ::new(),
tx_buf: RingQ::new()
});
#[no_mangle]
pub unsafe extern "avr-interrupt" fn $isr_rx() {
crate::hal::concurrency::interrupt::isr(||{
match &mut INSTANCE {
None => {},
Some(atmelusart) => {
let trigger = v_read!(u8, atmelusart.control.status);
if (trigger & 0b10000000) > 0 { let byte = v_read!(u8, atmelusart.control.rxdatal);
match isr_cb_invoke!(atmelusart.read_handler.get(), $srcref, byte) {
ReadHandlerResult::Buffer(byte) => {
if !atmelusart.isr_try_receive_u8_to_buffer(byte) {
isr_cb_invoke!(atmelusart.error_handler.get(), $srcref, SerialError::BufferOverflow);
}
},
ReadHandlerResult::Discard => {}
}
}
if (trigger & 0b00001000) > 0 { isr_cb_invoke!(atmelusart.error_handler.get(), $srcref, SerialError::AutoBaudDetectFail);
}
if (trigger & 0b00000010) > 0 { isr_cb_invoke!(atmelusart.error_handler.get(), $srcref, SerialError::Break);
}
core::ptr::write_volatile(&mut atmelusart.control.status as *mut u8,
0b00011010);
}
}
})
}
#[no_mangle]
pub unsafe extern "avr-interrupt" fn $isr_tx() {
crate::hal::concurrency::interrupt::isr(||{
})
}
#[no_mangle]
pub unsafe extern "avr-interrupt" fn $isr_dre() {
crate::hal::concurrency::interrupt::isr(||{
match &mut INSTANCE {
None => {},
Some(atmelusart) => {
match atmelusart.isr_try_send_u8_from_buffer() {
true => {
},
false => {
atmelusart.dre_int_enable(false);
isr_cb_invoke!(atmelusart.write_complete_handler.get(), $srcref);
}
}
}
}
})
}
}
}
}
}
#[cfg(not(target_arch="avr"))]
pub mod base {
pub mod usart {
use crate::hal::generic::serial::{SerialPortMode, SerialPortIdentity, BaudRate, Parity, StopBits, DataBits, SerialRxTx, SerialWriteEventCallback, SerialReadEventCallback, SerialError, ReadHandlerResult, SerialErrorEventCallback};
use core::marker::PhantomData;
use std::fmt::{Display, Formatter};
#[repr(C)]
pub struct DummyUsartControl {
}
pub trait MuxControl {
fn route(&self);
}
#[allow(dead_code)]
pub struct DummyUsart<M,const BUF_SIZE: usize>
where
M: MuxControl
{
pub(crate) control: DummyUsartControl,
pub(crate) phantom: Option<PhantomData<M>>
}
pub(crate) fn read_nop_handler(_src: SerialPortIdentity, byte: u8) -> ReadHandlerResult<u8> {
ReadHandlerResult::Buffer(byte)
}
pub(crate) fn write_nop_handler(_src: SerialPortIdentity) -> () {
}
pub(crate) fn error_nop_handler(_src: SerialPortIdentity, _error: SerialError) -> () {
}
impl<M,const BUF_SIZE:usize> DummyUsart<M,BUF_SIZE>
where
M: MuxControl
{
pub fn mux(&mut self, mux: M) -> &mut Self {
mux.route();
self
}
}
impl Display for SerialPortMode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SerialPortMode::Asynch(baud, dbits, parity, stopbits) => {
f.write_str(&format!("{} {}{}{}", baud, dbits, parity, stopbits))
}
SerialPortMode::Synch(_) => {
f.write_str("Synchronous")
}
}
}
}
impl Display for BaudRate {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
BaudRate::Baud300 => "300",
BaudRate::Baud600 => "600",
BaudRate::Baud1200 => "1200",
BaudRate::Baud2400 => "2400",
BaudRate::Baud4800 => "4800",
BaudRate::Baud9600 => "9600",
BaudRate::Baud14400 => "14400",
BaudRate::Baud19200 => "19200",
BaudRate::Baud28800 => "28800",
BaudRate::Baud38400 => "38400",
BaudRate::Baud57600 => "57600",
BaudRate::Baud76800 => "76800",
BaudRate::Baud115200 => "115200",
BaudRate::Auto => "Auto"
})
}
}
impl Display for DataBits {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
DataBits::Bits5 => "5",
DataBits::Bits6 => "6",
DataBits::Bits7 => "7",
DataBits::Bits8 => "8",
DataBits::Bits9LE => "9le",
DataBits::Bits9HE => "9he"
})
}
}
impl Display for Parity {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Parity::None => "N",
Parity::Even => "E",
Parity::Odd => "O"
})
}
}
impl Display for StopBits {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
StopBits::Bits1 => "1",
StopBits::Bits2 => "2"
})
}
}
impl<M,const BUF_SIZE:usize> SerialRxTx for DummyUsart<M,BUF_SIZE>
where
M: MuxControl
{
fn mode(&mut self, mode: SerialPortMode) -> &mut Self {
println!("*** USART: Set port mode to {}", mode);
self
}
fn enable_rxtx(&mut self, enable: bool) -> &mut Self {
println!("*** USART: Rx/Tx enable set to {}", enable);
self
}
fn set_write_complete_callback(&self, callback: SerialWriteEventCallback) {
println!("*** USART: Write callback set to {:?}", callback);
}
fn set_read_callback(&self, callback: SerialReadEventCallback) {
println!("*** USART: Write callback set to {:?}", callback);
}
fn set_error_callback(&self, callback: SerialErrorEventCallback) {
println!("*** USART: Write callback set to {:?}", callback);
}
fn write_u8(&mut self, byte: u8) {
println!("*** USART: Wrote '{}'", byte as char);
eprint!("{}", byte as char);
}
fn flush(&mut self) {
todo!()
}
fn read_u8(&mut self) -> u8 {
todo!()
}
fn try_read_u8(&mut self) -> Option<u8> {
todo!()
}
}
#[macro_export]
macro_rules! atmel_usart_tpl {
($usartref:expr, $srcref:expr, $muxtype:ty, $rxtxbufsize:expr, $isr_rx:ident, $isr_tx:ident, $isr_dre:ident) => {
use crate::hal::generic::serial::base::usart::{ DummyUsart, DummyUsartControl, read_nop_handler, write_nop_handler, error_nop_handler };
pub type SerialImpl = DummyUsart<$muxtype,$rxtxbufsize>;
static mut INSTANCE : DummyUsart<$muxtype,$rxtxbufsize> = DummyUsart {
control: DummyUsartControl {},
phantom: None
};
pub fn instance() -> &'static mut SerialImpl {
unsafe {
&mut INSTANCE
}
}
}
}
}
}