Skip to content

Commit 5f89197

Browse files
committed
docs/migration: document gpio change to &mut self.
1 parent bf488df commit 5f89197

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

docs/migrating-from-0.2-to-1.0.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [Fallibility](#fallibility)
1616
- [SPI transfer return type](#spi-transfer-return-type)
1717
- [Error type bounds](#error-type-bounds)
18+
- [GPIO traits now require `&mut self`](#gpio-traits-now-require-mut-self)
1819
- [Prelude](#prelude)
1920
- [Removed blanket implementations](#removed-blanket-implementations)
2021
- [Cargo Features](#cargo-features)
@@ -330,6 +331,95 @@ fn set_some_parameter(&mut self) -> Result<(), Self::Error> {
330331
}
331332
```
332333

334+
## GPIO traits now require `&mut self`
335+
336+
Methods on `InputPin` and `State` now take `&mut self` instead of `&self`, to allow implementations to
337+
have mutable state or access exclusive resources.
338+
339+
**For HAL implementors**: You should not need to do any changes, since `&mut self` is strictly more permissive
340+
for implementations.
341+
342+
For ease of use, you might want to provide inherent methods that take `&self` if the hardware permits it. In this case,
343+
you might need to do `&*self` to call them from the trait methods. Otherwise Rust will resolve the
344+
method call to the trait method, causing infinite recursion.
345+
346+
```rust
347+
struct HalPin;
348+
349+
impl HalPin {
350+
fn is_high(&self) -> bool {
351+
true
352+
}
353+
354+
fn is_low(&self) -> bool {
355+
true
356+
}
357+
}
358+
359+
impl InputPin for HalPin {
360+
fn is_high(&mut self) -> Result<bool, Self::Error> {
361+
// Needs `&*self` so that the inherent `is_high` is picked.
362+
Ok((&*self).is_high())
363+
}
364+
365+
fn is_low(&mut self) -> Result<bool, Self::Error> {
366+
Ok((&*self).is_low())
367+
}
368+
}
369+
```
370+
371+
**For driver authors**: If your driver does not need sharing input pins, you should be able to upgrade without any changes.
372+
If you do need to share input pins, the recommended solution is wrapping them with a `RefCell`.
373+
374+
Note that if you need to share multiple objects, you should prefer using a single `RefCell` wherever possible to reduce RAM
375+
usage. Make an "inner" struct with all the objects that need sharing, and wrap it in a single `RefCell`. Below is an example
376+
skeleton of a keypad driver using row/column multiplexing, sharing multiple `InputPin`s and `OutputPin`s with a single `RefCell`:
377+
378+
```rust
379+
use core::cell::RefCell;
380+
381+
use embedded_hal::digital::{ErrorType, InputPin, OutputPin};
382+
383+
pub struct Keypad<O: OutputPin, I: InputPin, const NCOLS: usize, const NROWS: usize> {
384+
inner: RefCell<KeypadInner<O, I, NCOLS, NROWS>>,
385+
}
386+
387+
struct KeypadInner<O: OutputPin, I: InputPin, const NCOLS: usize, const NROWS: usize> {
388+
cols: [O; NCOLS],
389+
rows: [I; NROWS],
390+
}
391+
392+
pub struct KeypadInput<'a, O: OutputPin, I: InputPin, const NCOLS: usize, const NROWS: usize> {
393+
inner: &'a RefCell<KeypadInner<O, I, NCOLS, NROWS>>,
394+
row: usize,
395+
col: usize,
396+
}
397+
398+
impl<'a, O: OutputPin, I: InputPin, const NCOLS: usize, const NROWS: usize> ErrorType for KeypadInput<'a, O, I, NCOLS, NROWS> {
399+
type Error = core::convert::Infallible;
400+
}
401+
402+
impl<'a, O: OutputPin, I: InputPin, const NCOLS: usize, const NROWS: usize> InputPin for KeypadInput<'a, O, I, NCOLS, NROWS> {
403+
fn is_high(&mut self) -> Result<bool, Self::Error> {
404+
Ok(!self.is_low()?)
405+
}
406+
407+
fn is_low(&mut self) -> Result<bool, Self::Error> {
408+
let inner = &mut *self.inner.borrow_mut();
409+
let row = &mut inner.rows[self.row];
410+
let col = &mut inner.cols[self.col];
411+
412+
// using unwrap for demo purposes, you should propagate errors up instead.
413+
col.set_low().unwrap();
414+
let out = row.is_low().unwrap();
415+
col.set_high().unwrap();
416+
417+
Ok(out)
418+
}
419+
}
420+
```
421+
422+
333423
## Prelude
334424

335425
The prelude has been removed because it could make method calls ambiguous, since the method names are now

0 commit comments

Comments
 (0)