bit_byte_structs/
registers.rs

1//! # Register based structures
2//!
3//! This mod builds on the Interface trait defined in the bus module and defines
4//! a series of structs that mirror the common register types of many peripherals.
5//!
6//! ## Sub byte
7//!
8//! Often a byte will be broken down in to bits or a couple of bits
9//! and you must then write code to bit shift and merge existing config to write
10//! or bit mask and bit shift to read.
11//!
12//! This code dose this for you, for very time critical code, bus specific
13//! code may be valuable but for many registers this code can save time and
14//! code lines.
15//!
16//! ## Multi byte
17//!
18//! The first two Multi byte implementations are CrossByteBitStructI16 and ByteStructI16
19//!
20//! The CrossByteBitStructI16 allows you to mange values that are less than or equal to 16 bits
21//! in size were they value is split over 2 bytes.
22//!
23//! The CrossByteBitStructI16 structure allows for you to retrieve a number of I16 values in
24//! adjacent registers.
25
26use super::bus::{Interface, InterfaceError};
27use core::fmt::{self, Debug};
28
29use core::marker::PhantomData;
30use core::usize;
31
32/// A error type returned by many of the structures in this mod
33///
34/// This error is generic over any type of E including SPI and I2C
35/// the struct also implements `from` trait for the underlying error and
36/// will report BitByteStructError::Bus in this case.
37///
38/// TODO: better support bus errors by passing them though better, possibly by
39/// implementing things more spiffily.
40pub enum BitByteStructError<E> {
41    TooManyBits,
42    TooBigShift,
43    InputToBig,
44    InterfaceError(InterfaceError<E>),
45    BusError(E),
46}
47
48impl<E> From<E> for BitByteStructError<E> {
49    fn from(err: E) -> Self {
50        BitByteStructError::BusError(err)
51    }
52}
53
54impl<E> Debug for BitByteStructError<E>
55//where
56//    E: Debug
57{
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
59        match self {
60            //Self::BusError(e) => f.write_fmt(format_args!("BitByteStructError bus error {:?}", e))?,
61            //Self::InterfaceError(e) => f.write_fmt(format_args!("BitByteStructError interface error {:?}", e))?,
62            Self::BusError(_) => f.write_str("BitByteStructError Bus error")?,
63            Self::InterfaceError(_) => f.write_str("BitByteStructError Interface error")?,
64            Self::TooManyBits => f.write_str("BitByteStructError too many bits error")?,
65            Self::TooBigShift => f.write_str("BitByteStructError too big shift error")?,
66            Self::InputToBig => f.write_str("BitByteStructError input too big error")?,
67        }
68
69        Ok(())
70    }
71}
72
73/// Struct for representing registers of 0-8bits
74pub struct BitStruct<Interface: ?Sized, const ADDRESS: u8, const BITS: u8, const SHIFT: u8> {
75    phantom: PhantomData<Interface>,
76}
77
78impl<I, const ADDRESS: u8, const BITS: u8, const SHIFT: u8> BitStruct<I, ADDRESS, BITS, SHIFT>
79where
80    I: Interface,
81    I: ?Sized,
82{
83    /// Create a new BitStruct
84    ///
85    /// Arguments:
86    ///
87    /// * `register_address: u8` - The address of the register that contains the bits.
88    /// * `bits: u8` - The number of bits this struct can read and write.
89    /// * `shift: u8` - The number of bits from the start of the byte.
90    pub fn new() -> Result<BitStruct<I, ADDRESS, BITS, SHIFT>, BitByteStructError<I::Error>> {
91        if BITS > 8 {
92            return Err(BitByteStructError::TooManyBits);
93        }
94        if SHIFT + BITS > 8 {
95            return Err(BitByteStructError::TooBigShift);
96        }
97        Ok(BitStruct {
98            phantom: PhantomData,
99        })
100    }
101
102    fn mask_size(&self) -> u8 {
103        (2_u16.pow(BITS as u32) - 1) as u8
104    }
105
106    /// Read the value from the peripheral
107    ///
108    /// * `bus: &mut dyn Interface<Error = I::Error>` - The interface to the bus over which to communicate with the peripheral.
109    ///
110    /// This will read the register that contains the information and then mask and shit the value for you.
111    pub fn read(
112        &self,
113        bus: &mut dyn Interface<Error = I::Error>,
114    ) -> Result<u8, BitByteStructError<I::Error>> {
115        let mut active_buffer: [u8; 1] = [0];
116        bus.read_register(ADDRESS, &mut active_buffer)?;
117        Ok((active_buffer[0] & (self.mask_size() << SHIFT)) >> SHIFT)
118    }
119
120    /// Write the value to the peripheral
121    ///
122    /// * `bus: &mut dyn Interface<Error = I::Error>` - The interface to the bus over which to communicate with the peripheral.
123    /// * `new_value: u8` - The new value to send to the peripheral
124    ///
125    /// This will read the register that contains the information and then mask and shit the new value and then write the full
126    /// register back without effecting the other bits not covered by this structures bits.
127    ///
128    /// If `new_value` is larger than the number of bits this structure covers then the function will return a `BitByteStructError::InputToBig`
129    /// without interacting with the peripheral.
130    pub fn write(
131        &self,
132        bus: &mut dyn Interface<Error = I::Error>,
133        new_value: u8,
134    ) -> Result<(), BitByteStructError<I::Error>> {
135        // This should be turned off with feature flag
136        let mask = self.mask_size() << SHIFT;
137        if new_value != new_value & self.mask_size() {
138            return Err(BitByteStructError::InputToBig);
139        }
140        let mut active_buffer: [u8; 1] = [0];
141        bus.read_register(ADDRESS, &mut active_buffer)?;
142        active_buffer[0] = (active_buffer[0] & !mask) | new_value << SHIFT;
143        bus.write_register(ADDRESS, &active_buffer)?;
144        Ok(())
145    }
146}
147
148/// A register for interacting with 0-16bits over two consecutive bytes/registers
149///
150/// This reads/writes two bytes but provides a api presenting a u16 to the lib using it.
151pub struct CrossByteBitStructI16<Interface: ?Sized> {
152    phantom: PhantomData<Interface>,
153    register_address: u8,
154    bits: u8,
155    /// Set true for Big endian registers
156    big_endian: bool,
157}
158
159impl<I> CrossByteBitStructI16<I>
160where
161    I: Interface,
162    I: ?Sized,
163{
164    pub fn new(
165        register_address: u8,
166        bits: u8,
167        big_endian: bool,
168    ) -> Result<CrossByteBitStructI16<I>, BitByteStructError<I::Error>> {
169        Ok(Self {
170            phantom: PhantomData,
171            register_address,
172            bits,
173            big_endian,
174        })
175    }
176
177    fn mask_size_full(&self) -> u16 {
178        (2_u32.pow(self.bits as u32) - 1) as u16
179    }
180
181    fn mask_size_byte(&self) -> u8 {
182        (2_u32.pow((self.bits - 8) as u32) - 1) as u8
183    }
184
185    /// Read the new value to the relevant sub set of the registers
186    pub fn read(
187        &self,
188        bus: &mut dyn Interface<Error = I::Error>,
189    ) -> Result<u16, BitByteStructError<I::Error>> {
190        let mut active_buffer: [u8; 2] = [0; 2];
191        bus.read_register(self.register_address, &mut active_buffer)?;
192        if self.big_endian {
193            Ok(u16::from_be_bytes([
194                active_buffer[0] & self.mask_size_byte(),
195                active_buffer[1],
196            ]))
197        } else {
198            Ok(u16::from_le_bytes([
199                active_buffer[0],
200                active_buffer[1] & self.mask_size_byte(),
201            ]))
202        }
203    }
204
205    /// Write the new value to the relevant sub set of the registers
206    pub fn write(
207        &self,
208        bus: &mut dyn Interface<Error = I::Error>,
209        new_value: u16,
210    ) -> Result<(), BitByteStructError<I::Error>> {
211        // TODO: blank, and error, on too large a value
212        if new_value != new_value & self.mask_size_full() {
213            return Err(BitByteStructError::InputToBig);
214        }
215        let active_buffer: [u8; 2] = if self.big_endian {
216            [((new_value & 0xFF00) >> 8) as u8, (new_value & 0xFF) as u8]
217        } else {
218            [(new_value & 0xFF) as u8, ((new_value & 0xFF00) >> 8) as u8]
219        };
220        bus.write_register(self.register_address, &active_buffer)?;
221        Ok(())
222    }
223}
224
225/// A Struct to map a number of 16bit integers to a number of consecutive registers
226///
227/// *NOTE: Currently read only for now*
228///
229/// Using the COUNT as part of the type should make it easier to mange the memory
230/// but I haven't got it down yet. So you can currently only read for up to 10
231/// integers.
232pub struct ByteStructI16<Interface: ?Sized, const COUNT: usize> {
233    phantom_i: PhantomData<Interface>,
234    register_address: u8,
235    /// Set true for Big endian registers
236    big_endian: bool,
237}
238
239impl<I, const COUNT: usize> ByteStructI16<I, COUNT>
240where
241    I: Interface,
242    I: ?Sized,
243{
244    pub fn new(
245        register_address: u8,
246        big_endian: bool,
247    ) -> Result<ByteStructI16<I, COUNT>, BitByteStructError<I::Error>> {
248        Ok(ByteStructI16 {
249            phantom_i: PhantomData,
250            register_address,
251            big_endian,
252        })
253    }
254
255    /// Read the values
256    ///
257    /// WARNING this will go horribly wrong if COUNT > 10
258    pub fn read(
259        &self,
260        bus: &mut dyn Interface<Error = I::Error>,
261    ) -> Result<[i16; COUNT], BitByteStructError<I::Error>> {
262        let mut result_slice: [i16; COUNT] = [0; COUNT];
263        // TODO find a way for this to be sized
264        let mut raw_slice: [u8; 20] = [0; 20];
265
266        bus.read_register(self.register_address, &mut raw_slice[0..(COUNT * 2)])?;
267        for iii in 0..COUNT {
268            if self.big_endian {
269                result_slice[iii] =
270                    i16::from_be_bytes([raw_slice[iii * 2], raw_slice[iii * 2 + 1]]);
271            } else {
272                result_slice[iii] =
273                    i16::from_le_bytes([raw_slice[iii * 2], raw_slice[iii * 2 + 1]]);
274            }
275        }
276        Ok(result_slice)
277    }
278}