Skip to content

Commit 252e5ad

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 403cf3b commit 252e5ad

File tree

4 files changed

+174
-9
lines changed

4 files changed

+174
-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"
15+
embedded-io = "0.6.1"
1516
unwrap-infallible = "0.1.5"
1617

1718
[dependencies.embedded-hal-v0]

avr-hal-generic/src/usart.rs

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

10+
use embedded_io::ErrorType;
11+
912
use crate::port;
1013

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

203206
/// Enable/Disable a certain interrupt.
204207
///
@@ -336,7 +339,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> Usart<H, USART, RX, TX, CLOCK
336339
}
337340

338341
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite for Usart<H, USART, RX, TX, CLOCK> {
339-
type Error = core::convert::Infallible;
342+
type Error = Infallible;
340343

341344
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
342345
for b in s.as_bytes().iter() {
@@ -349,7 +352,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite for Usart<H, USA
349352
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Write<u8>
350353
for Usart<H, USART, RX, TX, CLOCK>
351354
{
352-
type Error = core::convert::Infallible;
355+
type Error = Infallible;
353356

354357
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
355358
self.p.raw_write(byte)
@@ -360,16 +363,78 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Writ
360363
}
361364
}
362365

366+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ErrorType for Usart<H, USART, RX, TX, CLOCK> { type Error = Infallible; }
367+
368+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_io::Write for Usart<H, USART, RX, TX, CLOCK> {
369+
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
370+
if buf.is_empty() {
371+
return Ok(0);
372+
}
373+
// block for first byte
374+
self.write_byte(buf[0]);
375+
let mut i = 1;
376+
377+
// write more bytes if it's possible
378+
for byte in buf[1..].iter() {
379+
match self.p.raw_write(*byte) {
380+
Ok(_) => {
381+
i += 1;
382+
}
383+
Err(nb::Error::WouldBlock) => {
384+
return Ok(i);
385+
}
386+
Err(_) => {
387+
unreachable!(); // `raw_write` is `Infallible`
388+
}
389+
}
390+
}
391+
Ok(i)
392+
}
393+
394+
fn flush(&mut self) -> Result<(), Self::Error> {
395+
self.p.raw_flush().unwrap(); // `raw_write` is `Infallible`
396+
Ok(())
397+
}
398+
}
399+
363400
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Read<u8>
364401
for Usart<H, USART, RX, TX, CLOCK>
365402
{
366-
type Error = core::convert::Infallible;
403+
type Error = Infallible;
367404

368405
fn read(&mut self) -> nb::Result<u8, Self::Error> {
369406
self.p.raw_read()
370407
}
371408
}
372409

410+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_io::Read for Usart<H, USART, RX, TX, CLOCK> {
411+
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
412+
// block for first byte
413+
buf[0] = self.read_byte();
414+
let mut i = 1;
415+
416+
// grab more bytes if available
417+
loop {
418+
match self.p.raw_read() {
419+
Ok(byte) => {
420+
buf[i] = byte;
421+
i += 1;
422+
423+
if i == buf.len() {
424+
return Ok(i);
425+
}
426+
}
427+
Err(nb::Error::WouldBlock) => {
428+
return Ok(i);
429+
}
430+
Err(_) => {
431+
unreachable!(); // `raw_read` is `Infallible`
432+
}
433+
}
434+
}
435+
}
436+
}
437+
373438
/// Writer half of a [`Usart`] peripheral.
374439
///
375440
/// Created by calling [`Usart::split`]. Splitting a peripheral into reader and writer allows
@@ -413,6 +478,14 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartWriter<H, USART, RX, TX,
413478
_h: marker::PhantomData,
414479
}
415480
}
481+
482+
/// Transmit a byte.
483+
///
484+
/// This method will block until the byte has been enqueued for transmission but **not** until
485+
/// it was entirely sent.
486+
fn write_byte(&mut self, byte: u8) {
487+
nb::block!(self.p.raw_write(byte)).unwrap()
488+
}
416489
}
417490

418491
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartReader<H, USART, RX, TX, CLOCK> {
@@ -434,7 +507,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartReader<H, USART, RX, TX,
434507
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite
435508
for UsartWriter<H, USART, RX, TX, CLOCK>
436509
{
437-
type Error = core::convert::Infallible;
510+
type Error = Infallible;
438511

439512
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
440513
for b in s.as_bytes().iter() {
@@ -447,7 +520,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite
447520
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Write<u8>
448521
for UsartWriter<H, USART, RX, TX, CLOCK>
449522
{
450-
type Error = core::convert::Infallible;
523+
type Error = Infallible;
451524

452525
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
453526
self.p.raw_write(byte)
@@ -458,16 +531,77 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Writ
458531
}
459532
}
460533

534+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ErrorType for UsartWriter<H, USART, RX, TX, CLOCK> { type Error = Infallible; }
535+
536+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_io::Write for UsartWriter<H, USART, RX, TX, CLOCK> {
537+
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
538+
if buf.is_empty() {
539+
return Ok(0);
540+
}
541+
// block for first byte
542+
self.write_byte(buf[0]);
543+
let mut i = 1;
544+
545+
// write more bytes if it's possible
546+
for byte in buf[1..].iter() {
547+
match self.p.raw_write(*byte) {
548+
Ok(_) => {
549+
i += 1;
550+
}
551+
Err(nb::Error::WouldBlock) => {
552+
return Ok(i);
553+
}
554+
Err(_) => {
555+
unreachable!(); // `raw_write` is `Infallible`
556+
}
557+
}
558+
}
559+
Ok(i)
560+
}
561+
562+
fn flush(&mut self) -> Result<(), Self::Error> {
563+
self.p.raw_flush().unwrap(); // `raw_flush` is `Infallible`
564+
Ok(())
565+
}
566+
}
567+
461568
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Read<u8>
462569
for UsartReader<H, USART, RX, TX, CLOCK>
463570
{
464-
type Error = core::convert::Infallible;
571+
type Error = Infallible;
465572

466573
fn read(&mut self) -> nb::Result<u8, Self::Error> {
467574
self.p.raw_read()
468575
}
469576
}
470577

578+
579+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ErrorType for UsartReader<H, USART, RX, TX, CLOCK> { type Error = Infallible; }
580+
581+
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_io::Read for UsartReader<H, USART, RX, TX, CLOCK> {
582+
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
583+
let mut i = 0;
584+
loop {
585+
match self.p.raw_read() {
586+
Ok(byte) => {
587+
buf[i] = byte;
588+
i += 1;
589+
590+
if i == buf.len() {
591+
return Ok(i);
592+
}
593+
}
594+
Err(nb::Error::WouldBlock) => {
595+
return Ok(i);
596+
}
597+
Err(_) => {
598+
unreachable!(); // `raw_read` is `Infallible`
599+
}
600+
}
601+
}
602+
}
603+
}
604+
471605
#[macro_export]
472606
macro_rules! impl_usart_traditional {
473607
(

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"
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 {} bytes long)", &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)