|
4 | 4 | #![allow(dead_code)]
|
5 | 5 | #![allow(unused_variables)]
|
6 | 6 |
|
7 |
| -use arraydeque::ArrayDeque; |
8 |
| - |
9 | 7 | use crate::raw;
|
10 | 8 | use crate::error::{Error, Result, to_result_void, to_result};
|
11 | 9 | use crate::printkln;
|
12 |
| -use crate::sys::sync::Semaphore; |
13 |
| -use crate::sync::{Arc, SpinMutex}; |
14 |
| -use crate::time::{NoWait, Timeout}; |
15 | 10 |
|
16 | 11 | use core::ffi::{c_int, c_uchar, c_void};
|
17 | 12 | use core::ptr;
|
18 | 13 |
|
19 | 14 | use super::Unique;
|
20 | 15 |
|
| 16 | +mod irq; |
| 17 | +pub use irq::UartIrq; |
| 18 | + |
21 | 19 | /// A wrapper around a UART device on Zephyr.
|
22 | 20 | pub struct Uart {
|
23 | 21 | /// The underlying device itself.
|
@@ -162,243 +160,3 @@ extern "C" fn async_callback(
|
162 | 160 | ) {
|
163 | 161 | printkln!("Async");
|
164 | 162 | }
|
165 |
| - |
166 |
| -/// Size of the irq buffer used for UartIrq. |
167 |
| -/// |
168 |
| -/// TODO: Make this a parameter of the type. |
169 |
| -const BUFFER_SIZE: usize = 256; |
170 |
| - |
171 |
| -/// The "outer" struct holds the semaphore, and the mutex. The semaphore has to live outside of the |
172 |
| -/// mutex because it can only be waited on when the Mutex is not locked. |
173 |
| -struct IrqOuterData { |
174 |
| - read_sem: Semaphore, |
175 |
| - write_sem: Semaphore, |
176 |
| - inner: SpinMutex<IrqInnerData>, |
177 |
| -} |
178 |
| - |
179 |
| -/// Data for communication with the UART IRQ. |
180 |
| -struct IrqInnerData { |
181 |
| - /// The Ring buffer holding incoming and read data. |
182 |
| - buffer: ArrayDeque<u8, BUFFER_SIZE>, |
183 |
| - /// Data to be written, if that is the case. |
184 |
| - /// |
185 |
| - /// If this is Some, then the irq should be enabled. |
186 |
| - write: Option<WriteSlice>, |
187 |
| -} |
188 |
| - |
189 |
| -/// Represents a slice of data that the irq is going to write. |
190 |
| -struct WriteSlice { |
191 |
| - data: *const u8, |
192 |
| - len: usize, |
193 |
| -} |
194 |
| - |
195 |
| -impl WriteSlice { |
196 |
| - /// Add an offset to the beginning of this slice, returning a new slice. This is equivalent to |
197 |
| - /// &item[count..] with a slice. |
198 |
| - pub unsafe fn add(&self, count: usize) -> WriteSlice { |
199 |
| - WriteSlice { |
200 |
| - data: unsafe { self.data.add(count) }, |
201 |
| - len: self.len - count, |
202 |
| - } |
203 |
| - } |
204 |
| -} |
205 |
| - |
206 |
| -/// This is the irq-driven interface. |
207 |
| -pub struct UartIrq { |
208 |
| - /// Interior wrapped device, to be able to hand out lifetime managed references to it. |
209 |
| - uart: Uart, |
210 |
| - /// Critical section protected data. |
211 |
| - data: Arc<IrqOuterData>, |
212 |
| -} |
213 |
| - |
214 |
| -// UartIrq is also Send, !Sync, for the same reasons as for Uart. |
215 |
| -unsafe impl Send for UartIrq {} |
216 |
| - |
217 |
| -impl UartIrq { |
218 |
| - /// Convert uart into irq driven one. |
219 |
| - pub unsafe fn new(uart: Uart) -> Result<UartIrq> { |
220 |
| - let data = Arc::new(IrqOuterData { |
221 |
| - read_sem: Semaphore::new(0, 1)?, |
222 |
| - write_sem: Semaphore::new(0, 1)?, |
223 |
| - inner: SpinMutex::new(IrqInnerData { |
224 |
| - buffer: ArrayDeque::new(), |
225 |
| - write: None, |
226 |
| - }), |
227 |
| - }); |
228 |
| - |
229 |
| - // Clone the arc, and convert to a raw pointer, to give to the callback. |
230 |
| - // This will leak the Arc (which prevents deallocation). |
231 |
| - let data_raw = Arc::into_raw(data.clone()); |
232 |
| - let data_raw = data_raw as *mut c_void; |
233 |
| - |
234 |
| - let ret = unsafe { |
235 |
| - raw::uart_irq_callback_user_data_set(uart.device, Some(irq_callback), data_raw) |
236 |
| - }; |
237 |
| - to_result_void(ret)?; |
238 |
| - // Should this be settable? |
239 |
| - unsafe { |
240 |
| - // raw::uart_irq_tx_enable(uart.device); |
241 |
| - raw::uart_irq_rx_enable(uart.device); |
242 |
| - } |
243 |
| - Ok(UartIrq { |
244 |
| - data, |
245 |
| - uart, |
246 |
| - }) |
247 |
| - } |
248 |
| - |
249 |
| - /// Get the underlying UART to be able to change line control and such. |
250 |
| - /// |
251 |
| - /// TODO: This really should return something like `&Uart` to bind the lifetime. Otherwise the |
252 |
| - /// user can continue to use the uart handle beyond the lifetime of the driver. |
253 |
| - pub unsafe fn inner(&mut self) -> &Uart { |
254 |
| - &self.uart |
255 |
| - } |
256 |
| - |
257 |
| - /// Attempt to read data from the UART into the buffer. If no data is available, it will |
258 |
| - /// attempt, once, to wait using the given timeout. |
259 |
| - /// |
260 |
| - /// Returns the number of bytes that were read, with zero indicating that a timeout occurred. |
261 |
| - pub unsafe fn try_read<T>(&mut self, buf: &mut [u8], timeout: T) -> usize |
262 |
| - where T: Into<Timeout>, |
263 |
| - { |
264 |
| - // Start with a read, before any blocking. |
265 |
| - let count = self.data.try_read(buf); |
266 |
| - if count > 0 { |
267 |
| - return count; |
268 |
| - } |
269 |
| - |
270 |
| - // Otherwise, wait for the semaphore. Ignore the result, as we will try to read again, in |
271 |
| - // case there was a race. |
272 |
| - let _ = self.data.read_sem.take(timeout); |
273 |
| - |
274 |
| - self.data.try_read(buf) |
275 |
| - } |
276 |
| - |
277 |
| - /// A blocking write to the UART. |
278 |
| - /// |
279 |
| - /// By making this blocking, we don't need to make an extra copy of the data. |
280 |
| - /// |
281 |
| - /// TODO: Async write. |
282 |
| - pub unsafe fn write<T>(&mut self, buf: &[u8], timeout: T) -> usize |
283 |
| - where T: Into<Timeout> |
284 |
| - { |
285 |
| - if buf.len() == 0 { |
286 |
| - return 0; |
287 |
| - } |
288 |
| - |
289 |
| - // Make the data to be written available to the irq handler, and get it going. |
290 |
| - { |
291 |
| - let mut inner = self.data.inner.lock().unwrap(); |
292 |
| - assert!(inner.write.is_none()); |
293 |
| - |
294 |
| - inner.write = Some(WriteSlice { |
295 |
| - data: buf.as_ptr(), |
296 |
| - len: buf.len(), |
297 |
| - }); |
298 |
| - |
299 |
| - unsafe { raw::uart_irq_tx_enable(self.uart.device) }; |
300 |
| - } |
301 |
| - |
302 |
| - // Wait for the transmission to complete. This shouldn't be racy, as the irq shouldn't be |
303 |
| - // giving the semaphore until there is 'write' data, and it has been consumed. |
304 |
| - let _ = self.data.write_sem.take(timeout); |
305 |
| - |
306 |
| - // Depending on the driver, there might be a race here. This would result in the above |
307 |
| - // 'take' returning early, and no actual data being written. |
308 |
| - |
309 |
| - { |
310 |
| - let mut inner = self.data.inner.lock().unwrap(); |
311 |
| - |
312 |
| - if let Some(write) = inner.write.take() { |
313 |
| - // First, make sure that no more interrupts will come in. |
314 |
| - unsafe { raw::uart_irq_tx_disable(self.uart.device) }; |
315 |
| - |
316 |
| - // The write did not complete, and this represents remaining data to write. |
317 |
| - buf.len() - write.len |
318 |
| - } else { |
319 |
| - // The write completed, the rx irq should be disabled. Just return the whole |
320 |
| - // buffer. |
321 |
| - buf.len() |
322 |
| - } |
323 |
| - } |
324 |
| - } |
325 |
| -} |
326 |
| - |
327 |
| -impl IrqOuterData { |
328 |
| - /// Try reading from the inner data, filling the buffer with as much data as makes sense. |
329 |
| - /// Returns the number of bytes actually read, or Zero if none. |
330 |
| - fn try_read(&self, buf: &mut [u8]) -> usize { |
331 |
| - let mut inner = self.inner.lock().unwrap(); |
332 |
| - let mut pos = 0; |
333 |
| - while pos < buf.len() { |
334 |
| - if let Some(elt) = inner.buffer.pop_front() { |
335 |
| - buf[pos] = elt; |
336 |
| - pos += 1; |
337 |
| - } else { |
338 |
| - break; |
339 |
| - } |
340 |
| - } |
341 |
| - |
342 |
| - if pos > 0 { |
343 |
| - // Any time we do a read, clear the semaphore. |
344 |
| - let _ = self.read_sem.take(NoWait); |
345 |
| - } |
346 |
| - pos |
347 |
| - } |
348 |
| -} |
349 |
| - |
350 |
| -extern "C" fn irq_callback( |
351 |
| - dev: *const raw::device, |
352 |
| - user_data: *mut c_void, |
353 |
| -) { |
354 |
| - // Convert our user data, back to the CS Mutex. |
355 |
| - let outer = unsafe { &*(user_data as *const IrqOuterData) }; |
356 |
| - let mut inner = outer.inner.lock().unwrap(); |
357 |
| - |
358 |
| - // TODO: Make this more efficient. |
359 |
| - let mut byte = 0u8; |
360 |
| - let mut did_read = false; |
361 |
| - loop { |
362 |
| - match unsafe { raw::uart_fifo_read(dev, &mut byte, 1) } { |
363 |
| - 0 => break, |
364 |
| - 1 => { |
365 |
| - // TODO: should we warn about overflow here? |
366 |
| - let _ = inner.buffer.push_back(byte); |
367 |
| - did_read = true; |
368 |
| - } |
369 |
| - e => panic!("Uart fifo read not implemented: {}", e), |
370 |
| - } |
371 |
| - } |
372 |
| - |
373 |
| - // This is safe (and important) to do while the mutex is held. |
374 |
| - if did_read { |
375 |
| - outer.read_sem.give(); |
376 |
| - } |
377 |
| - |
378 |
| - // If there is data to write, ensure the fifo is full, and when we run out of data, disable the |
379 |
| - // interrupt and signal the waiting thread. |
380 |
| - if let Some(write) = inner.write.take() { |
381 |
| - let count = unsafe { |
382 |
| - raw::uart_fifo_fill(dev, write.data, write.len as i32) |
383 |
| - }; |
384 |
| - if count < 0 { |
385 |
| - panic!("Incorrect use of device fifo"); |
386 |
| - } |
387 |
| - let count = count as usize; |
388 |
| - |
389 |
| - if count == write.len { |
390 |
| - // The write finished, leave 'write' empty, and let the thread know we're done. |
391 |
| - outer.write_sem.give(); |
392 |
| - |
393 |
| - // Disable the tx fifo, as we don't need it any more. |
394 |
| - unsafe { raw::uart_irq_tx_disable(dev) }; |
395 |
| - } else { |
396 |
| - // We're not finished, so remember how much is left. |
397 |
| - inner.write = Some(unsafe { write.add(count) }); |
398 |
| - } |
399 |
| - } |
400 |
| - |
401 |
| - unsafe { |
402 |
| - raw::uart_irq_update(dev); |
403 |
| - } |
404 |
| -} |
0 commit comments