-
Notifications
You must be signed in to change notification settings - Fork 214
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
IoPin trait not practical to implement with multiple input/output types #340
Comments
There's one in stm32f4xx-hal. I agree the trait is quite unwieldy, yes: https://github.com/stm32-rs/stm32f4xx-hal/blob/dc1552b2fc2e14901203a13ab42e76a5121a08eb/src/gpio.rs#L574-L683 It also feels strange to me Also, taking I wonder if it'd be better to have a trait for a pin that you can switch at runtime without changing type. /// A pin that can switch between input and output modes at runtime
pub trait IoPin: InputPin + OutputPin {
/// Configures the pin to operate in input mode
fn as_input(&mut self);
/// Configures the pin to operate in output mode
fn as_output(&mut self)
} |
this seems preferable to me, maybe with i tried to do some trickier type-based stuff but, i think there's elegance in this simplicity |
I've run into some difficulties with Initially I implemented the struct (simplified) as pub struct Device<E, P>
where
E: core::fmt::Debug,
P: InputPin<Error = E> + OutputPin<Error = E>,
{
pin: P,
} But then while using I've switched to (again, simplified): pub struct Device<E, IP, OP>
where
E: core::fmt::Debug,
IP: InputPin<Error = E> + IoPin<IP, OP, Error = E>,
OP: OutputPin<Error = E> + IoPin<IP, OP, Error = E>,
{
pin: Option<OP>, // need to use Option so I can easily pull the pin out of the struct to change its mode
} And then using it looks something like this: impl<E, IP, OP> Device<E, IP, OP>
where
... // stuff
{
pub fn read<D: Delay<Error = E>>(&mut self, delay: &D) -> Result<Reading, MyError<E>> {
let mut pin = self.pin.take().unwrap();
pin.set_low()?;
delay.delay_us(500)?;
pin.set_high()?;
delay.delay_us(500)?;
let pin = pin.into_input_pin()?;
let reading = {
// a bunch of `is_high()` and `is_low()` and delays that builds some sort of sensor reading
};
let pin = pin.into_output_pin()?;
self.pin = Some(pin);
Ok(reading)
}
} Ok, so on the face of it that's not terrible, but what happens if there is an error anywhere? Welp, the pin gets dropped and is now gone for good, and if someone calls I think the proposed alternative in #340 (comment) is nice from the perspective of simplicity, but the big downside is that the trait IoPin<E, TInput, TOutput>
where
E: core::fmt::Debug,
TInput: InputPin<Error = E>,
TOutput: OutputPin<Error = E>,
{
type Error: core::fmt::Debug;
fn as_input_pin(&self) -> Result<TInput, E>;
fn as_output_pin(&self) -> Result<TOutput, E>;
} The idea here is that the two fn as_input_pin<'a>(&'a mut self) -> Result<&'a TInput, E>;
fn as_output_pin<'a>(&'a mut self) -> Result<&'a mut TOutput, E>; The idea there would be to keep the mutable borrow on the |
393: Remove IoPin r=eldruin a=Dirbaio As discussed in #340 it's unclear if the current IoPin trait is the best way to go (tldr: due to the fact it changes type it's hard to own it in driver structs). I propose temporarily removing it, to unblock the 1.0 release. When discussion settles on a final design, we can add it back. Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
I also have doubts about
I know it now got removed for |
I've tried to implement a HAL based drive once and stuck into an issue that some MCU (AVR for example) are not supporting open/drain pins and similar stuff. But still you could communicate with some sensors via single pin by simply switching between input/output modes like it done for Arduino (see DHT11 DHT22). In order to do it using HAL I need to have some interface that would not consume itself while toggling between input/output. The thing here is that implementing |
The IoPin trait - added in #29, seems like it would be impractical to implement in a system with multiple input / output pin types. The STM32 HALs that I'm familiar with (g0, l4, h7) use different types for OpenDrain and PushPull pin types. Because IoPin is parameterized on both input and output pin types, it appears that you would need to implement every combination NxM (where N is the number of input types and M is the number of output types).
Is there a reason why it's one trait rather than two? I guess having a single trait can be good if you want to construct a trait object - although I don't think you can do that in this case anyway, since the methods take self by value.
The only implementation I managed to find was in linux-embedded-hal which seems to only have a single type for pins.
The text was updated successfully, but these errors were encountered: