Git Product home page Git Product logo

gpio-cdev's People

Contributors

bors[bot] avatar dfrankland avatar dirreke avatar drinkdhmo avatar eldruin avatar fpagliughi avatar hellow554 avatar jodal avatar kmdouglass avatar lovasoa avatar m-ou-se avatar mgottschlag avatar mpi3d avatar oll3 avatar posborne avatar stefan-muc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gpio-cdev's Issues

How to do monitor for an event on more than one input?

How do you extend the gpioevents.rs example to handle multiple input pins using event handlers?

EDIT: To clarify, I don't really want to have to follow the poll methodology in monitor.rs as polling IO pins is inefficient and prone to missing changes in IO state.

-Andy.

Error: "There is no reactor running, must be called from the context of a Tokio 0.2.x runtime" from tokio::task::spawn

I am fairly new to Rust, and particularly to embedded Rust, so there's a good chance this is just my mistake.
I am running the following:

#[tokio::main]
async fn main() {
    let mut chip = Chip::new("/dev/gpiochip0").unwrap();
    let line = chip.get_line(10).unwrap();
    let _trigger_task = tokio::task::spawn(async move {
        let mut events = AsyncLineEventHandle::new(line.events(LineRequestFlags::INPUT, EventRequestFlags::FALLING_EDGE, "input_trigger").unwrap()).unwrap();
        while let Some(_event) = events.next().await {
            println!("Trigger");
        }
    }
    );
}

And it panics with:
There is no reactor running, must be called from the context of a Tokio 0.2.x runtime.

I replaced the code inside the closure with a simple print statement, and it worked fine suggesting the issue is in the GPIO stuff.
Am I just being stupid? I would really appreciate any help!

Seeming deadlock on select!

Hello,

When using the following snippet in my code (as part of a Wiegand reader program) on a Raspberry Pi 0:

let monitor_0: Next<AsyncLineEventHandle> = events0.next();
let monitor_1: Next<AsyncLineEventHandle> = events1.next();

pin!(monitor_0, monitor_1);

select! {
    res = monitor_0 => { data = data << 1; },
    res = monitor_1 => { data = (data << 1) | 1 as u64; },
}

it seems like the code ends up in a Deadlock in the select! macro after running this snippet for 128 times, after which the program uses 100% CPU but neither of the Nexts ever completes.

events0 and events1 are AsyncLineEventHandles that come from Lines that come from the same Chip.

Introducing a millisecond delay at the very top increases the amount of bytes that can be read to 256.

Introducing a larger delay seems to remove the deadlock all together, but the ordering of the events is lost causing the data to become garbage as the order of the events determines the final data output.

I'm not certain if this is a gpio-cdev problem, a kernel problem, or if I'm simply doing this incorrectly.

Any feedback is highly appreciated.

Version 0.2 is not on crates.io

Installation instructions in the readme uses version 0.2, but it looks like 0.2 is not published on crates.io

    Updating crates.io index
error: failed to select a version for the requirement `gpio-cdev = "^0.2"`
  candidate versions found which didn't match: 0.1.0
  location searched: crates.io index

Multi-bit access

Hi! Do you have a plan, in the near future, to implement the access of multiple bits simultaneously? If not, do you want me to take a crack at it? I'm going to need this within the next few weeks.

Replace error-chain with std::error::Error

Impossible to use anyhow with gpio-cdev:

error[E0277]: `(dyn std::error::Error + std::marker::Send + 'static)` cannot be shared between threads safely
 --> src/main.rs:9:52
  |
9 |     let mut chip = gpio_cdev::Chip::new(RELAY_CHIP)?;
  |                                                    ^ `(dyn std::error::Error + std::marker::Send + 'static)` cannot be shared between threads safely
  |
  = help: the trait `std::marker::Sync` is not implemented for `(dyn std::error::Error + std::marker::Send + 'static)`
  = note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<(dyn std::error::Error + std::marker::Send + 'static)>`
  = note: required because it appears within the type `std::boxed::Box<(dyn std::error::Error + std::marker::Send + 'static)>`
  = note: required because it appears within the type `std::option::Option<std::boxed::Box<(dyn std::error::Error + std::marker::Send + 'static)>>`
  = note: required because it appears within the type `error_chain::State`
  = note: required because it appears within the type `gpio_cdev::errors::Error`
  = note: required because of the requirements on the impl of `std::convert::From<gpio_cdev::errors::Error>` for `anyhow::Error`
  = note: required by `std::convert::From::from`

Remove error-chain and manually implement an error type.

As discussed in #24

This would remove a dependency and give end users of the library more flexibility to handle errors how they wish.

error-chain is going to be deprecated in any case.

The new error type should endeavor to play nicely with failure without having a direct dependency on it.

Please include Async documentation on docs.rs

There is no mention of AsyncLineEventHandle anywhere on docs.rs. The only way to see this documentation is to build it locally with cargo doc, which is a bit of a pain, especially since many of the people using gpio-cdev are working on a raspberry pi, and if they are running the lite version of Raspbian, without a GUI, as I am, there is no browser, so cargo doc --open won't work. We need to manually go in and copy the docs directory to a different computer to read it.

When I did cargo doc on my project, it generated 16k files. Using scp to copy them over to my other computer was going to take like half an hour. I had to interrupt the scp copy operation, tar the 16k of doc html files, transfer it as one file, and unarchive it before opening it. The whole process took like 20 minutes. It would have been nice if I could have just found the documentation on docs.rs in seconds, as I do with most other documentation.

Please remove `backtrace` and `libc` dependency

Great library! It got me up and running on the new chardev gpio devices which was fantastic. I've been experimenting with using Rust on Linux SBCs. However the library isn't suitable for cross compiling currently; would it be possible to remove the extra C library dependencies?

My embedded device build system uses cross compiling for everything and the backtrace dependency (via both the error-chain and clap dependencies) makes cross compiling a pain. To get it to function correctly you have to use an obscure environment variable CARGO_TARGET_$(TRIPLET)_LINKER= to setup the appropriate cross linker.

Effectively the addition of a C library in the Rust toolchain eliminates almost all of the advantages of using Rust. It add unnecessary complications in a cross compiling scenario as now I have 2 more compilers settings to get correct (the Rust one, and the c compiler). Is it possible to remove the backtrace or use a Rust native one?

Servo example?

Want to say thanks to the team behind this library, but as a newbie to embedded programming how do i use this to control a servo?

Represent line levels as a bool

I know the char driver(s) expose bits as u8 values, but it might be easier to manipulate the values as booleans. Should we consider:

impl LineHandle {
    pub fn get_value(&self) -> Result<bool> { ... }
    pub fn set_value(&self, value: bool) -> Result<()> { ... }
    ...

Update to Tokio 1

Tokio 1 with long stability guarantee is out. It would be nice if at some point gpio-cdev updates to this version.

LineEventHandle drops events

LineEventHandle seems to be dropping events, as evident in the repro below, but also in a more optimized repro just filtering for FALLING_EDGES and knowing the min/max rate that these events are emitted, versus the actual interval between events.

Repro

The following snippet run on a Raspberry Pi Zero (ARM32).

for e in Chip::new("/dev/gpiochip0")?
            .get_line(pin)?
            .events(
                LineRequestFlags::INPUT,
                EventRequestFlags::BOTH_EDGES,
                "read",
            )? {
    println!("{}", e.event_type());
}

Observed

LineEventHandle yields multiple events of the same type in sequence.

Expected

LineEventHandle strictly alternates between each type.

New release?

It has been 2 years since it released last time. Could we make a new release?

gpio-cdev = { version = "0.3", features = ["async-tokio"] } fails

Create a new project foo with gpio-cdev as a dependency with the async-tokio feature.

[dependencies]
gpio-cdev = { version = "0.3", features = ["async-tokio"] }

This gives us an error

... the package `foo` depends on `gpio-cdev`, with features: `async-tokio` but `gpio-cdev` does not have these features.

No /dev/gpiochip0 on Artik 530s

I want to use this driver to see if it is more performant than sysfs. The one problem I'm running into is there is no gpiochip0 listed under /dev.

How do I add gpiochip0 to /dev so I can start using this library?

Thanks so much for all your hard work and help! Go rust!

no method named `get_lines`

I'm trying to follow the mutliread.rs example but when I try to compile it then I get the following error:

error[E0599]: no method named get_lines found for type std::result::Result<gpio_cdev::Chip, gpio_cdev::errors::Error> in the current scope

I'm new to Rust so don't know exactly what I am doing and why this is going wrong!

-Andy.

Example for async multiread

Could an example be shown for doing an async multiread? I don't see a lot of things i can do with get_lines such as events() and events_async()

Non-blocking polling of events

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.

Is kernel event queueing per-process?

Just looking for a bit of clarification here.

From what I understand, this is how it works:

  • When a GPIO pin's state changes (a button is pressed, or whatever), the CPU gets an interrupt, and the kernel is notified
  • The kernel checks if anyone is registered to be alerted of that pin's state change
  • If so, they have a dedicated queue that the event will be added to

Importantly, this queue is per-process.
As in, when our Rust application starts up, and uses gpio_cdev to register to be notified about a pin state change with:

let handle = chip.get_line(N)?.request(LineRequestFlags::INPUT, 0, "read-input")?;

The kernel sets up a queue specifically for this process, for this one line.

The alternative, which I'm really hoping isn't the case, is that there's one queue per line that the kernel maintains, and when your Rust application starts, and registers to be notified, the queue may already have events in it that may potentially need to be discarded.

Control the mode or peripheral function aka alternate mode of GPIO PINs.

Is it possible to use gpio-cdev to change the peripheral function of a GPIO PIN?

For context, I'm using gpio-cdev on a Raspberry PI to turn GPIO PIN 2 into output mode and send a wake pulse to a chip connected via I2C. Unfortunately, calling chip.get_line(2).request(LineRequestFlags::OUTPUT, 1, "test") changes the mode of the GPIO PIN to output and I have not yet found a way of "resetting" the PIN to its original state after completing the wake pulse.

I found, however, I can reset it manually from the command line using sudo raspi-gpio set 2 a0 but I was wondering if the same could be accomplished from within gpio-cdev or if it could be extended to allow for that.

Fix CI

CI is currently broken, also we need to migrate to GitHub MQ.
See #72

Version 0.3.0

Is there anything that needs doing before bumping the version?

Error using blocking iterator

Hi, I've successfully used the streaming interface using the request method:

fn do_main(args: Cli) -> errors::Result<()> {
    let mut chip = Chip::new("/dev/gpiochip7")?;
    let lines = vec![0, 1, 2, 3, 4, 5];
    let initial_values = vec![0; lines.len()];
    loop {
        let handle = chip.get_lines(&lines)?.request(
            LineRequestFlags::INPUT,
            &initial_values,
            "multiread",
        )?;
        println!("Values: {:?}", handle.get_values()?);
        thread::sleep(time::Duration::from_millis(10));
    }
}

When I try to use a blocking iterator however (see code below), I get the following error:
Error: Error(Msg("lineevent ioctl failed"), State { next_error: Some(Sys(ENODEV)), backtrace: InternalBacktrace { backtrace: None } }).

ENODEV would appear to be a device driver issue ("the corresponding device driver does not support the ioctl() function.") but I'm not clear on that.

Has anyone bumped into this issue before?

Failing code:

fn do_main(args: Cli) -> errors::Result<()> {
    let mut chip = Chip::new("/dev/gpiochip7")?;
    let input = chip.get_line(0)?;

    // Show all state changes for this line forever
    for event in input.events(
        LineRequestFlags::INPUT,
        EventRequestFlags::BOTH_EDGES,
        "rust-gpio",
    )? {
        println!("{:?}", event?);
    }

    Ok(())
}

possible to target wasm32-wasi?

I think it would be amazing to be able to compile to WASM + WASI, so that we can compile code, that has only access to given devices. In my understanding, it should be possible, since /dev/gpiochipX are handled as files** and could be preopened via fs over WASI. I'm a total noob though, so I don't know if that's even possible.

Following, some interesing infos I've found:

  • I've seen examples from wasm3 runtime that use WASI with Arduinos by passing the needed functions into WASM.
  • WASI has no official support for hardware peripheral abstractions as derived from this WASI issue.
  • In this tutorial by wasmtime, they demonstrate how files or dirs can be passed into the WASM sandbox env

Currently building to target wasm32-wasi results in several errors.

** on Linux

Improve documentation about keeping LineHandles in scope

Hello!

First, thanks a lot for creating this crate and the work you put into it.

I have a small suggestion that could improve the documentation. Consider the following program which is a simplified version of the driveoutput.rs example:

use gpio_cdev::{Chip, LineRequestFlags};

fn main() {
    let mut chip = Chip::new("/dev/gpiochip0").unwrap();

    chip
        .get_line(4).unwrap()
        .request(LineRequestFlags::OUTPUT, 1, "set-pin").unwrap();
    
    println!("Press Enter to exit");
    let mut buf = String::new();
    ::std::io::stdin().read_line(&mut buf).unwrap();
}

This program compiles and does not panic, but seemingly does nothing as the pin remains in an unset state while the program waits on the user to press Enter. However, if we assign the LineHandle instance to a variable like this:

let _handle = chip
        .get_line(4).unwrap()
        .request(LineRequestFlags::OUTPUT, 1, "set-pin").unwrap();

Then the pin state is correctly set, presumably because the file descriptor contained inside the LineHandle doesn't immediately get dropped after request is called.

I think that it is important to note in the comments that the LineHandle needs to remain in scope or assigned to a persistent variable to prevent these sorts of "silent failures." It may be obvious in the above example, but in my case I do some initialization of the chip and store it inside a struct that is passed around; it took me about a day of debugging to realize that I needed initialize and store the LineHandle instance in addition to the Chip.

If you agree, then I will open a small PR to update the examples and docstrings to make note of this.

Ambiguity of Line.request()'s default arg polarity in light of ACTIVE_LOW outputs

Background

Line.request() accepts LineRequestFlags including ACTIVE_LOW. This inverts the polarity of the value in the LineHandle::get_value() and LineHandle::set_value() APIs to mean:

  • 0 -> inactive -> electrically high
  • 1 -> active -> electrically low

Problem

Line.request() also accepts a default argument which is currently documented as:

For an output, the default parameter specifies the value the line should have when it is configured as an output.

The polarity of this argument is not clear.

If I do this:

line.request(LineRequestFlags.ACTIVE_LOW, 0, "me");

does 0 mean:

  • inactive -> electrically high
  • electrically low

Somewhat related: #49

Lines.request fail at runtime

I've tried to run readall.rs example on orange pi zero, but app panicked with the message "panicked at 'index out of bounds: the len is 64 but the index is 64', .\gpio-cdev-0.2.0\src\lib.rs:766:13"
The problem is that Lines struct in my case contains more than 64(GPIOHANDLES_MAX) lines.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.