Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GPIO capability #406

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open

Conversation

Quantaly
Copy link

This work was completed for our Advanced Software Engineering course at Colorado School of Mines.

We've added a GPIO capability with an implementation for Raspberry Pi based on rppal. The interface supports basic digital input and output as well as PWM output. A video demonstrating this functionality is attached.

demo.webm

Quantaly and others added 30 commits May 30, 2023 12:05
Signed-off-by: Kai Page <[email protected]>
Signed-off-by: Kai Page <[email protected]>
Signed-off-by: Kai Page <[email protected]>
Signed-off-by: joeyvongphasouk <[email protected]>
Signed-off-by: brendan burmeister <[email protected]>
Signed-off-by: Kai Page <[email protected]>
Signed-off-by: joeyvongphasouk <[email protected]>
@Mossaka
Copy link
Member

Mossaka commented Jun 15, 2023

Hey @Quantaly ! Thanks for your contribution! This looks pretty awesome 💙

I will admit that I am not familiar with GPIO capability, but I noted that it will only be able to run on a Raspberry Pi. This is quiet a different capability than the ones we already have, which are mostly centered on the theme of wasi-cloud-core World proposal. On the other hand, this PR does add a optional compilation feature like all other capabilities so it won't affect any downstream projects that use only a subset of SpiderLightning's capabilities.

With that being said, I am happy to merge this to the main branch, but this does not indicate that it will be part of the wasi-cloud-core World proposal. In order to become part of that, you will need to present this idea to the WASI CG meeting and then we will discuss if it makes sense to be part of the bigger World.

Since this is a pretty big PR, I will do a quick pass of review today and then let's iterate through it. I noticed that the CI is failing, could you please help to fix it?

Copy link
Member

@Mossaka Mossaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly look good to me but admitted I didn't run this locally yet.

I left some comments and once they are ready, I am happy to do a round 2 review!

@@ -0,0 +1,38 @@
variant gpio-error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add some docs on this new WIT file? What are each resources represent, much like the pwm-output-pin resource.

let gpio: &mut dyn GpioImplementor = &mut gpio;
for config in [
"",
"some",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣

@@ -330,6 +335,16 @@ async fn build_store_instance(
linked_capabilities.insert("http-client".to_string());
}
}
#[cfg(feature = "gpio")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add at least one intergration test to this new capability so that it will be automatically tested in our CI/CD pipelines?

name = "slight-gpio"
version = "0.1.0"
edition = { workspace = true }
authors = { workspace = true }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add your names to the authors of this crate

Copy link
Collaborator

@danbugs danbugs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really solid – Thank you so much for the PR, folks! Awesome work!

I've just added some comments here and there, but nothing major.

Also, to fix our CI, you might want to run:

cargo clippy --fix --all
cargo fmt --all

- For output: initially set to `low` or `high`
- For PWM output: the PWM period in microseconds, if supported by the implementation

See the [example application](../../examples/gpio-demo/).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely not required to close this PR, but it might be helpful to add some comments to aid someone getting started w/ this capability – I have a Raspberry Pi at home like the one in your video, and would love to try using this (:

Comment on lines +107 to +113
Some(Ok(_)) => Err(gpio::GpioError::PinUsageError(format!(
"'{name}' is not an input pin"
))),
Some(Err(e)) => Err(e.clone()),
None => Err(gpio::GpioError::PinUsageError(format!(
"'{name}' is not a named pin"
))),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ties to my comment above about storing errors in the HashMap. I feel like a better look for this would only handle Some(<my_pin>), or None.

Comment on lines +125 to +132
Some(Ok(Pin::Output(pin))) => Ok(pin.clone()),
Some(Ok(_)) => Err(gpio::GpioError::PinUsageError(format!(
"'{name}' is not an output pin"
))),
Some(Err(e)) => Err(e.clone()),
None => Err(gpio::GpioError::PinUsageError(format!(
"'{name}' is not a named pin"
))),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

~same as above.

Comment on lines +145 to +153
match self.pins.get(name) {
Some(Ok(Pin::PwmOutput(pin))) => Ok(pin.clone()),
Some(Ok(_)) => Err(gpio::GpioError::PinUsageError(format!(
"'{name}' is not a PWM output pin"
))),
Some(Err(e)) => Err(e.clone()),
None => Err(gpio::GpioError::PinUsageError(format!(
"'{name}' is not a named pin"
))),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

~same as above.

let gpio: &mut dyn GpioImplementor = &mut gpio;
for config in [
"",
"some",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣

enable: func() -> unit
/// Disable the output signal.
disable: func() -> unit
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually, we'd first get a proposal for an interface, and then later move on to the implementation to allow for agreement over the interface prior to any work being done – That said, I think this is looking very solid. It'd be cool to be able to add some sort of pin event handling to be able to register callbacks or smt based on specific GPIO pin events, but callback support in WIT is very restricted.

Comment on lines +7 to +10
push_down_button = "17/input/pulldown"
led = "5/output"
pwm_control_button = "18/input/pullup"
pwm_led = "6/pwm_output"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that you're defining pin config. (i.e., pull-up/pull-down) directly in the string vars here. Have you considered baking this into some sort of structure within the interface?

Comment on lines +50 to +58
let pins = state
.configs_map
.map(|configs| {
configs
.iter()
.map(|(name, config)| (name.clone(), implementor.parse_pin_config(config)))
.collect()
})
.unwrap_or_else(HashMap::new);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, all pin usage is registered via the slightfile – Is there any usage to registering pins are runtime?

/// It must be [Send], [Sync], and [Clone].
#[derive(Clone)]
pub struct Gpio {
pins: HashMap<String, Result<Pin, gpio::GpioError>>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure we want to store possible errors in the HashMap? As a user, I'd rather fail at compile-time instead of trying to get my pin and failing at runtime.

@danbugs
Copy link
Collaborator

danbugs commented Sep 11, 2023

@Quantaly , @joeyvongphasouk , and @BrendanBurm ~ Is this something you are still interested in merging?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants