bit_byte_structs/
bus.rs

1//! Define a common interface trait and implement so that other code can be bus agnostic
2//!
3//! Implementations of the trait for a variate of buses, currently I2C and a proto for SPI
4//!
5//! Note that this code will end up in its own crate but it is easer to develop
6//! in the same crate as a peripheral for now.
7use core::fmt::Debug;
8use core::marker::PhantomData;
9use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
10use embedded_hal::blocking::spi::Transfer;
11use embedded_hal::digital::v2::OutputPin;
12
13#[cfg(feature = "cortex-m-debuging")]
14use cortex_m_semihosting::hprintln;
15
16#[derive(Debug)]
17pub enum InterfaceError<E> {
18    Bus(E),
19    Pin,
20}
21impl<E> From<E> for InterfaceError<E> {
22    fn from(err: E) -> Self {
23        InterfaceError::Bus(err)
24    }
25}
26
27/// This Trait allows all the other Bus agnostic code to interface
28/// with a common bus independent api
29///
30/// The trait is not meant to be supper preferment as any code that
31/// needs to be particularly preformat probably wants to go in
32/// bus specific code.
33pub trait Interface {
34    type Error;
35
36    fn read_register(&mut self, register: u8, buffer: &mut [u8]) -> Result<(), Self::Error>;
37    fn write_register(&mut self, register: u8, bytes: &[u8]) -> Result<(), Self::Error>;
38}
39
40/// The I2C Implementation of the Interface trait
41///
42/// This seems to work and has been tested a bit.
43///
44/// Note the lifetimes. This struct takes ownership of the mutable borrow until it is dropped out of scope
45pub struct I2CPeripheral<'a, I2C, E, const ADDRESS: u8> {
46    bus: &'a mut I2C,
47    phantom_e: PhantomData<E>,
48}
49
50impl<'a, I2C, E, const ADDRESS: u8> I2CPeripheral<'a, I2C, E, ADDRESS>
51where
52    I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
53{
54    /// This makes a peripheral struct that implements the Interface trait
55    ///
56    /// The peripheral takes ownership of the mut borrow for the life
57    /// Of the struct so the struct is only ever expected to live breifely
58    /// but it might be nice to make a parent thing that know the chip id etc
59    /// that can have long life and then spawns on of these periodically
60    pub fn new(bus: &'a mut I2C) -> I2CPeripheral<'a, I2C, E, ADDRESS> {
61        I2CPeripheral {
62            phantom_e: PhantomData,
63            bus: bus,
64        }
65    }
66}
67
68impl<'a, I2C, E, const ADDRESS: u8> Interface for I2CPeripheral<'a, I2C, E, ADDRESS>
69where
70    I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
71{
72    type Error = InterfaceError<E>;
73
74    /// Read buffer.len() bytes starting at the reg at register
75    /// This is the i2c implementation for the interface trait
76    fn read_register(&mut self, register: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
77        self.bus.write(ADDRESS, &[register])?;
78        self.bus.read(ADDRESS, buffer)?;
79        Ok(())
80    }
81
82    /// Write  buffer.len() bytes starting at the reg at register
83    /// This is the i2c implementation for the interface trait
84    /// *NOTE*: The current implementation only works for 10 bytes
85    ///         And will panic if more are given.
86    fn write_register(&mut self, register: u8, bytes: &[u8]) -> Result<(), Self::Error> {
87        let mut new_buff: [u8; 10] = [0; 10];
88        new_buff[0] = register;
89        if bytes.len() > 10 {
90            // this should fail but i havent
91            // worked out a nice way yet
92            panic!("cant write that bigger slice AHAH")
93        }
94        for iii in 1..(bytes.len() + 1) {
95            new_buff[iii] = bytes[iii - 1]
96        }
97        self.bus.write(ADDRESS, &new_buff[0..(bytes.len() + 1)])?;
98        Ok(())
99    }
100}
101
102/// A struct to implement the Interface trait
103///
104/// This seems to work but is not extensively tested
105pub struct SPIPeripheral<'a, SPI, CS, E> {
106    bus: &'a mut SPI,
107    cs: &'a mut CS,
108    phantom_e: PhantomData<E>,
109}
110
111impl<'a, SPI, CS, E> SPIPeripheral<'a, SPI, CS, E>
112where
113    SPI: Transfer<u8>,
114    CS: OutputPin,
115{
116    pub fn new(bus: &'a mut SPI, cs: &'a mut CS) -> Self {
117        SPIPeripheral {
118            phantom_e: PhantomData,
119            bus: bus,
120            cs: cs,
121        }
122    }
123}
124
125impl<'a, SPI, CS, E> Interface for SPIPeripheral<'a, SPI, CS, E>
126where
127    SPI: Transfer<u8, Error = E>,
128    CS: OutputPin,
129{
130    type Error = InterfaceError<E>;
131    /// This is pretty much just filler code for now
132    fn read_register(&mut self, register: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
133        let mut local_buff: [u8; 50] = [0; 50];
134        self.cs.set_low().map_err(|_| InterfaceError::Pin)?;
135        // TODO, the read/write bit might want to be configurable
136        local_buff[0] = register | 0b10_00_00_00;
137
138        self.bus.transfer(&mut local_buff[0..(buffer.len() + 1)])?;
139
140        self.cs.set_high().map_err(|_| InterfaceError::Pin)?;
141
142        for iii in 1..(buffer.len() + 1) {
143            buffer[iii - 1] = local_buff[iii]
144        }
145        //#[cfg(feature = "cortex-m-debuging")]
146        //hprintln!(
147        //    "read: {:?} {:?} {:?},",
148        //    register,
149        //    local_buff,
150        //    buffer,
151        //).unwrap();
152        Ok(())
153    }
154
155    /// This is pretty much just filler code for now
156    fn write_register(&mut self, register: u8, bytes: &[u8]) -> Result<(), Self::Error> {
157        self.cs.set_low().map_err(|_| InterfaceError::Pin)?;
158        // If the first bit is 0, the register is written.
159        let mut new_buff: [u8; 10] = [0; 10];
160        new_buff[0] = register & 0b01_11_11_11;
161        if bytes.len() > 10 {
162            // this should fail but i havent
163            // worked out a nice way yet
164            panic!("cant write that bigger slice AHAH")
165        }
166        for iii in 1..(bytes.len() + 1) {
167            new_buff[iii] = bytes[iii - 1]
168        }
169        self.bus.transfer(&mut new_buff[0..(bytes.len() + 1)])?;
170        self.cs.set_high().map_err(|_| InterfaceError::Pin)?;
171        Ok(())
172    }
173}