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

Move reading functions from OutputPin trait to StatefulOutputPin #72

Merged
merged 4 commits into from
May 12, 2018

Conversation

astro
Copy link
Contributor

@astro astro commented Apr 7, 2018

As it has come up in #29, here is a proposal for removing the burden of caching the state on implementations that cannot read it from an output pin.

Copy link
Contributor

@therealprof therealprof left a comment

Choose a reason for hiding this comment

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

I'm very much in favour of this change but I'd like a second opinion about how we're going to do this.

Also are you planning to follow up with the additional traits?

@astro
Copy link
Contributor Author

astro commented Apr 7, 2018

Also are you planning to follow up with the additional traits?

See #73. StatefulOutputPin looks good to me. Is there any shorter name for it?

@astro
Copy link
Contributor Author

astro commented Apr 7, 2018

Please refresh your browser, I edited my comment several times. :) Sorry!

I think this and #73 are separate problems. You can implement StatefulOutputPin (which I pushed later) without switching modes.

@therealprof
Copy link
Contributor

Err, yes, my bad, the comment was really meant for #73. Let me move it there.

@astro astro changed the title Remove reading functions from OutputPin trait Move reading functions from OutputPin trait to StatefulOutputPin Apr 7, 2018
Copy link
Member

@hannobraun hannobraun left a comment

Choose a reason for hiding this comment

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

Looks good to me! Thank you, @astro.

Copy link
Contributor

@therealprof therealprof left a comment

Choose a reason for hiding this comment

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

I'd prefer having the composable traits instead of a composed trait but it is better than what we have now so I'm good with it.

The only problem I see is that this might potentially break existing implementations?

@hannobraun
Copy link
Member

@therealprof

The only problem I see is that this might potentially break existing implementations?

As I stated before elsewhere, I don't think we should be losing sleep over backwards-compatibility at this point. Yes, breaking implementations sucks, but I'm more concerned about whether embedded-hal is going to look good a few years from now.

@therealprof
Copy link
Contributor

@hannobraun That's fine with me, too. Just wanted to raise the concern others might have to feel whether there's consensus on that topic.

@austinbes
Copy link

FWIW, I'm totally of @hannobraun's opinion. Break things early, if they're to break at all

src/digital.rs Outdated
/// Is the pin set to low?
fn is_set_low(&self) -> bool;

/// Toggle pin output
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry if I am late to the party. Can you override a method in a trait? On some cores toggle is exposed as a separate register / no read state is required.

I'd propose having the toggle as a separate trait that you can implement on StatefulOutputPin if toggle function is not available.

Copy link
Contributor

Choose a reason for hiding this comment

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

As discussed in #31 (et al) I also think that different capabilities should be modelled in different composable (and mode dependent) traits instead of being munged together into a few traits that do a lot of things at once. Something like is_set_low() on a StatefulOutputPin is not clear what it actually means, i.e. is that supposed to be the electrical or the logical state of the pin? For toggle() it has to be the latter, not the former, in other cases you might want to have the electrical state, though and cannot have this. Also (as you said) there are implementations allowing an efficient toggle without reading the logical state from a pin. There might even be implementations which do not allow you to read back the logical state, although I don't recall any from the top of my head.

I only agreed to moving it out of OutputPin because it belongs there even less and this change turns into into an unproven functionality so if it doesn't provide the hoped for benefit (as I suspect it will not) then we can replace it by something better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds reasonable. I'll remove it in favour of adding ToggleableOutputPin later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you override a method in a trait?

@ryankurte Yes, you can.

@astro
Copy link
Contributor Author

astro commented Apr 12, 2018

I have moved toggle() into a separate ToggleableOutputPin trait with a default impl for StatefulOutputPin.

Also, I removed the OutputPin constraint from StatefulOutputPin as it is now optional and possible for theoretical output pins from which you can read but not write the state (eg. set by hardware).

src/digital.rs Outdated
/// toggleable by software. You may override the `toggle()` method
/// with a hardware implementation.
#[cfg(feature = "unproven")]
impl<PIN: OutputPin + StatefulOutputPin> ToggleableOutputPin for PIN {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be good to add an empty DefaultToggle trait here, and thus make this implementation opt-in rather than opt-out?

It would match the way the blocking SPI traits are handled. On the other hand, this is a simpler implementation.

I'm not particularly attached to one way or the other, but I do think consistency throughout the embedded-hal will be valuable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion. I added that now by copying the style of the opt-in default traits in spi and serial. I hope that the doc example is helpful.

@astro astro force-pushed the rm-read-from-outputpin branch 3 times, most recently from b47006d to 2fd1a3a Compare April 12, 2018 17:37
@astro
Copy link
Contributor Author

astro commented Apr 29, 2018

Is there anything I can do to help this move forward?

/// Sets the pin low
fn set_low(&mut self);

/// Sets the pin high
fn set_high(&mut self);
}

/// Output pin that can read its output state
Copy link
Contributor

Choose a reason for hiding this comment

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

As I've mentioned before there's a distinction between a logical state and an electrical state. It should be made clear that this is meant to represent the logical (or register) state of a pin and not the electrical state.

/// Output pin that can read its output state
#[cfg(feature = "unproven")]
pub trait StatefulOutputPin {
/// Is the pin set to high?
Copy link
Contributor

Choose a reason for hiding this comment

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

A pin could also be logically floating so either it needs to be made clear that a tri-stated pin may not implement this trait or that the implicit assumption p.is_set_high() == !p.is_set_low() does not necessarily hold and should not be assumed.

@japaric
Copy link
Member

japaric commented May 11, 2018

This seems OK to me but it should be explicitly noted that these traits should be implemented only for push pull output pins and that low / high are referring to the electrical output of the pin. That was missing in the original trait as well.


@hannobraun just for the record: releasing a new minor version doesn't "just breaks implementations"; it fragments the ecosystem. Once a HAL implementation moves from e.g. v0.1.x to v0.2.x it can no longer be used with driver crates that depend on embedded hal v0.1.x. This happens even if the trait that the driver crate uses as a bound has not changed at all between the two minor releases. This situation increases the maintenance work of driver authors which now have to publish a new minor version of their crate that supports the new embedded-hal and probably will also have to maintain the v0.1.x version until all / most-of the existing / active / maintained HAL implementations move to v0.2.x. So bumping the minor version shouldn't be done often / lightly; as the embedded-hal ecosystem grows we'll have to allow more "settling time" between each new minor version release.

That being said we have to make a new minor version release beacuse of #80 so let's include this PR which also contains breaking changes in v0.2.0. @astro could you update the docs?

@therealprof
Copy link
Contributor

that low / high are referring to the electrical output of the pin.

I disagree. We can not make any assumption of the electrical state of a pin, only the logical state. Even if you drive it low on a push/pull pin there might be a stronger source keeping it high and vice versa.

@japaric
Copy link
Member

japaric commented May 12, 2018

@therealprof point taken

I'll merge this PR as it is and adjust the docs locally before releasing v0.2.0. Thanks for the PR, @astro!

bors r+

@bors
Copy link
Contributor

bors bot commented May 12, 2018

👎 Rejected by code reviews

@japaric
Copy link
Member

japaric commented May 12, 2018

bors r+

@bors
Copy link
Contributor

bors bot commented May 12, 2018

👎 Rejected by code reviews

@japaric japaric dismissed therealprof’s stale review May 12, 2018 18:28

docs will be updated in a follow up commit

@japaric
Copy link
Member

japaric commented May 12, 2018

bors r+

bors bot added a commit that referenced this pull request May 12, 2018
72: Move reading functions from OutputPin trait to StatefulOutputPin r=japaric a=astro

As it has come up in #29, here is a proposal for removing the burden of caching the state on implementations that cannot read it from an output pin.

Co-authored-by: Astro <[email protected]>
@bors
Copy link
Contributor

bors bot commented May 12, 2018

Build succeeded

@bors bors bot merged commit 6549d73 into rust-embedded:master May 12, 2018
@hannobraun
Copy link
Member

@japaric

just for the record: releasing a new minor version doesn't "just breaks implementations"; it fragments the ecosystem.

Good point, thanks for the explanation. While that doesn't change my stance about breaking changes in general, it's good to keep in mind that we need to release them strategically.

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.

8 participants