Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
230: Make I2C compatible with multiple address sizes r=ryankurte a=eldruin This adds I2C 7-bit and 10-bit address mode compatibility as roughly described [here](#147 (comment)). Discussion issue: #147 I have also added the `SevenBitAddress` as the default address mode to the traits so this is not even a breaking change. Usage broken down per use case: * **Device driver which only supports 7-bit addressing mode:** The driver looks exactly the same as now since the default address mode is 7-bit. ```rust impl<I2C, E> MyDriver<I2C> where I2C: i2c::Write<Error = E> { pub fn do_cool_stuff(&mut self) // ... } ``` * **Device driver which only supports 10-bit addressing mode:** The only difference to a 7-bit-address-only driver is one additional parameter in the I2C trait bound. ```rust impl<I2C, E> MyDriver<I2C> where I2C: i2c::Write<TenBitAddress, Error = E> { pub fn do_cool_stuff(&mut self) // ... } ``` * **Driver for device supporting both addressing modes:** Complexity can be abstracted away into additional internal traits which can handle the addressing stuff. Driver code stays clean. **This is nothing new**. We already do this on drivers for devices compatible with both I2C and SPI. No need for duplicated code. Here a real example: [usage](https://github.com/eldruin/bmi160-rs/blob/3af5637f1df047bb811a4885525cfbe8b44d8ede/src/device_impl.rs#L43), [traits](https://github.com/eldruin/bmi160-rs/blob/master/src/interface.rs) ```rust impl<DI, E> MyDriver<DI> where DI: WriteData<Error = E> { pub fn do_cool_stuff(&mut self) {} // ... } pub trait WriteData { // ... } // it is also possible to just leave the `SevenBitAddress` type out here, // since it is the default. impl<I2C, E> WriteData for I2cInterface<I2C, SevenBitAddress> where I2C: i2c::Write<SevenBitAddress, Error = E>, { // ... } impl<I2C, E> WriteData for I2cInterface<I2C, TenBitAddress> where I2C: i2c::Write<TenBitAddress, Error = E>, { // ... } ``` * **Bus controller impl supporting only 7-bit addressing mode:** Code stays almost the same, just adding one addressing mode parameter. Additionally, _if desired_: * 10-bit addressing can be software-emulated: Emulate by extending and copying payload in separate `TenBitAddress` implementation. Total flexibility to do whatever is necessary in this case since the code is independent. * 10-bit addressing cannot be software-emulated: Implementation does not offer implementation for `TenBitAddress` variant. The user gets a compilation error and everything is clear. * **Bus controller impl supporting both addressing modes:** No problem. Two separate implementations guarantee as much flexibility as necessary. At the same time, sharing generic code is possible. Additional benefits: * No runtime performance cost * No runtime switching, duplicated code or panics for unsupported modes. * Consistent with what we do for code paths that can be determined statically by the compiler. * To my taste elegant, simple and very descriptive. See [here](#147 (comment)) for a comparison to other alternatives. I have also sealed the trait. ## Proof * A HAL implementation of both modes: [bitbang-hal](https://github.com/eldruin/bitbang-hal/tree/i2c-multi-address-mode). [code changes](eldruin/bitbang-hal@embedded-hal-1.0.0-alpha.1...eldruin:i2c-multi-address-mode) * Drivers supporting only 7-bit addresses need **no changes**. For demonstration purposes, explicitly including the `SevenBitAddress` would look like this: [OPT300x](https://github.com/eldruin/opt300x-rs/tree/i2c-multi-address-mode). [code changes](https://github.com/eldruin/opt300x-rs/compare/i2c-multi-address-mode). This would be similar to the case of a 10-bit-only device driver. Co-authored-by: Diego Barrios Romero <eldruin@gmail.com>
- Loading branch information