rust-embedded/gpio-cdev

Non-blocking polling of events

svenvdvoort opened this issue · 2 comments

Hello,

Thank you for providing us with this wonderful library!
A missing feature of this library to me is the ability to do a non-blocking poll on the LineEventHandle struct.
Currently every method (.get_event(), .next() and .read_event()) is blocking.
Ideally we would have a sort of .has_event() -> bool function available to check whether there is an event available to process. This way we would take maximum advantage of the queue-like architecture of the new GPIO character device ABI.

Please let me know what you think of this suggestion.

Cheers,
Sven.

hmm is this for async or sync use? in the async case would .poll_next() per the standard stream implementation work?

in the blocking case this seems like it could be useful, perhaps a .try_get_event() -> Option<bool> or similar?

Hi,
I do not know how @svenvdvoort plans to use, but I am searching to someway impletent a timeout for the .read_event():
a process starts a request for a GPIO interaction from the user and, if there is no input for a Duration, the code continues with a timeout.
I tried this with select!, but the result was very unstable.

pub async fn confirma_giro(&self, timeout: Duration) -> LeitorResult<()> {
    let _handle_confirm = match self.gpio_confirm.events(
        gpio_cdev::LineRequestFlags::INPUT,
        gpio_cdev::EventRequestFlags::FALLING_EDGE,
        &(self.sentido.to_string() + "_GPIO_CONFIRM"),
    ) {
        Ok(value) => value,
        Err(e) => return Err(LeitorError::GPIO { kind: e }),
    };

    let timeout = async {
        thread::sleep(timeout);
    };

    let giro = Box::pin(async {
        // *** Aguarda o sinal chegar ao estado desligado
        match _handle_confirm.get_value() {
            Ok(sinal) => {
                if sinal != SIGNAL_OFF {
                    return Err(LeitorError::ConfirmaGiroIncorreto);
                }
            }
            Err(e) => return Err(LeitorError::GPIO { kind: e }),
        };

        if let Ok(_e) = _handle_confirm.get_event() {
            thread::sleep(Duration::from_millis(100));

            if let Ok(sinal) = _handle_confirm.get_value() {
                if sinal == SIGNAL_ON {
                    return Ok(());
                }
            }
            return Err(LeitorError::SinalInstavel);
        }
        Err(LeitorError::ConfirmaGiroIncorreto)
    });

    select! {
        resp = giro.fuse() => resp,
        _out = timeout.fuse() => Err(LeitorError::TimeOut),
    }
}