Skip to content

Commit caf09c4

Browse files
bors[bot]chris ricketts
and
chris ricketts
authored
Merge #26
26: Closes: #25 - manually implement errors r=posborne a=chris-ricketts Wraps ioctl macros with another macro that maps the ioctl call to a particular `IoctlType`. That type and the underlying `nix::Error` are then stored in the `ErrorKind::Ioctl` variant. Plays nicely with the [anyhow](https://github.com/dtolnay/anyhow) error handling crate, which seems like a more mature version of `failure`. This can be seen in the [monitor example](https://github.com/chris-ricketts/gpio-cdev/blob/6179eea9d16025a9236a0d961ce932b8517fbda9/examples/monitor.rs#L30). Co-authored-by: chris ricketts <[email protected]>
2 parents 832b6b8 + 6179eea commit caf09c4

13 files changed

+237
-122
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ license = "MIT OR Apache-2.0"
1212

1313
[dependencies]
1414
bitflags = "1.0"
15-
error-chain = "0.12"
1615
libc = "0.2"
1716
nix = "0.14"
1817

1918
[dev-dependencies]
2019
quicli = "0.2"
20+
anyhow = "1.0"

examples/blinky.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use quicli::prelude::*;
1515
use std::thread::sleep;
1616
use std::time::{Duration, Instant};
1717

18+
1819
#[derive(Debug, StructOpt)]
1920
struct Cli {
2021
/// The gpiochip device (e.g. /dev/gpiochip0)
@@ -27,7 +28,7 @@ struct Cli {
2728
duration_ms: u64,
2829
}
2930

30-
fn do_main(args: Cli) -> errors::Result<()> {
31+
fn do_main(args: Cli) -> std::result::Result<(), errors::Error> {
3132
let mut chip = Chip::new(args.chip)?;
3233

3334
// NOTE: we set the default value to the desired state so

examples/driveoutput.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct Cli {
2323
value: u8,
2424
}
2525

26-
fn do_main(args: Cli) -> errors::Result<()> {
26+
fn do_main(args: Cli) -> std::result::Result<(), errors::Error> {
2727
let mut chip = Chip::new(args.chip)?;
2828

2929
// NOTE: we set the default value to the desired state so

examples/gpioevents.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extern crate quicli;
1313
use gpio_cdev::*;
1414
use quicli::prelude::*;
1515

16+
1617
#[derive(Debug, StructOpt)]
1718
struct Cli {
1819
/// The gpiochip device (e.g. /dev/gpiochip0)
@@ -21,7 +22,7 @@ struct Cli {
2122
line: u32,
2223
}
2324

24-
fn do_main(args: Cli) -> errors::Result<()> {
25+
fn do_main(args: Cli) -> std::result::Result<(), errors::Error> {
2526
let mut chip = Chip::new(args.chip)?;
2627
let line = chip.get_line(args.line)?;
2728

examples/monitor.rs

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88

99
extern crate gpio_cdev;
1010
extern crate nix;
11-
#[macro_use] extern crate quicli;
11+
#[macro_use]
12+
extern crate quicli;
13+
extern crate anyhow;
1214

1315
use gpio_cdev::*;
14-
use quicli::prelude::*;
1516
use nix::poll::*;
16-
use std::os::unix::io::{AsRawFd};
17+
use quicli::prelude::*;
18+
use std::os::unix::io::AsRawFd;
1719

1820
type PollEventFlags = nix::poll::PollFlags;
1921

@@ -25,27 +27,40 @@ struct Cli {
2527
lines: Vec<u32>,
2628
}
2729

28-
fn do_main(args: Cli) -> errors::Result<()> {
30+
fn do_main(args: Cli) -> anyhow::Result<()> {
2931
let mut chip = Chip::new(args.chip)?;
3032

3133
// Get event handles for each line to monitor.
32-
let mut evt_handles: Vec<LineEventHandle> = args.lines.into_iter().map(|off| {
33-
let line = chip.get_line(off).unwrap();
34-
line.events(LineRequestFlags::INPUT, EventRequestFlags::BOTH_EDGES,
35-
"monitor").unwrap()
36-
}).collect();
34+
let mut evt_handles: Vec<LineEventHandle> = args
35+
.lines
36+
.into_iter()
37+
.map(|off| {
38+
let line = chip.get_line(off).unwrap();
39+
line.events(
40+
LineRequestFlags::INPUT,
41+
EventRequestFlags::BOTH_EDGES,
42+
"monitor",
43+
)
44+
.unwrap()
45+
})
46+
.collect();
3747

3848
// Create a vector of file descriptors for polling
39-
let mut pollfds: Vec<PollFd> = evt_handles.iter().map(|h| {
40-
PollFd::new(h.as_raw_fd(), PollEventFlags::POLLIN | PollEventFlags::POLLPRI)
41-
}).collect();
49+
let mut pollfds: Vec<PollFd> = evt_handles
50+
.iter()
51+
.map(|h| {
52+
PollFd::new(
53+
h.as_raw_fd(),
54+
PollEventFlags::POLLIN | PollEventFlags::POLLPRI,
55+
)
56+
})
57+
.collect();
4258

4359
loop {
4460
// poll for an event on any of the lines
4561
if poll(&mut pollfds, -1)? == 0 {
4662
println!("Timeout?!?");
47-
}
48-
else {
63+
} else {
4964
for i in 0..pollfds.len() {
5065
if let Some(revts) = pollfds[i].revents() {
5166
let h = &mut evt_handles[i];
@@ -58,9 +73,8 @@ fn do_main(args: Cli) -> errors::Result<()> {
5873
// to read the value of the bit.
5974
let val = h.get_value()?;
6075
println!(" {}", val);
61-
}
62-
else if revts.contains(PollEventFlags::POLLPRI) {
63-
println!("[{}] Got a POLLPRI", h.line().offset());
76+
} else if revts.contains(PollEventFlags::POLLPRI) {
77+
println!("[{}] Got a POLLPRI", h.line().offset());
6478
}
6579
}
6680
}
@@ -70,7 +84,7 @@ fn do_main(args: Cli) -> errors::Result<()> {
7084

7185
main!(|args: Cli| {
7286
match do_main(args) {
73-
Ok(()) => {},
87+
Ok(()) => {}
7488
Err(e) => {
7589
println!("Error: {:?}", e);
7690
}

examples/multioutput.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct Cli {
2828
// to set lines 0, 1, & 3 high
2929
// 2 & 4 low
3030
//
31-
fn do_main(args: Cli) -> errors::Result<()> {
31+
fn do_main(args: Cli) -> std::result::Result<(), errors::Error> {
3232
let mut chip = Chip::new(args.chip)?;
3333
let mut offsets = Vec::new();
3434
let mut values = Vec::new();

examples/multiread.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct Cli {
2121
lines: Vec<u32>,
2222
}
2323

24-
fn do_main(args: Cli) -> errors::Result<()> {
24+
fn do_main(args: Cli) -> std::result::Result<(), errors::Error> {
2525
let mut chip = Chip::new(args.chip)?;
2626
let ini_vals = vec![ 0; args.lines.len() ];
2727
let handle = chip

examples/readall.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ struct Cli {
1919
chip: String,
2020
}
2121

22-
fn do_main(args: Cli) -> errors::Result<()> {
22+
fn do_main(args: Cli) -> std::result::Result<(), errors::Error> {
2323
let mut chip = Chip::new(args.chip)?;
24-
let ini_vals = vec![ 0; chip.num_lines() as usize ];
24+
let ini_vals = vec![0; chip.num_lines() as usize];
2525
let handle = chip
2626
.get_all_lines()?
2727
.request(LineRequestFlags::INPUT, &ini_vals, "readall")?;

examples/readinput.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct Cli {
2121
line: u32,
2222
}
2323

24-
fn do_main(args: Cli) -> errors::Result<()> {
24+
fn do_main(args: Cli) -> std::result::Result<(), errors::Error> {
2525
let mut chip = Chip::new(args.chip)?;
2626
let handle = chip
2727
.get_line(args.line)?

examples/tit_for_tat.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use quicli::prelude::*;
1515
use std::thread::sleep;
1616
use std::time::Duration;
1717

18+
1819
#[derive(Debug, StructOpt)]
1920
struct Cli {
2021
/// The gpiochip device (e.g. /dev/gpiochip0)
@@ -27,7 +28,7 @@ struct Cli {
2728
sleeptime: u64,
2829
}
2930

30-
fn do_main(args: Cli) -> errors::Result<()> {
31+
fn do_main(args: Cli) -> std::result::Result<(), errors::Error> {
3132
let mut chip = Chip::new(args.chip)?;
3233
let input = chip.get_line(args.inputline)?;
3334
let output = chip.get_line(args.outputline)?;

src/errors.rs

Lines changed: 99 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,101 @@
1-
// Copyright (c) 2018 The rust-gpio-cdev Project Developers.
2-
//
3-
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4-
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5-
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6-
// option. This file may not be copied, modified, or distributed
7-
// except according to those terms.
8-
9-
error_chain! {
10-
types {
11-
Error,
12-
ErrorKind,
13-
ResultExt,
14-
Result;
15-
}
16-
17-
foreign_links {
18-
Nix(::nix::Error);
19-
Io(::std::io::Error);
1+
use std::error::Error as StdError;
2+
use std::fmt;
3+
use std::io::Error as IOError;
4+
5+
pub(crate) type Result<T> = std::result::Result<T, Error>;
6+
7+
#[derive(Debug)]
8+
pub struct Error {
9+
kind: ErrorKind,
10+
}
11+
12+
#[derive(Debug)]
13+
pub enum IoctlKind {
14+
ChipInfo,
15+
LineInfo,
16+
LineHandle,
17+
LineEvent,
18+
GetLine,
19+
SetLine,
20+
}
21+
22+
#[derive(Debug)]
23+
pub enum ErrorKind {
24+
Event(nix::Error),
25+
Io(IOError),
26+
Ioctl { kind: IoctlKind, cause: nix::Error },
27+
InvalidRequest(usize, usize),
28+
Offset(u32),
29+
}
30+
31+
pub(crate) fn ioctl_err(kind: IoctlKind, cause: nix::Error) -> Error {
32+
Error {
33+
kind: ErrorKind::Ioctl { kind, cause },
34+
}
35+
}
36+
37+
pub(crate) fn invalid_err(n_lines: usize, n_values: usize) -> Error {
38+
Error {
39+
kind: ErrorKind::InvalidRequest(n_lines, n_values),
40+
}
41+
}
42+
43+
pub(crate) fn offset_err(offset: u32) -> Error {
44+
Error {
45+
kind: ErrorKind::Offset(offset),
46+
}
47+
}
48+
49+
pub(crate) fn event_err(err: nix::Error) -> Error {
50+
Error {
51+
kind: ErrorKind::Event(err),
52+
}
53+
}
54+
55+
impl fmt::Display for IoctlKind {
56+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57+
match *self {
58+
IoctlKind::ChipInfo => write!(f, "get chip info"),
59+
IoctlKind::LineInfo => write!(f, "get line info"),
60+
IoctlKind::LineHandle => write!(f, "get line handle"),
61+
IoctlKind::LineEvent => write!(f, "get line event "),
62+
IoctlKind::GetLine => write!(f, "get line value"),
63+
IoctlKind::SetLine => write!(f, "set line value"),
64+
}
65+
}
66+
}
67+
68+
impl fmt::Display for Error {
69+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70+
match &self.kind {
71+
ErrorKind::Event(err) => write!(f, "Failed to read event: {}", err),
72+
ErrorKind::Io(err) => err.fmt(f),
73+
ErrorKind::Ioctl { cause, kind } => write!(f, "Ioctl to {} failed: {}", kind, cause),
74+
ErrorKind::InvalidRequest(n_lines, n_values) => write!(
75+
f,
76+
"Invalid request: {} values requested to be set but only {} lines are open",
77+
n_values, n_lines
78+
),
79+
ErrorKind::Offset(offset) => write!(f, "Offset {} is out of range", offset),
80+
}
81+
}
82+
}
83+
84+
impl StdError for Error {
85+
fn source(&self) -> Option<&(dyn StdError + 'static)> {
86+
match &self.kind {
87+
ErrorKind::Event(err) => Some(err),
88+
ErrorKind::Io(err) => Some(err),
89+
ErrorKind::Ioctl { kind: _, cause } => Some(cause),
90+
_ => None,
91+
}
92+
}
93+
}
94+
95+
impl From<IOError> for Error {
96+
fn from(err: IOError) -> Error {
97+
Error {
98+
kind: ErrorKind::Io(err),
99+
}
20100
}
21101
}

src/ffi.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9+
use super::errors::IoctlKind;
910
use libc;
1011

1112
pub const GPIOHANDLES_MAX: usize = 64;
@@ -56,10 +57,52 @@ pub struct gpioevent_data {
5657
pub id: u32,
5758
}
5859

59-
ioctl_read!(gpio_get_chipinfo_ioctl, 0xB4, 0x01, gpiochip_info);
60-
ioctl_readwrite!(gpio_get_lineinfo_ioctl, 0xB4, 0x02, gpioline_info);
61-
ioctl_readwrite!(gpio_get_linehandle_ioctl, 0xB4, 0x03, gpiohandle_request);
62-
ioctl_readwrite!(gpio_get_lineevent_ioctl, 0xB4, 0x04, gpioevent_request);
60+
macro_rules! wrap_ioctl {
61+
($ioctl_macro:ident!($name:ident, $ioty:expr, $nr:expr, $ty:ident), $ioctl_error_type:expr) => {
62+
mod $name {
63+
$ioctl_macro!($name, $ioty, $nr, super::$ty);
64+
}
6365

64-
ioctl_readwrite!(gpiohandle_get_line_values_ioctl, 0xB4, 0x08, gpiohandle_data);
65-
ioctl_readwrite!(gpiohandle_set_line_values_ioctl, 0xB4, 0x09, gpiohandle_data);
66+
pub(crate) fn $name(fd: libc::c_int, data: &mut $ty) -> crate::errors::Result<libc::c_int> {
67+
unsafe {
68+
$name::$name(fd, data).map_err(|e| crate::errors::ioctl_err($ioctl_error_type, e))
69+
}
70+
}
71+
};
72+
}
73+
74+
wrap_ioctl!(
75+
ioctl_read!(gpio_get_chipinfo_ioctl, 0xB4, 0x01, gpiochip_info),
76+
IoctlKind::ChipInfo
77+
);
78+
wrap_ioctl!(
79+
ioctl_readwrite!(gpio_get_lineinfo_ioctl, 0xB4, 0x02, gpioline_info),
80+
IoctlKind::LineInfo
81+
);
82+
wrap_ioctl!(
83+
ioctl_readwrite!(gpio_get_linehandle_ioctl, 0xB4, 0x03, gpiohandle_request),
84+
IoctlKind::LineHandle
85+
);
86+
wrap_ioctl!(
87+
ioctl_readwrite!(gpio_get_lineevent_ioctl, 0xB4, 0x04, gpioevent_request),
88+
IoctlKind::LineEvent
89+
);
90+
91+
wrap_ioctl!(
92+
ioctl_readwrite!(
93+
gpiohandle_get_line_values_ioctl,
94+
0xB4,
95+
0x08,
96+
gpiohandle_data
97+
),
98+
IoctlKind::GetLine
99+
);
100+
wrap_ioctl!(
101+
ioctl_readwrite!(
102+
gpiohandle_set_line_values_ioctl,
103+
0xB4,
104+
0x09,
105+
gpiohandle_data
106+
),
107+
IoctlKind::SetLine
108+
);

0 commit comments

Comments
 (0)