1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
//! Transactional SPI wrapper implementation
//! This provides a `Wrapper` type that is generic over an `embedded_hal::blocking::spi` 
//! and `embedded_hal::digital::v2::OutputPin` to provide a transactional API for SPI transactions.

use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::digital::v2::{OutputPin, InputPin};

use crate::{Transaction, Transactional, PinState, Error};

/// Wrapper wraps an Spi and Pin object to support transactions
#[derive(Debug, Clone, PartialEq)]
pub struct Wrapper<Spi, SpiError, OutputPin, InputPin, PinError> {
    spi: Spi,
    cs: OutputPin,
    busy: Option<InputPin>,

    pub(crate) err: Option<Error<SpiError, PinError>>,
}

impl <Spi, SpiError, Output, Input, PinError> Wrapper<Spi, SpiError, Output, Input, PinError>  
where
    Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
    Output: OutputPin<Error = PinError>,
    Input: InputPin<Error = PinError>,
{
    /// Create a new wrapper object with the provided SPI and pin
    pub fn new(spi: Spi, cs: Output) -> Self {
        Self{spi, cs, err: None, busy: None}
    }

    /// Add a busy input to the wrapper object
    pub fn with_busy(s: &mut Self, busy: Input) -> &mut Self {
        s.busy = Some(busy);
        s
    }

    /// Write to a Pin instance while wrapping and storing the error internally
    /// This returns 0 for success or -1 for errors
    pub fn pin_write<P>(&mut self, pin: &mut P, value: bool) -> i32 
    where P: OutputPin<Error = PinError>
    {
        let r = match value {
            true => pin.set_high(),
            false => pin.set_low(),
        };
        match r {
            Ok(_) => 0,
            Err(e) => {
                self.err = Some(Error::Pin(e));
                -1
            }
        }
    }

    /// Write to a Pin instance while wrapping and storing the error internally
    /// This returns 0 for low, 1 for high, and -1 for errors
    pub fn pin_read<P>(&mut self, pin: &mut P) -> i32 
    where P: InputPin<Error = PinError>
    {
        let r = pin.is_high();
        match r {
            Ok(true) => 1,
            Ok(false) => 0,
            Err(e) => {
                self.err = Some(Error::Pin(e));
                -1
            }
        }
    }
    
    /// Check the internal error state of the peripheral
    /// This provides a mechanism to retrieve the rust error if an error occurs
    /// during an FFI call, and clears the internal error state
    pub fn check_error(&mut self) -> Result<(), Error<SpiError, PinError>> {
        match self.err.take() {
            Some(e) => Err(e),
            None => Ok(())
        }
    }
}

impl <Spi, SpiError, Output, Input, PinError> Transactional for Wrapper<Spi, SpiError, Output, Input, PinError>  
where
    Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
    Output: OutputPin<Error = PinError>,
    Input: InputPin<Error = PinError>,
{
    type Error = Error<SpiError, PinError>;

    /// Read data from a specified address
    /// This consumes the provided input data array and returns a reference to this on success
    fn spi_read<'a>(&mut self, prefix: &[u8], mut data: &'a mut [u8]) -> Result<(), Self::Error> {
        // Assert CS
        self.cs.set_low().map_err(|e| { Error::Pin(e) })?;

        // Write command
        let mut res = self.spi.write(&prefix);

        // Read incoming data
        if res.is_ok() {
            res = self.spi.transfer(&mut data).map(|_r| () );
        }

        // Clear CS
        self.cs.set_high().map_err(|e| { Error::Pin(e) })?;

        // Return result (contains returned data)
        match res {
            Err(e) => Err( Error::Spi(e) ),
            Ok(_) => Ok(()),
        }
    }

    /// Write data to a specified register address
    fn spi_write(&mut self, prefix: &[u8], data: &[u8]) -> Result<(), Self::Error> {
        // Assert CS
        self.cs.set_low().map_err(|e| { Error::Pin(e) })?;

        // Write command
        let mut res = self.spi.write(&prefix);

        // Read incoming data
        if res.is_ok() {
            res = self.spi.write(&data);
        }

        // Clear CS
        self.cs.set_high().map_err(|e| { Error::Pin(e) })?;

        // Return result
        match res {
            Err(e) => Err( Error::Spi(e) ),
            Ok(_) => Ok(()),
        }
    }

    /// Execute the provided transactions
    fn spi_exec(&mut self, transactions: &mut [Transaction]) -> Result<(), Self::Error> {
        let mut res = Ok(());

        // Assert CS
        self.cs.set_low().map_err(|e| { Error::Pin(e) })?;

        for i in 0..transactions.len() {
            let mut t = &mut transactions[i];

            res = match &mut t {
                Transaction::Write(d) => self.spi.write(d),
                Transaction::Read(d) =>  self.spi.transfer(d).map(|_r| () ),
            }.map_err(|e| Error::Spi(e) );

            if res.is_err() {
                break;
            }
        }

        // Assert CS
        self.cs.set_low().map_err(|e| { Error::Pin(e) })?;

        res
    }

    /// Check if the peripheral is currently busy
    /// This will panic if not busy pin is bound
    fn spi_busy(&mut self) -> Result<PinState, Self::Error> {
        match &self.busy {
            // TODO: should this be an error?
            None => Ok(PinState::Low),
            Some(b) => {
                let v = b.is_high().map_err(|e| Error::Pin(e) )?;
                match v {
                    true => Ok(PinState::High),
                    false => Ok(PinState::Low),
                }
            }
        }
    }
}

impl <Spi, SpiError, Output, Input, PinError> Transfer<u8> for Wrapper<Spi, SpiError, Output, Input, PinError>  
where
    Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
    Output: OutputPin<Error = PinError>,
    Input: InputPin<Error = PinError>,
    
{
    type Error = SpiError;

    fn transfer<'w>(&mut self, buffer: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
        Transfer::transfer(&mut self.spi, buffer)
    }
}

impl <Spi, SpiError, Output, Input, PinError> Write<u8> for Wrapper<Spi, SpiError, Output, Input, PinError>  
where
    Spi: Transfer<u8, Error = SpiError> + Write<u8, Error = SpiError>,
    Output: OutputPin<Error = PinError>,
    Input: InputPin<Error = PinError>,
{
    type Error = SpiError;
    
    fn write<'w>(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
        Write::write(&mut self.spi, buffer)
    }
}