Skip to content

Commit 235d9db

Browse files
bors[bot]rnestlerdbrgn
committed
Merge #9
9: Add serial::Read/Write implementation r=ryankurte a=rnestler So this is just a quick PoC to implement #8. @japaric Do you think it would be OK to implement it in that way? If yes I can finish it up. Co-authored-by: Raphael Nestler <raphael.nestler@gmail.com> Co-authored-by: Raphael Nestler <raphael.nestler@sensirion.com> Co-authored-by: Danilo Bargen <mail@dbrgn.ch>
2 parents 92a092d + b4239f1 commit 235d9db

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ embedded-hal = { version = "0.2.0", features = ["unproven"] }
1313
i2cdev = "0.4.1"
1414
spidev = "0.3.0"
1515
sysfs_gpio = "0.5.1"
16+
serial-unix = "0.4.0"
17+
serial-core = "0.4.0"
18+
nb = "0.1.1"
19+
20+
[dev-dependencies]
21+
openpty = "0.1.0"
1622

1723
[dependencies.cast]
1824
# we don't need the `Error` implementation

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ extern crate embedded_hal as hal;
1717
pub extern crate i2cdev;
1818
pub extern crate spidev;
1919
pub extern crate sysfs_gpio;
20+
pub extern crate serial_unix;
21+
pub extern crate serial_core;
22+
pub extern crate nb;
2023

2124
use std::io::{self, Write};
2225
use std::path::{Path, PathBuf};
@@ -27,6 +30,10 @@ use cast::{u32, u64};
2730
use i2cdev::core::I2CDevice;
2831
use spidev::SpidevTransfer;
2932

33+
mod serial;
34+
35+
pub use serial::Serial;
36+
3037
/// Empty struct that provides delay functionality on top of `thread::sleep`
3138
pub struct Delay;
3239

src/serial.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//! Implementation of [`Serial`](https://docs.rs/embedded-hal/0.2.1/embedded_hal/serial/index.html)
2+
3+
use std::io::{ErrorKind as IoErrorKind, Read, Write};
4+
use std::path::Path;
5+
6+
use nb;
7+
8+
use hal;
9+
use serial_core;
10+
use serial_unix::TTYPort;
11+
12+
/// Newtype around [`serial_unix::TTYPort`] that implements
13+
/// the `embedded-hal` traits.
14+
pub struct Serial(pub TTYPort);
15+
16+
impl Serial {
17+
/// Wrapper for `serial_unix::TTYPort::open`
18+
pub fn open(path: &Path) -> Result<Serial, serial_core::Error> {
19+
Ok(Serial(TTYPort::open(path)?))
20+
}
21+
}
22+
23+
/// Helper to convert std::io::Error to the nb::Error
24+
fn translate_io_errors(err: std::io::Error) -> nb::Error<IoErrorKind> {
25+
match err.kind() {
26+
IoErrorKind::WouldBlock | IoErrorKind::TimedOut | IoErrorKind::Interrupted => {
27+
nb::Error::WouldBlock
28+
}
29+
err => nb::Error::Other(err),
30+
}
31+
}
32+
33+
impl hal::serial::Read<u8> for Serial {
34+
type Error = IoErrorKind;
35+
36+
fn read(&mut self) -> nb::Result<u8, Self::Error> {
37+
let mut buffer = [0; 1];
38+
let bytes_read = self.0.read(&mut buffer).map_err(translate_io_errors)?;
39+
if bytes_read == 1 {
40+
Ok(buffer[0])
41+
} else {
42+
Err(nb::Error::WouldBlock)
43+
}
44+
}
45+
}
46+
47+
impl hal::serial::Write<u8> for Serial {
48+
type Error = IoErrorKind;
49+
50+
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
51+
self.0.write(&[word]).map_err(translate_io_errors)?;
52+
Ok(())
53+
}
54+
55+
fn flush(&mut self) -> nb::Result<(), Self::Error> {
56+
self.0.flush().map_err(translate_io_errors)
57+
}
58+
}
59+
60+
#[cfg(test)]
61+
mod test {
62+
use std::path::Path;
63+
64+
use hal::serial::{Read, Write};
65+
use std::io::{Read as IoRead, Write as IoWrite};
66+
67+
use super::*;
68+
69+
fn create_pty_and_serial() -> (std::fs::File, Serial) {
70+
let (master, _slave, name) =
71+
openpty::openpty(None, None, None).expect("Creating pty failed");
72+
let serial = Serial::open(Path::new(&name)).expect("Creating TTYPort failed");
73+
(master, serial)
74+
}
75+
76+
#[test]
77+
fn test_empty_read() {
78+
let (mut _master, mut serial) = create_pty_and_serial();
79+
assert_eq!(Err(nb::Error::WouldBlock), serial.read());
80+
}
81+
82+
#[test]
83+
fn test_read() {
84+
let (mut master, mut serial) = create_pty_and_serial();
85+
master.write(&[1]).expect("Write failed");
86+
assert_eq!(Ok(1), serial.read());
87+
}
88+
89+
#[test]
90+
fn test_write() {
91+
let (mut master, mut serial) = create_pty_and_serial();
92+
serial.write(2).expect("Write failed");
93+
let mut buf = [0; 2];
94+
assert_eq!(1, master.read(&mut buf).unwrap());
95+
assert_eq!(buf, [2, 0]);
96+
}
97+
}

0 commit comments

Comments
 (0)