Skip to content

Commit 3679a64

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 3679a64

4 files changed

Lines changed: 174 additions & 9 deletions

File tree

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

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

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

417490
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartReader<H, USART, RX, TX, CLOCK> {
@@ -433,7 +506,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartReader<H, USART, RX, TX,
433506
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite
434507
for UsartWriter<H, USART, RX, TX, CLOCK>
435508
{
436-
type Error = core::convert::Infallible;
509+
type Error = Infallible;
437510

438511
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
439512
for b in s.as_bytes().iter() {
@@ -446,7 +519,7 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite
446519
impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
447520
for UsartWriter<H, USART, RX, TX, CLOCK>
448521
{
449-
type Error = core::convert::Infallible;
522+
type Error = Infallible;
450523

451524
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
452525
self.p.raw_write(byte)
@@ -457,16 +530,77 @@ impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> hal::serial::Write<u8>
457530
}
458531
}
459532

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

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

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

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 {} 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)