Skip to content

Commit 27f3879

Browse files
authored
Merge pull request #8 from fpagliughi/fixed-evt-handle-fd
LineEventHandle (fixed)
2 parents 30286b5 + 6dbdf21 commit 27f3879

File tree

2 files changed

+162
-12
lines changed

2 files changed

+162
-12
lines changed

examples/monitor.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
extern crate gpio_cdev;
10+
extern crate nix;
11+
#[macro_use] extern crate quicli;
12+
13+
use gpio_cdev::*;
14+
use quicli::prelude::*;
15+
use nix::poll::*;
16+
use std::os::unix::io::{AsRawFd};
17+
18+
type PollEventFlags = nix::poll::EventFlags;
19+
20+
#[derive(Debug, StructOpt)]
21+
struct Cli {
22+
/// The gpiochip device (e.g. /dev/gpiochip0)
23+
chip: String,
24+
/// The offset of the GPIO lines for the provided chip
25+
lines: Vec<u32>,
26+
}
27+
28+
fn do_main(args: Cli) -> errors::Result<()> {
29+
let mut chip = Chip::new(args.chip)?;
30+
31+
// 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();
37+
38+
// 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();
42+
43+
loop {
44+
// poll for an event on any of the lines
45+
if poll(&mut pollfds, -1)? == 0 {
46+
println!("Timeout?!?");
47+
}
48+
else {
49+
for i in 0..pollfds.len() {
50+
if let Some(revts) = pollfds[i].revents() {
51+
let h = &mut evt_handles[i];
52+
if revts.contains(PollEventFlags::POLLIN) {
53+
let event = h.get_event()?;
54+
println!("[{}] {:?}", h.line().offset(), event);
55+
56+
// You can figure out the new level from the event,
57+
// but this shows that you can use the event handle
58+
// to read the value of the bit.
59+
let val = h.get_value()?;
60+
println!(" {}", val);
61+
}
62+
else if revts.contains(PollEventFlags::POLLPRI) {
63+
println!("[{}] Got a POLLPRI", h.line().offset());
64+
}
65+
}
66+
}
67+
}
68+
}
69+
}
70+
71+
main!(|args: Cli| {
72+
match do_main(args) {
73+
Ok(()) => {},
74+
Err(e) => {
75+
println!("Error: {:?}", e);
76+
}
77+
}
78+
});

src/lib.rs

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ use std::cmp::min;
9191
use std::ffi::CStr;
9292
use std::fs::{read_dir, File, ReadDir};
9393
use std::mem;
94-
use std::os::unix::io::{AsRawFd, FromRawFd};
94+
use std::os::unix::io::{RawFd, AsRawFd, FromRawFd};
9595
use std::path::{Path, PathBuf};
9696
use std::ptr;
9797
use std::slice;
@@ -181,7 +181,7 @@ impl Iterator for ChipIterator {
181181
/// Iterate over all GPIO chips currently present on this system
182182
pub fn chips() -> Result<ChipIterator> {
183183
Ok(ChipIterator {
184-
readdir: read_dir("/dev").chain_err(|| "unabled to rea /dev directory")?,
184+
readdir: read_dir("/dev").chain_err(|| "unabled to read /dev directory")?,
185185
})
186186
}
187187

@@ -518,11 +518,12 @@ impl Line {
518518
})
519519
}
520520

521-
/// Get a blocking iterator over events (state changes) for this Line
521+
/// Get an event handle that can be used as a blocking iterator over
522+
/// the events (state changes) for this Line
522523
///
523-
/// This iterator blocks while there is not another event available
524-
/// from the kernel for this line matching the subscription criteria
525-
/// specified in the `event_flags`. The line will be configured
524+
/// When used as an iterator, it blocks while there is not another event
525+
/// available from the kernel for this line matching the subscription
526+
/// criteria specified in the `event_flags`. The line will be configured
526527
/// with the specified `handle_flags` and `consumer` label.
527528
///
528529
/// Note that as compared with the sysfs interface, the character
@@ -559,7 +560,7 @@ impl Line {
559560
handle_flags: LineRequestFlags,
560561
event_flags: EventRequestFlags,
561562
consumer: &str,
562-
) -> Result<LineEventIterator> {
563+
) -> Result<LineEventHandle> {
563564
let mut request = ffi::gpioevent_request {
564565
lineoffset: self.offset,
565566
handleflags: handle_flags.bits(),
@@ -580,7 +581,10 @@ impl Line {
580581
.chain_err(|| "lineevent ioctl failed")?
581582
};
582583

583-
Ok(LineEventIterator {
584+
Ok(LineEventHandle {
585+
line: self.clone().refresh()?, // TODO: revisit
586+
handle_flags,
587+
event_flags,
584588
file: unsafe { File::from_raw_fd(request.fd) },
585589
})
586590
}
@@ -590,7 +594,7 @@ impl Line {
590594
///
591595
/// In order for userspace to read/write the value of a GPIO
592596
/// it must be requested from the chip using [`Line::request`].
593-
/// On success, the kernel creates and anonymous file descriptor
597+
/// On success, the kernel creates an anonymous file descriptor
594598
/// for interacting with the requested line. This structure
595599
/// is the go-between for callers and that file descriptor.
596600
///
@@ -647,6 +651,13 @@ impl LineHandle {
647651
}
648652
}
649653

654+
impl AsRawFd for LineHandle {
655+
/// Gets the raw file descriptor for the LineHandle.
656+
fn as_raw_fd(&self) -> RawFd {
657+
self.file.as_raw_fd()
658+
}
659+
}
660+
650661
/// Did the Line rise (go active) or fall (go inactive)?
651662
///
652663
/// Maps to kernel [`GPIOEVENT_EVENT_*`] definitions.
@@ -699,13 +710,74 @@ impl LineEvent {
699710
}
700711
}
701712

702-
/// Blocking iterator over events for a given line
713+
/// Handle for retrieving events from the kernel for a line
714+
///
715+
/// In order for userspace to retrieve incoming events on a GPIO,
716+
/// an event handle must be requested from the chip using
717+
/// [`Line::events`].
718+
/// On success, the kernel creates an anonymous file descriptor
719+
/// for reading events. This structure is the go-between for callers
720+
/// and that file descriptor.
721+
///
722+
/// [`Line::events`]: struct.Line.html#method.events
703723
#[derive(Debug)]
704-
pub struct LineEventIterator {
724+
pub struct LineEventHandle {
725+
line: Line,
726+
handle_flags: LineRequestFlags,
727+
event_flags: EventRequestFlags,
705728
file: File,
706729
}
707730

708-
impl Iterator for LineEventIterator {
731+
impl LineEventHandle {
732+
/// Retrieve the next event from the kernel for this line
733+
///
734+
/// This blocks while there is not another event available from the
735+
/// kernel for the line which matches the subscription criteria
736+
/// specified in the `event_flags` when the handle was created.
737+
pub fn get_event(&self) -> Result<LineEvent> {
738+
let mut data: ffi::gpioevent_data = unsafe { mem::zeroed() };
739+
let mut data_as_buf = unsafe {
740+
slice::from_raw_parts_mut(
741+
&mut data as *mut ffi::gpioevent_data as *mut u8,
742+
mem::size_of::<ffi::gpioevent_data>(),
743+
)
744+
};
745+
let bytes_read = nix::unistd::read(self.file.as_raw_fd(), &mut data_as_buf)?;
746+
747+
if bytes_read != mem::size_of::<ffi::gpioevent_data>() {
748+
let e = nix::Error::Sys(nix::errno::Errno::EIO);
749+
Err(e.into())
750+
} else {
751+
Ok(LineEvent(data))
752+
}
753+
}
754+
755+
/// Request the current state of this Line from the kernel
756+
///
757+
/// This value should be 0 or 1 which a "1" representing that
758+
/// the line is active. Usually this means that the line is
759+
/// at logic-level high but it could mean the opposite if the
760+
/// line has been marked as being ACTIVE_LOW.
761+
pub fn get_value(&self) -> Result<u8> {
762+
let mut data: ffi::gpiohandle_data = unsafe { mem::zeroed() };
763+
let _ = unsafe { ffi::gpiohandle_get_line_values_ioctl(self.file.as_raw_fd(), &mut data)? };
764+
Ok(data.values[0])
765+
}
766+
767+
/// Get the Line information associated with this handle.
768+
pub fn line(&self) -> &Line {
769+
&self.line
770+
}
771+
}
772+
773+
impl AsRawFd for LineEventHandle {
774+
/// Gets the raw file descriptor for the LineEventHandle.
775+
fn as_raw_fd(&self) -> RawFd {
776+
self.file.as_raw_fd()
777+
}
778+
}
779+
780+
impl Iterator for LineEventHandle {
709781
type Item = Result<LineEvent>;
710782

711783
fn next(&mut self) -> Option<Result<LineEvent>> {

0 commit comments

Comments
 (0)