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

dio: Make digital PWM RAII #69

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

auscompgeek
Copy link
Member

No description provided.

@auscompgeek auscompgeek mentioned this pull request Jul 14, 2019

/// Set the PWM rate for digital PWM outputs, from 0.6Hz to 19kHz.
/// All digital channels will use the same PWM rate.
/// Will return an error if PWM has not been enabled.
Copy link
Collaborator

Choose a reason for hiding this comment

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

With the handle, isn't it always enabled?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point. I probably forgot to remove this when moving things around.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually re-reading this, this doesn't take a handle, so this comment is correct.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't this method only usable on a DigitalPwm, which will alwys have PWM enabled?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is an associated function, not a method.

@Lytigas
Copy link
Collaborator

Lytigas commented Nov 11, 2019

I like the idea, but I think the borrowing creates a unwieldy interaction with borrowck.

struct PWMMechanism<'a> {
    dio: DigitalOutput,
    pwm: DigitalPwm<'a>,
}

impl<'a> PWMMechanism<'a> {
    fn new(port: i32) -> Self {
        let mut d = DigitalOutput::new(port).unwrap();
        let p = d.enable_pwm(0.5).unwrap();
        Self { dio: d, pwm: p }
    }
}
error[E0515]: cannot return value referencing local variable `d`
  --> wpilib-examples/./digital_pwm.rs:20:9
   |
19 |         let p = d.enable_pwm(0.5).unwrap();
   |                 - `d` is borrowed here
20 |         Self { dio: d, pwm: p }
   |         ^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `d` because it is borrowed
  --> wpilib-examples/./digital_pwm.rs:20:21
   |
16 | impl<'a> PWMMechanism<'a> {
   |      -- lifetime `'a` defined here
...
19 |         let p = d.enable_pwm(0.5).unwrap();
   |                 - borrow of `d` occurs here
20 |         Self { dio: d, pwm: p }
   |         ------------^----------
   |         |           |
   |         |           move out of `d` occurs here
   |         returning this value requires that `d` is borrowed for `'a`

error: aborting due to 2 previous errors

I think a better solution would be to have enable_pwm take ownership, and return a Result<DigitalPWM, (Err, DigitalOut)>. The DigitalPWM (name tbd) struct has the functionality in that state, and a downgrade method back to DigitalOut.

wpilib/src/dio.rs Outdated Show resolved Hide resolved
@auscompgeek
Copy link
Member Author

Note to self: add some sort of test to ensure using this actually compiles.

@@ -106,37 +93,19 @@ impl DigitalOutput {
}

/// Enable PWM for this output.
pub fn enable_pwm(&mut self, initial_duty_cycle: f64) -> HalResult<()> {
pub fn enable_pwm(self, initial_duty_cycle: f64) -> HalResult<DigitalPwm> {
Copy link
Collaborator

@Lytigas Lytigas Nov 13, 2019

Choose a reason for hiding this comment

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

With this API, in the case of a failure, the DIO is lost. I'm not sure if its possible to recover here, or if it's worth trying, but if it is recoverable we could return Result<DigitalPWM, (HalError,Self)> or something similar.

Copy link
Member Author

Choose a reason for hiding this comment

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

Such a Result would make it difficult to Try.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree, but in a realistic usecase where you want to recover from a failed upgrade, this API requires you to recreate the DigitalOut. Using ? requires just .map_err(|(e, _p)| e), which we can put in an example.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm struggling to find a good reason to recover from an error in this scenario though. What would you do in such a scenario? The Nidec Brushless requires a DIO pin in PWM mode, for example.

Copy link
Collaborator

@Lytigas Lytigas Nov 14, 2019

Choose a reason for hiding this comment

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

In the general case of a hardware output failure, you basically have two options:

  1. Retry Later
  2. Abandon and restart
  3. Ignore it and carry on running your robot

The failure mode in which 1. could be useful is possible resource exhaustion *status = NO_AVAILABLE_RESOURCES; in HAL_AllocateDigitalPWM.

It's also more conducive to dependency injection. Say I get a DigitalOutput injected; I don't know it's port. How do I recover from this error? Maybe I just wanted to try using PWM if it's available. If I only want to use PWM sometimes, I'd like to keep my DigitalOutput around for other use.

These use cases / failure modes are unlikely enough that I'm willing to merge it either way, but that's my perspective.

wpilib/src/dio.rs Outdated Show resolved Hide resolved

/// Set the PWM rate for digital PWM outputs, from 0.6Hz to 19kHz.
/// All digital channels will use the same PWM rate.
/// Will return an error if PWM has not been enabled.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't this method only usable on a DigitalPwm, which will alwys have PWM enabled?

@auscompgeek auscompgeek force-pushed the raii-dio-pwm branch 2 times, most recently from 3561b77 to 52a35da Compare December 23, 2019 03:30
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

2 participants