#![allow(dead_code)]
use std::fmt;
use std::thread;
use std::time::{Duration, Instant};
use crate::gpio::epoll::{epoll_event, Epoll, EventFd, EPOLLERR, EPOLLET, EPOLLIN, EPOLLPRI};
use crate::gpio::ioctl;
use crate::gpio::pin::InputPin;
use crate::gpio::{Error, Level, Result, Trigger};
#[derive(Debug)]
struct Interrupt {
pin: u8,
trigger: Trigger,
cdev_fd: i32,
event_request: ioctl::EventRequest,
}
impl Interrupt {
fn new(cdev_fd: i32, pin: u8, trigger: Trigger) -> Result<Interrupt> {
Ok(Interrupt {
pin,
trigger,
cdev_fd,
event_request: ioctl::EventRequest::new(cdev_fd, pin, trigger)?,
})
}
fn trigger(&self) -> Trigger {
self.trigger
}
fn fd(&self) -> i32 {
self.event_request.fd
}
fn pin(&self) -> u8 {
self.pin
}
fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
self.trigger = trigger;
self.reset()
}
fn event(&mut self) -> Result<ioctl::Event> {
ioctl::get_event(self.event_request.fd)
}
fn reset(&mut self) -> Result<()> {
self.event_request.close();
self.event_request = ioctl::EventRequest::new(self.cdev_fd, self.pin, self.trigger)?;
Ok(())
}
}
#[derive(Debug)]
struct TriggerStatus {
interrupt: Option<Interrupt>,
triggered: bool,
level: Level,
}
pub struct EventLoop {
poll: Epoll,
events: Vec<epoll_event>,
trigger_status: Vec<TriggerStatus>,
cdev_fd: i32,
}
impl fmt::Debug for EventLoop {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EventLoop")
.field("poll", &self.poll)
.field("events", &format_args!("{{ .. }}"))
.field("trigger_status", &format_args!("{{ .. }}"))
.field("cdev_fd", &self.cdev_fd)
.finish()
}
}
impl EventLoop {
pub fn new(cdev_fd: i32, capacity: usize) -> Result<EventLoop> {
let mut trigger_status = Vec::with_capacity(capacity);
for _ in 0..trigger_status.capacity() {
trigger_status.push(TriggerStatus {
interrupt: None,
triggered: false,
level: Level::Low,
});
}
Ok(EventLoop {
poll: Epoll::new()?,
events: vec![epoll_event { events: 0, u64: 0 }; capacity],
trigger_status,
cdev_fd,
})
}
pub fn poll<'a>(
&mut self,
pins: &[&'a InputPin],
reset: bool,
timeout: Option<Duration>,
) -> Result<Option<(&'a InputPin, Level)>> {
for pin in pins {
let trigger_status = &mut self.trigger_status[pin.pin() as usize];
if trigger_status.triggered {
trigger_status.triggered = false;
if !reset {
return Ok(Some((pin, trigger_status.level)));
}
}
if let Some(ref mut interrupt) = trigger_status.interrupt {
if reset {
self.poll.delete(interrupt.fd())?;
interrupt.reset()?;
self.poll.add(
interrupt.fd(),
u64::from(interrupt.pin()),
EPOLLIN | EPOLLPRI,
)?;
}
}
}
let now = Instant::now();
loop {
let num_events = self.poll.wait(&mut self.events, timeout)?;
if num_events == 0 {
return Ok(None);
}
for event in &self.events[0..num_events] {
let pin = event.u64 as usize;
let trigger_status = &mut self.trigger_status[pin];
if let Some(ref mut interrupt) = trigger_status.interrupt {
trigger_status.level = interrupt.event()?.level();
trigger_status.triggered = true;
};
}
for pin in pins {
let trigger_status = &mut self.trigger_status[pin.pin() as usize];
if trigger_status.triggered {
trigger_status.triggered = false;
return Ok(Some((pin, trigger_status.level)));
}
}
if let Some(t) = timeout {
if now.elapsed() > t {
return Ok(None);
}
}
}
}
pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
let trigger_status = &mut self.trigger_status[pin as usize];
trigger_status.triggered = false;
if let Some(ref mut interrupt) = trigger_status.interrupt {
if interrupt.trigger != trigger {
self.poll.delete(interrupt.fd())?;
interrupt.set_trigger(trigger)?;
self.poll
.add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
}
return Ok(());
}
let interrupt = Interrupt::new(self.cdev_fd, pin, trigger)?;
self.poll
.add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
trigger_status.interrupt = Some(interrupt);
Ok(())
}
pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
let trigger_status = &mut self.trigger_status[pin as usize];
trigger_status.triggered = false;
if let Some(interrupt) = trigger_status.interrupt.take() {
self.poll.delete(interrupt.fd())?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct AsyncInterrupt {
poll_thread: Option<thread::JoinHandle<Result<()>>>,
tx: EventFd,
}
impl AsyncInterrupt {
pub fn new<C>(fd: i32, pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
where
C: FnMut(Level) + Send + 'static,
{
let tx = EventFd::new()?;
let rx = tx.fd();
let poll_thread = thread::spawn(move || -> Result<()> {
let poll = Epoll::new()?;
poll.add(rx, rx as u64, EPOLLERR | EPOLLET | EPOLLIN)?;
let mut interrupt = Interrupt::new(fd, pin, trigger)?;
poll.add(interrupt.fd(), interrupt.fd() as u64, EPOLLIN | EPOLLPRI)?;
let mut events = [epoll_event { events: 0, u64: 0 }; 2];
loop {
let num_events = poll.wait(&mut events, None)?;
if num_events > 0 {
for event in &events[0..num_events] {
let fd = event.u64 as i32;
if fd == rx {
return Ok(()); } else if fd == interrupt.fd() {
let level = interrupt.event()?.level();
callback(level);
}
}
}
}
});
Ok(AsyncInterrupt {
poll_thread: Some(poll_thread),
tx,
})
}
pub fn stop(&mut self) -> Result<()> {
self.tx.notify()?;
if let Some(poll_thread) = self.poll_thread.take() {
match poll_thread.join() {
Ok(r) => return r,
Err(_) => return Err(Error::ThreadPanic),
}
}
Ok(())
}
}
impl Drop for AsyncInterrupt {
fn drop(&mut self) {
if !thread::panicking() {
let _ = self.stop();
}
}
}