Skip to content

Commit f99adad

Browse files
committed
implement embedded-io v0.6 Read & Write
with `embedded-hal` v1 the USART traits have been removed in favour of the new `embedded-io` crate. this adds a (very basic) implementation for `Read` and `Write`. other traits (such as the `*Ready` or `BufRead` traits) have not (yet) been implemented and some (like `Seek`) probably can't be implemented for this HAL. a better implementation might use a buffer in the background to receive more than one byte at once. see also #249 for a related PR. this is part of #468
1 parent dfc94f6 commit f99adad

File tree

4 files changed

+138
-9
lines changed

4 files changed

+138
-9
lines changed

avr-hal-generic/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ paste = "1.0.0"
1212
avr-device = "0.5.3"
1313
embedded-storage = "0.2"
1414
embedded-hal = "1.0.0-rc.3"
15+
embedded-io = "0.6.1"
1516

1617
[dependencies.embedded-hal-v0]
1718
version = "0.2.3"

avr-hal-generic/src/usart.rs

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
//! Check the documentation of [`Usart`] for details.
44
55
use core::cmp::Ordering;
6+
use core::convert::Infallible;
67
use core::marker;
78

9+
use embedded_io::ErrorType;
10+
811
use crate::port;
912

1013
/// Representation of a USART baudrate
@@ -183,21 +186,21 @@ pub trait UsartOps<H, RX, TX> {
183186
/// was flushed yet.
184187
///
185188
/// **Warning**: This is a low-level method and should not be called directly from user code.
186-
fn raw_flush(&mut self) -> nb::Result<(), core::convert::Infallible>;
189+
fn raw_flush(&mut self) -> nb::Result<(), Infallible>;
187190
/// Write a byte to the TX buffer.
188191
///
189192
/// This operation must be non-blocking and return [`nb::Error::WouldBlock`] until the byte is
190193
/// enqueued. The operation should not wait for the byte to have actually been sent.
191194
///
192195
/// **Warning**: This is a low-level method and should not be called directly from user code.
193-
fn raw_write(&mut self, byte: u8) -> nb::Result<(), core::convert::Infallible>;
196+
fn raw_write(&mut self, byte: u8) -> nb::Result<(), Infallible>;
194197
/// Read a byte from the RX buffer.
195198
///
196199
/// This operation must be non-blocking and return [`nb::Error::WouldBlock`] if no incoming
197200
/// byte is available.
198201
///
199202
/// **Warning**: This is a low-level method and should not be called directly from user code.
200-
fn raw_read(&mut self) -> nb::Result<u8, core::convert::Infallible>;
203+
fn raw_read(&mut self) -> nb::Result<u8, Infallible>;
201204

202205
/// Enable/Disable a certain interrupt.
203206
///
@@ -335,7 +338,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> Usart<H, USART, RX, TX, CLOCK
335338
}
336339

337340
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite for Usart<H, USART, RX, TX, CLOCK> {
338-
type Error = core::convert::Infallible;
341+
type Error = Infallible;
339342

340343
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
341344
for b in s.as_bytes().iter() {
@@ -348,7 +351,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite for Usart<H, USA
348351
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
349352
for Usart<H, USART, RX, TX, CLOCK>
350353
{
351-
type Error = core::convert::Infallible;
354+
type Error = Infallible;
352355

353356
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
354357
self.p.raw_write(byte)
@@ -359,16 +362,60 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
359362
}
360363
}
361364

365+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ErrorType for Usart<H, USART, RX, TX, CLOCK> { type Error = embedded_io::ErrorKind; }
366+
367+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_io::Write for Usart<H, USART, RX, TX, CLOCK> {
368+
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
369+
for byte in buf {
370+
self.write_byte(*byte);
371+
}
372+
Ok(buf.len())
373+
}
374+
375+
fn flush(&mut self) -> Result<(), Self::Error> {
376+
self.p.raw_flush().unwrap(); // `raw_write` is `Infallible`
377+
Ok(())
378+
}
379+
}
380+
362381
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Read<u8>
363382
for Usart<H, USART, RX, TX, CLOCK>
364383
{
365-
type Error = core::convert::Infallible;
384+
type Error = Infallible;
366385

367386
fn read(&mut self) -> nb::Result<u8, Self::Error> {
368387
self.p.raw_read()
369388
}
370389
}
371390

391+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_io::Read for Usart<H, USART, RX, TX, CLOCK> {
392+
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
393+
// block for first byte
394+
buf[0] = self.read_byte();
395+
let mut i = 1;
396+
397+
// grab more bytes when available
398+
loop {
399+
match self.p.raw_read() {
400+
Ok(byte) => {
401+
buf[i] = byte;
402+
i += 1;
403+
404+
if i == buf.len() {
405+
return Ok(i);
406+
}
407+
}
408+
Err(nb::Error::WouldBlock) => {
409+
return Ok(i);
410+
}
411+
Err(_) => {
412+
unreachable!(); // `raw_read` is `Infallible`
413+
}
414+
}
415+
}
416+
}
417+
}
418+
372419
/// Writer half of a [`Usart`] peripheral.
373420
///
374421
/// Created by calling [`Usart::split`]. Splitting a peripheral into reader and writer allows
@@ -412,6 +459,14 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartWriter<H, USART, RX, TX,
412459
_h: marker::PhantomData,
413460
}
414461
}
462+
463+
/// Transmit a byte.
464+
///
465+
/// This method will block until the byte has been enqueued for transmission but **not** until
466+
/// it was entirely sent.
467+
fn write_byte(&mut self, byte: u8) {
468+
nb::block!(self.p.raw_write(byte)).unwrap()
469+
}
415470
}
416471

417472
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartReader<H, USART, RX, TX, CLOCK> {
@@ -433,7 +488,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartReader<H, USART, RX, TX,
433488
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite
434489
for UsartWriter<H, USART, RX, TX, CLOCK>
435490
{
436-
type Error = core::convert::Infallible;
491+
type Error = Infallible;
437492

438493
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
439494
for b in s.as_bytes().iter() {
@@ -446,7 +501,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite
446501
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
447502
for UsartWriter<H, USART, RX, TX, CLOCK>
448503
{
449-
type Error = core::convert::Infallible;
504+
type Error = Infallible;
450505

451506
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
452507
self.p.raw_write(byte)
@@ -457,16 +512,59 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
457512
}
458513
}
459514

515+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ErrorType for UsartWriter<H, USART, RX, TX, CLOCK> { type Error = Infallible; }
516+
517+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_io::Write for UsartWriter<H, USART, RX, TX, CLOCK> {
518+
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
519+
for byte in buf {
520+
self.write_byte(*byte);
521+
}
522+
Ok(buf.len())
523+
}
524+
525+
fn flush(&mut self) -> Result<(), Self::Error> {
526+
self.p.raw_flush().unwrap(); // `raw_flush` is `Infallible`
527+
Ok(())
528+
}
529+
}
530+
460531
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Read<u8>
461532
for UsartReader<H, USART, RX, TX, CLOCK>
462533
{
463-
type Error = core::convert::Infallible;
534+
type Error = Infallible;
464535

465536
fn read(&mut self) -> nb::Result<u8, Self::Error> {
466537
self.p.raw_read()
467538
}
468539
}
469540

541+
542+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ErrorType for UsartReader<H, USART, RX, TX, CLOCK> { type Error = Infallible; }
543+
544+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_io::Read for UsartReader<H, USART, RX, TX, CLOCK> {
545+
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
546+
let mut i = 0;
547+
loop {
548+
match self.p.raw_read() {
549+
Ok(byte) => {
550+
buf[i] = byte;
551+
i += 1;
552+
553+
if i == buf.len() {
554+
return Ok(i);
555+
}
556+
}
557+
Err(nb::Error::WouldBlock) => {
558+
return Ok(i);
559+
}
560+
Err(_) => {
561+
unreachable!(); // `raw_read` is `Infallible`
562+
}
563+
}
564+
}
565+
}
566+
}
567+
470568
#[macro_export]
471569
macro_rules! impl_usart_traditional {
472570
(

examples/arduino-uno/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ embedded-hal = "1.0.0-rc.3"
1313
pwm-pca9685 = "0.3.1"
1414
infrared = "0.14.1"
1515
embedded-storage = "0.2"
16+
embedded-io = "0.6.1"
1617

1718
[dependencies.embedded-hal-v0]
1819
version = "0.2.3"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*!
2+
* Demonstration of writing to and reading from the serial console.
3+
*/
4+
#![no_std]
5+
#![no_main]
6+
7+
use panic_halt as _;
8+
9+
use embedded_io::{Read, Write};
10+
11+
fn usart_handler(serial: &mut (impl Read + Write)) -> ! {
12+
serial.write_all("Hello from Arduino!\r\n".as_bytes()).unwrap();
13+
14+
loop {
15+
let mut rx_buf: [u8; 16] = [0; 16];
16+
let len = serial.read(&mut rx_buf).unwrap();
17+
18+
writeln!(serial, "Got {:?} (which is {} long)\r\n", &rx_buf[..len], len).unwrap();
19+
}
20+
}
21+
22+
#[arduino_hal::entry]
23+
fn main() -> ! {
24+
let dp = arduino_hal::Peripherals::take().unwrap();
25+
let pins = arduino_hal::pins!(dp);
26+
let mut serial = arduino_hal::default_serial!(dp, pins, 57600);
27+
28+
usart_handler(&mut serial);
29+
}

0 commit comments

Comments
 (0)