-
Notifications
You must be signed in to change notification settings - Fork 49
Implement Observable POC #157
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
Conversation
src/observable.rs
Outdated
pub trait IntoObservationToken: Sized + crate::Sealed { | ||
type Peripheral; | ||
fn into_ot(self) -> ObservationToken<Self::Peripheral>; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to do this since we can not do this due to the trait impl rules
impl<T: Observable> Into<ObservationToken<T>> for T {
fn into(self) -> ObservationToken<T> {
ObservationToken {
_p: PhantomData
}
}
}
do you know if there is a better way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The most recent version of this concept (with a few name changes and being used in a brand new context) is here. The simple solution to this is to implement From
rather than Into
. This is a good idea in general (save some rare edge cases).
impl<P> From<P> for ObservationToken<P>
where
P: Observable,
{
fn from(_: P) -> Self {
Self { _p: PhantomData }
}
}
Another option - which eliminates the need for calling .into()
to directly pass a peripheral as an observation token - is to create a new trait called ObservationLock
which is implemented by all P: Observable
and ObservationToken
s. Interfaces would thus hold impl ObservationLock
s rather than concrete ObservationToken
s. This is described in this gist.
The former is a solution I am putting to use right now in proto-hal, the latter I suspect is a better solution, but have not implemented quite yet.
Hope this helps!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the ObservationLock
trait is unneeded since the interfaces can accept an Into<ObservationToken<P>>
. Clever!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want the user to be able to destruct the consumer of the ObservationToken
how does this affect things?
If the user passed an actual owned peripheral than would it not be best to just not convert it and let the consumer store the peripheral as is until it is destructed?
In that case would ObservationLock
make more sense since that better signals what we are doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes! That was why ObservationLock
was good. Since the peripherals would store an impl ObservationLock
, the release()
would return back whatever was originally passed in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The former is a solution I am putting to use right now in proto-hal
Very interesting!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! Have you run any integration tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every occurrence of P
should be P: Observable
.
examples/comp_w_dac.rs
Outdated
@@ -59,7 +61,7 @@ fn main() -> ! { | |||
// * 0V at p1 => 0% duty | |||
// * VDDA at p1 => 100% duty | |||
loop { | |||
dac.set_value(val); | |||
dac.as_mut().set_value(val); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we even go as far as implementing Deref{Mut}
for Observed
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, Deref
will be a really good QoL feature.
Thanks :) No, no tests at all yet |
src/adc.rs
Outdated
impl Channel<stm32::$adc> for $pin { | ||
impl<P> Channel<stm32::$adc> for P | ||
where P: stasis::EntitlementLock<Resource = $pin> | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not work. Both Channel
and EntitlementLock
(or rather P
i suppose) are from outside this crate. There are also errors about conflicting implementations with the other opamps below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the simplest solution is to make a local trait like AdcChannel
which requires embedded_hal::adc::Channel
and then it would work.
I'm not very familiar with what you're doing here though. I'll think on it.
You could also do concrete implementations since this is macro generated anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also do concrete implementations since this is macro generated anyway.
Yeah that would probably be the simplest solution. I'll give it a go
@burrbull do you have any thoughts on this as a concept? TLDR(please @AdinAck correct me where I am wrong here): There are several cases where it is useful to have multiple observers of the same resource while preventing one observer from reconfiguring the resource in a way not compatible with the others. For example a gpio pin may be "observed" by a comparator while still being usable for AD readings at the same time. However we want to prevent the user from reconfiguring the pin to something other than Analog mode. Another example would be a Dac. We want it to be observable from the comparator and/or opamp while we still have access to change its output. This proposes to solve this by introducing a trait By recombining all |
You are exactly right! Additional background: this is exactly what references are, the compiler just automatically tracks the "recombination" (dropping of references) and forbids moving or dropping the resource if a reference to it exists. We are electing not to use references for two reasons:
The drawbacks of this approach is we need to explicitly dispatch "entitlements" which are our reference analog, and explicitly recombine them, which is a bit of a hassle. |
ffa9af6
to
fcfef77
Compare
@AdinAck do you have any suggestions for how to move forward with this? Are you planning to release your stasis thing so we can depend on it from stm32g4xx-hal (and later I would probably want to use it for usbalbin/stm32-hrtim too). Or do you think I should have a local copy in stm32g4xx-hal for now? :) |
I am still actively developing proto-hal and haven't reached a stable release point yet, so I wouldn't want my changes to affect you. I think a local copy makes sense, for now :) |
Makes sense, thanks Is it ok if I copy your stasis.rs? 8df2caf |
Yep! |
Awesome! Thank you! |
copy proto-hal/src/stasis.rs from https://github.com/AdinAck/proto-hal/tree/main Add `Ad` wrapper around ADC-type in Channel and OneShot impl to avoid problems with orphan rule" Co-authored-by: Adin Ackerman <adinackerman@gmail.com>
917d672
to
f1b56df
Compare
@@ -0,0 +1,316 @@ | |||
#![no_std] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! Have you run any integration tests?
I have now added some more tests. These ones require a jumper(I took the one at CN12 at the top left corner) when using a Nucleo-G474 between A1 and A2. But I do believe that single modification opens up for some pretty interesting self tests
Alternative to #138
@AdinAck is this somewhere close to what you discribed in #138 ?
TODO