### Share Input/Output Pins with RefCell in Driver Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md For drivers that need to share input or output pins, wrap them in a `RefCell`. This example demonstrates a keypad driver using a single `RefCell` to manage multiple pins, reducing RAM usage. ```rust use core::cell::RefCell; use embedded_hal::digital::{ErrorType, InputPin, OutputPin}; pub struct Keypad { inner: RefCell>, } struct KeypadInner { cols: [O; NCOLS], rows: [I; NROWS], } pub struct KeypadInput<'a, O: OutputPin, I: InputPin, const NCOLS: usize, const NROWS: usize> { inner: &'a RefCell>, row: usize, col: usize, } impl<'a, O: OutputPin, I: InputPin, const NCOLS: usize, const NROWS: usize> ErrorType for KeypadInput<'a, O, I, NCOLS, NROWS> { type Error = core::convert::Infallible; } impl<'a, O: OutputPin, I: InputPin, const NCOLS: usize, const NROWS: usize> InputPin for KeypadInput<'a, O, I, NCOLS, NROWS> { fn is_high(&mut self) -> Result { Ok(!self.is_low()?) } fn is_low(&mut self) -> Result { let inner = &mut *self.inner.borrow_mut(); let row = &mut inner.rows[self.row]; let col = &mut inner.cols[self.col]; // using unwrap for demo purposes, you should propagate errors up instead. col.set_low().unwrap(); let out = row.is_low().unwrap(); col.set_high().unwrap(); Ok(out) } } ``` -------------------------------- ### Handling I2C NACK Errors in Drivers Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md Drivers can now interpret and act on specific error kinds, such as I2C NACK. This example shows how to wrap original errors with custom driver-specific errors. ```rust const address = 0x1D; fn set_some_parameter(&mut self) -> Result<(), Self::Error> { const data = [0, 1]; match self.i2c.write(address, &data) { Err(e) => match e.kind() { ErrorKind::NoAcknowledge(_) => Err(Self::Error::DeviceBusy(e)), _ => Err(Self::Error::Comm(e)) // wrap and return any other error }, Ok(_) => Ok(()) } } ``` -------------------------------- ### Implement Infallible OutputPin methods alongside Fallible ones Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md This example shows how a HAL implementation can provide both fallible (`Result<(), Self::Error>`) and infallible (`()` ) versions of trait methods. This allows generic code to use the fallible versions while non-generic code can use the infallible ones, avoiding unnecessary `unwrap()` calls. ```rust use core::convert::Infallible; use embedded_hal::digital::blocking::OutputPin; struct HalImplGpioPin; impl OutputPin for HalImplGpioPin { type Error = Infallible; fn set_high(&mut self) -> Result<(), Self::Error> { // ... Ok(()) } fn set_low(&mut self) -> Result<(), Self::Error> { // ... Ok(()) } } impl HalImplGpioPin { fn set_high(&mut self) { // ... } fn set_low(&mut self) { // ... } } ``` -------------------------------- ### Implement `&mut self` for GPIO traits in HAL Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md When implementing `InputPin` or `State` traits, methods now require `&mut self`. This example shows how to handle this by calling inherent methods using `*self` to avoid infinite recursion. ```rust struct HalPin; impl HalPin { fn is_high(&self) -> bool { true } fn is_low(&self) -> bool { true } } impl InputPin for HalPin { fn is_high(&mut self) -> Result { // Needs `*self` so that the inherent `is_high` is picked. Ok((*self).is_high()) } fn is_low(&mut self) -> Result { Ok((*self).is_low()) } } ``` -------------------------------- ### Convert SpiBus to SpiDevice with ExclusiveDevice Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md Use `ExclusiveDevice` to wrap an `SpiBus` and a CS pin, creating an `SpiDevice`. This is necessary when a driver requires `SpiDevice` but the HAL only provides `SpiBus`. ```rust use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay}; // Create the SPI from the HAL. This implements SpiBus, not SpiDevice! let spi_bus = my_hal::spi::Spi::new (...); // Create the CS. This must implement OutputPin. let cs = my_hal::gpio::Output::new (...); // Combine the SPI bus and the CS pin into a SPI device. This now does implement SpiDevice! let spi_device = ExclusiveDevice::new(spi_bus, cs, NoDelay); // Now you can create your driver with it! let driver = my_driver::Driver::new(spi_device, ...); ``` -------------------------------- ### Share SpiBus with multiple SpiDevices using RefCellDevice Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md Use `RefCellDevice` to allow multiple drivers to share a single `SpiBus` when they don't need to be `Send`. This requires wrapping the `SpiBus` in a `RefCell`. ```rust use core::cell::RefCell; use embedded_hal_bus::spi::{RefCellDevice, NoDelay}; // Create the SPI bus and CS pins. let spi_bus = my_hal::spi::Spi::new (...); let cs1 = my_hal::gpio::Output::new (...); let cs2 = my_hal::gpio::Output::new (...); // Wrap the bus with a RefCell. let spi_bus = RefCell::new(spi_bus); // Combine references to the SPI bus with a CS pin to get a SpiDevice for one device on the bus. let device1 = RefCellDevice::new(&spi_bus, cs1, NoDelay); let device2 = RefCellDevice::new(&spi_bus, cs2, NoDelay); // Now you can create drivers. They will transparently talk each to its own device, sharing the same bus. let driver1 = my_driver::Driver::new(device1, ...); let driver2 = my_driver::Driver::new(device2, ...); ``` -------------------------------- ### Implement embedded-hal v0.2 and v1.0 traits Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md Implement both the v0.2 and v1.0 traits on the same struct for an input pin. The v0.2 implementation is conditionally compiled using a feature flag. ```rust /// The HAL's input pin struct struct Input {...} /// Implement the v0.2 traits on the struct. #[cfg(feature = "embedded-hal-02")] impl embedded_hal_02::digital::v2::InputPin for Input { type Error = Infallible; fn is_high(&self) -> Result { ... } fn is_low(&self) -> Result { ... } } /// ... and implement the v1.0 traits on the *same* struct. impl embedded_hal_1::digital::ErrorType for Input { type Error = Infallible; } impl embedded_hal_1::digital::InputPin for Input { fn is_high(&mut self) -> Result { ... } fn is_low(&mut self) -> Result { ... } } ``` -------------------------------- ### Add embedded-hal 0.2 and 1.0 dependencies Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md Declare dependencies for both embedded-hal versions in Cargo.toml. The 0.2 version is optional and enabled via a feature flag. ```toml [dependencies] embedded-hal-02 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"], optional = true } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } ``` -------------------------------- ### Derive Debug for Error Types Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md All associated error types must now implement `core::fmt::Debug`. Add `#[derive(Debug)]` to your error types. ```rust + #[derive(Debug)] pub enum MyError { InvalidInputData, // ... } ``` -------------------------------- ### SPI Transfer Return Type Change Source: https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md The `transfer()` method in SPI now returns `Result<(), Self::Error>` instead of a slice of output data. Use the reception buffer directly for received data. ```rust let tx_data = [1, 2, 3, 4]; let mut rx_data = [0; 4]; let data = spi.transfer(&tx_data, &mut rx_data)?; println!("{:?}", data); // There is no need to do `let data = `, since we already have the data in `rx_data`. // Do this instead: spi.transfer(&tx_data, &mut rx_data)?; println!("{:?}", rx_data); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.