From 76cd398c7f0ee7f8e66d793d2c0b3a88d6f79c41 Mon Sep 17 00:00:00 2001 From: Markus Kasten Date: Mon, 25 Mar 2024 22:16:55 +0100 Subject: [PATCH] chore: remove embedded_hal 0.x support --- Cargo.toml | 9 +- src/interface.rs | 378 +++++++++++++++-------------------------------- src/lib.rs | 44 ++---- 3 files changed, 132 insertions(+), 299 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9ff5857..b95bdf0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,14 +10,9 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[features] -eh1_0 = ["dep:eh1_0"] - [dependencies] -embedded-hal = "0.2" +embedded-hal = "1.0" defmt = "^0.3" -eh1_0 = { package = "embedded-hal", version = "1.0.0-alpha.10", optional = true } [dev-dependencies] -embedded-hal-mock = "0.9" -eh1_0-mock = { package = "embedded-hal-mock", git = "https://github.com/dbrgn/embedded-hal-mock.git", branch = "1-alpha" } +embedded-hal-mock = "0.10" diff --git a/src/interface.rs b/src/interface.rs index a818907..f9aed7d 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -1,3 +1,5 @@ +use embedded_hal::{i2c, spi}; + use crate::Error; /// Trait for giving read and write access to registers @@ -43,344 +45,196 @@ const fn spi_transmission_header(register: u16, write: bool) -> [u8; 2] { ] } -use embedded_hal::{blocking::spi, digital::v2::OutputPin}; - -pub struct SpiInterface { - pub(crate) spi: SPI, - pub(crate) cs: CS, +pub struct I2cInterface { + pub(crate) i2c: I2C, + pub(crate) address: u8, } -impl + spi::Write, CS: OutputPin> SpiInterface { - pub fn new(spi: SPI, cs: CS) -> Self { - Self { spi, cs } +impl I2cInterface { + pub fn new(i2c: I2C, address: u8) -> Self { + Self { i2c, address } } - pub fn release(self) -> (SPI, CS) { - (self.spi, self.cs) + fn address_with_register(&self, register: u16) -> u8 { + // The `address` is the 7bit i2c address (so excluding the R/W bit), not 8 bit (incl R/W) + (self.address & !0b11) | ((register & 0x300) >> 8) as u8 } } -#[derive(Debug)] -pub enum SpiInterfaceError { - /// An SPI error occured - SPI(SPIE), - - /// An error with the CS pin occurred - CS(CSE), +impl I2cInterface { + pub fn release(self) -> I2C { + self.i2c + } } -impl RegisterAccess for SpiInterface +impl RegisterAccess for I2cInterface where - SPI: spi::Transfer + spi::Write, - CS: OutputPin, + I2C: i2c::I2c, { - type Error = Error>; + type Error = Error; fn read_registers(&mut self, start_register: u16, data: &mut [u8]) -> Result<(), Self::Error> { - let header = spi_transmission_header(start_register, false); - - self.cs - .set_low() - .map_err(SpiInterfaceError::CS) - .map_err(Error::Interface)?; - - self.spi - .write(&header) - .map_err(SpiInterfaceError::SPI) - .map_err(Error::Interface)?; + let header = [(start_register & 0xff) as u8]; + let mut operations = [i2c::Operation::Write(&header), i2c::Operation::Read(data)]; - self.spi - .transfer(data) - .map_err(SpiInterfaceError::SPI) - .map_err(Error::Interface)?; - - self.cs - .set_high() - .map_err(SpiInterfaceError::CS) + self.i2c + .transaction(self.address_with_register(start_register), &mut operations) .map_err(Error::Interface)?; Ok(()) } fn write_registers(&mut self, start_register: u16, data: &[u8]) -> Result<(), Self::Error> { - let header = spi_transmission_header(start_register, true); + let header = [(start_register & 0xff) as u8]; - self.cs - .set_low() - .map_err(SpiInterfaceError::CS) - .map_err(Error::Interface)?; + // TODO: does this actually result in a single transaction or a restart? + let mut operations = [i2c::Operation::Write(&header), i2c::Operation::Write(data)]; - self.spi - .write(&header) - .map_err(SpiInterfaceError::SPI) - .map_err(Error::Interface)?; - self.spi - .write(data) - .map_err(SpiInterfaceError::SPI) - .map_err(Error::Interface)?; - - self.cs - .set_high() - .map_err(SpiInterfaceError::CS) + self.i2c + .transaction(self.address_with_register(start_register), &mut operations) .map_err(Error::Interface)?; Ok(()) } } -pub struct I2cInterface { - pub(crate) i2c: I2C, - pub(crate) address: u8, +pub struct SpiDeviceInterface { + pub(crate) spi_device: SPID, } -impl I2cInterface { - pub fn new(i2c: I2C, address: u8) -> Self { - Self { i2c, address } +impl SpiDeviceInterface { + pub fn new(spi_device: SPID) -> Self { + Self { spi_device } } - fn address_with_register(&self, register: u16) -> u8 { - // The `address` is the 7bit i2c address (so excluding the R/W bit), not 8 bit (incl R/W) - (self.address & !0b11) | ((register & 0x300) >> 8) as u8 + pub fn release(self) -> SPID { + self.spi_device } } -#[cfg(not(feature = "eh1_0"))] -use embedded_hal::blocking::i2c; - -#[cfg(not(feature = "eh1_0"))] -impl RegisterAccess for I2cInterface +impl RegisterAccess for SpiDeviceInterface where - I2C: i2c::Write + i2c::WriteRead, + SPID: spi::SpiDevice, { type Error = Error; fn read_registers(&mut self, start_register: u16, data: &mut [u8]) -> Result<(), Self::Error> { - self.i2c - .write_read( - self.address_with_register(start_register), - &[start_register as u8], - data, - ) - .map_err(Error::Interface) - } - - fn write_registers(&mut self, start_register: u16, data: &[u8]) -> Result<(), Self::Error> { - /// Should be enough for any LP586x device variant, as we only have a 10bit register address space in the LP586x - /// Possibly we can set this buffer size appropriately, based on the LP586x variant somehow... for now we - /// just allocate this buffe 'large enough' for all cases - const MAX_DATA_SIZE: usize = 0x400; - - let data_len = data.len(); - if data_len > MAX_DATA_SIZE { - Err(Error::BufferOverrun)? - } - - // create buffer to hold our "wide" address header and data in, for 'legacy/basic' I2C-hal support (meh..) - // This is wasteful, but needded (?) to support the 'legacy' i2c `Write` trait (for HALs not implementing the - // `WriteIter` and/or `Transactional` i2c traits e.g. the nrf-hal) - let mut buffer = [start_register as u8; MAX_DATA_SIZE + 1]; - let data_slice = &mut buffer[1..data_len + 1]; + let header = spi_transmission_header(start_register, false); - assert!(data_slice.len() == data.len()); - data_slice.copy_from_slice(data); + let mut operations = [spi::Operation::Write(&header), spi::Operation::Read(data)]; - let composite_bytes = &buffer[..data_len + 1]; + self.spi_device + .transaction(&mut operations) + .map_err(Error::Interface)?; - self.i2c - .write(self.address_with_register(start_register), composite_bytes) - .map_err(Error::Interface) + Ok(()) } -} -#[cfg(feature = "eh1_0")] -mod for_eh1_0 { - use super::*; - use eh1_0::{i2c, spi}; + fn write_registers(&mut self, start_register: u16, data: &[u8]) -> Result<(), Self::Error> { + let header = spi_transmission_header(start_register, true); - pub struct SpiDeviceInterface { - pub(crate) spi_device: SPID, - } + let mut operations = [spi::Operation::Write(&header), spi::Operation::Write(data)]; - impl SpiDeviceInterface { - pub fn new(spi_device: SPID) -> Self { - Self { spi_device } - } + self.spi_device + .transaction(&mut operations) + .map_err(Error::Interface)?; - pub fn release(self) -> SPID { - self.spi_device - } + Ok(()) } +} - impl RegisterAccess for SpiDeviceInterface - where - SPID: spi::SpiDevice, - { - type Error = Error; - - fn read_registers( - &mut self, - start_register: u16, - data: &mut [u8], - ) -> Result<(), Self::Error> { - let header = spi_transmission_header(start_register, false); - - let mut operations = [spi::Operation::Write(&header), spi::Operation::Read(data)]; - - self.spi_device - .transaction(&mut operations) - .map_err(Error::Interface)?; +#[cfg(test)] +mod tests { + use super::*; + use embedded_hal_mock::eh1::{ + i2c::{Mock as I2cMock, Transaction as I2cTransaction}, + spi::{Mock as SpiMock, Transaction as SpiTransaction}, + }; - Ok(()) - } + #[test] + fn test_spi_read_register() { + // test writing to register 0x38b + const REGISTER: u16 = 0x38b; + const VALUE: u8 = 0xAB; - fn write_registers(&mut self, start_register: u16, data: &[u8]) -> Result<(), Self::Error> { - let header = spi_transmission_header(start_register, true); + let spi = SpiMock::new(&[ + SpiTransaction::transaction_start(), + SpiTransaction::write_vec(vec![0xe2, 0xc0]), + SpiTransaction::read(VALUE), + SpiTransaction::transaction_end(), + ]); - let mut operations = [spi::Operation::Write(&header), spi::Operation::Write(data)]; + let mut spi_if = SpiDeviceInterface::new(spi); - self.spi_device - .transaction(&mut operations) - .map_err(Error::Interface)?; + let value = spi_if.read_register(REGISTER).unwrap(); - Ok(()) - } - } + assert_eq!(value, VALUE); - impl I2cInterface { - pub fn release(self) -> I2C { - self.i2c - } + spi_if.release().done(); } - impl RegisterAccess for I2cInterface - where - I2C: i2c::I2c, - { - type Error = Error; - - fn read_registers( - &mut self, - start_register: u16, - data: &mut [u8], - ) -> Result<(), Self::Error> { - let header = [(start_register & 0xff) as u8]; - let mut operations = [i2c::Operation::Write(&header), i2c::Operation::Read(data)]; - - self.i2c - .transaction(self.address_with_register(start_register), &mut operations) - .map_err(Error::Interface)?; + #[test] + fn test_spi_write_register() { + // test writing to register 0x38b + const REGISTER: u16 = 0x38b; + const VALUE: u8 = 0xAB; - Ok(()) - } - - fn write_registers(&mut self, start_register: u16, data: &[u8]) -> Result<(), Self::Error> { - let header = [(start_register & 0xff) as u8]; + let spi = SpiMock::new(&[ + SpiTransaction::transaction_start(), + SpiTransaction::write_vec(vec![0xe2, 0xe0]), + SpiTransaction::write(VALUE), + SpiTransaction::transaction_end(), + ]); - let mut operations = [i2c::Operation::Write(&header), i2c::Operation::Write(data)]; + let mut spi_if = SpiDeviceInterface::new(spi); - self.i2c - .transaction(self.address_with_register(start_register), &mut operations) - .map_err(Error::Interface)?; + spi_if.write_register(REGISTER, VALUE).unwrap(); - Ok(()) - } + spi_if.release().done(); } - #[cfg(test)] - mod tests { - use super::*; - use eh1_0_mock::{ - i2c::{Mock as I2cMock, Transaction as I2cTransaction}, - spi::{Mock as SpiMock, Transaction as SpiTransaction}, - }; - - #[test] - fn test_spi_read_register() { - // test writing to register 0x38b - const REGISTER: u16 = 0x38b; - const VALUE: u8 = 0xAB; - - let spi = SpiMock::new(&[ - SpiTransaction::transaction_start(), - SpiTransaction::write_vec(vec![0xe2, 0xc0]), - SpiTransaction::read(VALUE), - SpiTransaction::transaction_end(), - ]); + #[test] + fn test_i2c_read_register() { + // test writing to register 0x38b + const REGISTER: u16 = 0x38b; + const VALUE: u8 = 0xAB; - let mut spi_if = SpiDeviceInterface::new(spi); + let i2c = I2cMock::new(&[ + I2cTransaction::transaction_start(0), + I2cTransaction::write(0x3, vec![0x8b]), + I2cTransaction::read(0x3, vec![VALUE]), + I2cTransaction::transaction_end(0), + ]); - let value = spi_if.read_register(REGISTER).unwrap(); - - assert_eq!(value, VALUE); - - spi_if.release().done(); - } + let mut i2c_if = I2cInterface::new(i2c, 0); - #[test] - fn test_spi_write_register() { - // test writing to register 0x38b - const REGISTER: u16 = 0x38b; - const VALUE: u8 = 0xAB; + let value = i2c_if.read_register(REGISTER).unwrap(); + assert_eq!(value, VALUE); - let spi = SpiMock::new(&[ - SpiTransaction::transaction_start(), - SpiTransaction::write_vec(vec![0xe2, 0xe0]), - SpiTransaction::write(VALUE), - SpiTransaction::transaction_end(), - ]); - - let mut spi_if = SpiDeviceInterface::new(spi); - - spi_if.write_register(REGISTER, VALUE).unwrap(); - - spi_if.release().done(); - } - - #[test] - fn test_i2c_read_register() { - // test writing to register 0x38b - const REGISTER: u16 = 0x38b; - const VALUE: u8 = 0xAB; - - let i2c = I2cMock::new(&[ - I2cTransaction::transaction_start(0), - I2cTransaction::write(0, vec![0x8b]), - I2cTransaction::read(0, vec![VALUE]), - I2cTransaction::transaction_end(0), - ]); - - let mut i2c_if = I2cInterface::new(i2c, 0); - - let value = i2c_if.read_register(REGISTER).unwrap(); - assert_eq!(value, VALUE); - - i2c_if.release().done(); - } + i2c_if.release().done(); + } - #[test] - fn test_i2c_write_register() { - // test writing to register 0x38b - const REGISTER: u16 = 0x38b; - const VALUE: u8 = 0xAB; + #[test] + fn test_i2c_write_register() { + // test writing to register 0x38b + const REGISTER: u16 = 0x38b; + const VALUE: u8 = 0xAB; - let i2c = I2cMock::new(&[ - I2cTransaction::transaction_start(0), - I2cTransaction::write(0, vec![0x8b, VALUE]), - I2cTransaction::transaction_end(0), - ]); + let i2c = I2cMock::new(&[ + I2cTransaction::transaction_start(0), + I2cTransaction::write(0x3, vec![0x8b]), + I2cTransaction::write(0x3, vec![VALUE]), + I2cTransaction::transaction_end(0), + ]); - let mut i2c_if = I2cInterface::new(i2c, 0); + let mut i2c_if = I2cInterface::new(i2c, 0); - i2c_if.write_register(REGISTER, VALUE).unwrap(); + i2c_if.write_register(REGISTER, VALUE).unwrap(); - i2c_if.release().done(); - } + i2c_if.release().done(); } } -#[cfg(feature = "eh1_0")] -pub use for_eh1_0::SpiDeviceInterface; - #[cfg(test)] pub(crate) mod mock { use super::RegisterAccess; diff --git a/src/lib.rs b/src/lib.rs index 065bdcb..f5e55e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub mod interface; mod register; use configuration::Configuration; -use interface::{RegisterAccess, SpiInterfaceError}; +use interface::RegisterAccess; use register::{BitFlags, Register}; /// Error enum for the LP586x driver @@ -194,6 +194,7 @@ impl DotGroup { } } +/// Holds information about global faults #[derive(Debug)] pub struct GlobalFaultState { led_open_detected: bool, @@ -305,16 +306,20 @@ impl DeviceVariant for Variant8 { } impl seal::Sealed for Variant8 {} +/// Marker trait for configured data mode pub trait DataModeMarker: seal::Sealed {} +#[doc(hidden)] pub struct DataModeUnconfigured; impl DataModeMarker for DataModeUnconfigured {} impl seal::Sealed for DataModeUnconfigured {} +#[doc(hidden)] pub struct DataMode8Bit; impl DataModeMarker for DataMode8Bit {} impl seal::Sealed for DataMode8Bit {} +#[doc(hidden)] pub struct DataMode16Bit; impl DataModeMarker for DataMode16Bit {} impl seal::Sealed for DataMode16Bit {} @@ -326,10 +331,9 @@ pub struct Lp586x { _phantom_data: core::marker::PhantomData, } -#[cfg(feature = "eh1_0")] impl Lp586x, DM> where - D: eh1_0::i2c::I2c, + D: embedded_hal::i2c::I2c, { pub fn new_with_i2c( i2c: D, @@ -339,10 +343,9 @@ where } } -#[cfg(feature = "eh1_0")] impl Lp586x, DM> where - D: eh1_0::spi::SpiDevice, + D: embedded_hal::spi::SpiDevice, { pub fn new_with_spi_device( spi_device: D, @@ -351,25 +354,6 @@ where } } -#[cfg(not(feature = "eh1_0"))] -impl - Lp586x, DM> -where - SPI: embedded_hal::blocking::spi::Transfer - + embedded_hal::blocking::spi::Write, - CS: embedded_hal::digital::v2::OutputPin, -{ - pub fn new_with_spi_cs( - spi: SPI, - cs: CS, - ) -> Result< - Lp586x, DataModeUnconfigured>, - Error>, - > { - Lp586x::::new(interface::SpiInterface::new(spi, cs)) - } -} - macro_rules! fault_per_dot_fn { ($name:ident, $reg:expr, $doc:literal) => { #[doc=$doc] @@ -525,8 +509,8 @@ where Ok(()) } - /// Set group current scaling (0..127). - pub fn set_group_current(&mut self, group: Group, current: u8) -> Result<(), Error> { + /// Set color group current scaling (0..127). + pub fn set_color_group_current(&mut self, group: Group, current: u8) -> Result<(), Error> { self.interface .write_register(group.current_reg_addr(), current.min(0x7f))?; @@ -648,16 +632,16 @@ where } } -#[cfg(feature = "eh1_0")] -impl Lp586x, DM> { +impl + Lp586x, DM> +{ /// Destroys the driver and releases the owned [`SpiDevice`]. pub fn release(self) -> SPID { self.interface.release() } } -#[cfg(feature = "eh1_0")] -impl Lp586x, DM> { +impl Lp586x, DM> { /// Destorys the driver and releases the owned [`I2c`]. pub fn release(self) -> I2C { self.interface.release()