1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
use super::*;
use std::collections::VecDeque;
use std::ptr::NonNull;
#[derive(Debug)]
pub struct Uart {
state: NonNull<UartState>,
irq_input: NonNull<ffi::avr_irq_t>,
}
impl Uart {
/// Initializes the subsystem; returns `None` if current AVR doesn't have
/// this UART.
///
/// # Safety
///
/// - Because this function registers an IRQ notification, the object
/// returned from here must be kept alive for at least as long as `avr`.
pub unsafe fn new(id: char, avr: &mut Avr) -> Option<Self> {
let mut flags: u32 = 0;
// First, let's make sure if the currently selected AVR supports this
// UART; if not, let's quickly bail out with `None`.
//
// (e.g. ATmega328P has only one UART and so initializing UART2 would
// fail there.)
//
// Safety: `IoCtl::UartGetFlags` requires a parameter of type `u32`
let status =
unsafe { avr.ioctl(IoCtl::UartGetFlags { id }, &mut flags) };
if status != 0 {
return None;
}
// Our AVR supports this UART, neat!
//
// Now let's detach it from the standard output so that simavr doesn't
// try to write there (this is especially important if someone's trying
// to send binary data through this UART, which otherwise would've
// gotten emitted into stdout as well).
flags &= !ffi::AVR_UART_FLAG_STDIO;
// Safety: `IoCtl::UartSetFlags` requires a parameter of type `u32`
unsafe {
avr.ioctl(IoCtl::UartSetFlags { id }, &mut flags);
}
// ----
// Now let's finalize everything by attaching to simavr's IRQs so that
// we can get notified when AVR sends something through this UART.
let ioctl = IoCtl::UartGetIrq { id };
let state = NonNull::from(Box::leak(Default::default()));
// Safety: All of callbacks match the expected IRQs
unsafe {
Avr::irq_register_notify(
avr.io_getirq(ioctl, ffi::UART_IRQ_OUTPUT),
Some(Self::on_output),
state.as_ptr(),
);
Avr::irq_register_notify(
avr.io_getirq(ioctl, ffi::UART_IRQ_OUT_XON),
Some(Self::on_xon),
state.as_ptr(),
);
Avr::irq_register_notify(
avr.io_getirq(ioctl, ffi::UART_IRQ_OUT_XOFF),
Some(Self::on_xoff),
state.as_ptr(),
);
}
let irq_input =
avr.io_getirq(IoCtl::UartGetIrq { id }, ffi::UART_IRQ_INPUT);
Some(Self { state, irq_input })
}
pub fn read(&mut self) -> Option<u8> {
// Safety: We're releasing the borrow right-away
unsafe { self.state_mut() }.rx.pop_front()
}
/// Schedules a byte to be sent during the nearest [`Self::flush()`].
pub fn write(&mut self, byte: u8) {
// Safety: We're releasing the borrow right-away
unsafe { self.state_mut() }.tx.push_back(byte);
}
pub fn flush(&mut self) {
loop {
let byte = {
// Safety: We're releasing the borrow before calling `.raise_irq()`
let state = unsafe { self.state_mut() };
if !state.xon {
break;
}
if let Some(byte) = state.tx.pop_front() {
byte
} else {
break;
}
};
unsafe {
ffi::avr_raise_irq(self.irq_input.as_ptr(), byte as u32);
}
}
}
/// # Safety
///
/// - UART interrupts are re-entrant, so the caller must make sure to
/// release the borrow before calling [`AvrManager::raise_irq()`].
unsafe fn state_mut(&mut self) -> &mut UartState {
unsafe { self.state.as_mut() }
}
unsafe extern "C" fn on_output(
_: NonNull<ffi::avr_irq_t>,
value: u32,
mut state: NonNull<UartState>,
) {
unsafe {
state.as_mut().rx.push_back(value as u8);
}
}
unsafe extern "C" fn on_xon(
_: NonNull<ffi::avr_irq_t>,
_: u32,
mut state: NonNull<UartState>,
) {
unsafe {
state.as_mut().xon = true;
}
}
unsafe extern "C" fn on_xoff(
_: NonNull<ffi::avr_irq_t>,
_: u32,
mut state: NonNull<UartState>,
) {
unsafe {
state.as_mut().xon = false;
}
}
}
impl Drop for Uart {
fn drop(&mut self) {
unsafe {
drop(Box::from_raw(self.state.as_ptr()));
}
}
}
#[derive(Debug)]
struct UartState {
/// Queue of bytes scheduled to be sent into AVR.
tx: VecDeque<u8>,
/// Queue of bytes retrieved from AVR, pending to be read by the simulator.
rx: VecDeque<u8>,
/// When true, AVR is ready to retrieve the next UART byte; AVR toggles this
/// value on and off as we flush the next bytes.
xon: bool,
}
impl Default for UartState {
fn default() -> Self {
Self {
tx: Default::default(),
rx: Default::default(),
xon: true,
}
}
}