embedded_hal_spy/
lib.rs

1#![no_std]
2extern crate  embedded_hal as hal;
3use core::cell::RefCell;
4/// embedded hal spy implemnets call backs for used traits
5///
6/// Intended use is chaining over an existing embedded_hal
7/// implementation sniffing all the data. Useful when preparing
8/// for a refacforing and want to collect actual data for unit
9/// test case.
10///
11
12/// Blocking SPI API
13/// hal::blocking::spi::Transfer will return
14/// DataWord::First at start of transfer, all data sent in DataWord::Byte(u8)
15/// DataWord::Response to indicate where transmit ends and response begins
16/// all recived bytes in DataWord::Byte(u8) ending with DataWord::Last
17///
18/// Usage:
19/// ```
20///    extern crate embedded_hal_spy;
21///    use embedded_hal_spy::DataWord;
22/// #   use linux_embedded_hal::Spidev;
23/// #   use linux_embedded_hal::Pin;
24///
25/// #   if let Ok(spi) = Spidev::open("/dev/spidev0.0"){
26///    let mut spix = embedded_hal_spy::new(spi,
27///             |w|{
28///                 match w {
29///                     DataWord::First => {
30///                         print!("data = [");
31///                     },
32///                     DataWord::Last =>  {println!("],"); },
33///                     DataWord::Response =>  { print!("],\r\n       ["); },
34///
35///                     DataWord::Byte(num) => {
36///                         print!("{:x},",num);
37///                         },
38///                     _other => {},
39///                 }
40///             }
41///      );
42/// #     }
43/// ```
44pub struct Spy<T,F>
45where F:Fn(DataWord)
46{
47    /// object implementing emedded hal
48    s: RefCell<T>,
49    /// Callback
50    f: RefCell<F>,
51}
52/// Chain existing embedded_hal trait implementation to
53/// embedded_hal_spy
54pub fn new<T,F>(s: T, f: F)-> Spy<T,F>
55where F:Fn(DataWord)
56{
57    Spy{s:RefCell::new(s), f:RefCell::new(f)}
58}
59
60
61/// Call back data is encapulated in enum DataWord
62/// First and Last are provided from some transation
63/// oriented traits to indicate first and last
64pub enum DataWord {
65    None,
66    /// Encapsulate data
67    Byte(u8),
68    /// indicates first byte in transaction when used it
69    /// will be followd by last after the last byte
70    First,
71    /// When used it is sent after last byte in transaction
72    Last,
73    /// Indicate beggining of response from a tranasction based class
74    Response,
75    /// embedded_hal call have failed and will report error
76    Failed,
77    /// hal::digital::ToggleableOutput return value
78    Toggle,
79}
80
81use hal::spi::FullDuplex;
82extern crate nb;
83/// FullDuplex will return every data sent and read in DataWord::Byte(u8)
84///
85impl<T,F> FullDuplex<u8> for Spy<T,F>
86where T:FullDuplex<u8>,
87      F: Fn(DataWord),
88{
89    type Error = T::Error;
90    fn read (&mut self) -> Result<u8, nb::Error<Self::Error>>{
91        let mut s = self.s.borrow_mut();
92        let ans = s.read();
93        match &ans {
94            Ok(w) => {(self.f.borrow_mut())(DataWord::Byte(w.clone()));},
95            _other => {},
96        }
97        ans
98    }
99    fn send(&mut self, w: u8) -> Result<(), nb::Error<Self::Error>>{
100        (self.f.borrow_mut())(DataWord::Byte(w));
101        let mut s = self.s.borrow_mut();
102        s.send(w)
103    }
104}
105
106impl<T,F> hal::blocking::spi::Transfer<u8> for Spy<T,F>
107where T: hal::blocking::spi::Transfer<u8>,
108      F:Fn(DataWord)
109{
110    type Error = T::Error;
111    /// Sends `Word` to the slave. Returns the `Word` received from the slave
112    fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error>{
113        (self.f.borrow_mut())(DataWord::First);
114        for w in words.iter(){
115            (self.f.borrow_mut())(DataWord::Byte(*w));
116        }
117        (self.f.borrow_mut())(DataWord::Response);
118        let ans = (self.s.borrow_mut()).transfer(words)?;
119        for w in ans.iter(){
120            (self.f.borrow_mut())(DataWord::Byte(*w));
121        }
122        (self.f.borrow_mut())(DataWord::Last);
123
124        Ok(ans)
125    }
126}
127
128/// Blocking write
129impl<T,F> hal::blocking::spi::Write<u8> for Spy<T,F>
130where T: hal::blocking::spi::Write<u8>,
131      F: Fn(DataWord)
132 {
133    type Error = T::Error;
134    /// Sends `words` to the slave, ignoring all the incoming words
135    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error>{
136        for w in words.iter(){
137            (self.f.borrow_mut())(DataWord::Byte(*w));
138        }
139        (self.s.borrow_mut()).write(words)
140    }
141}
142#[cfg(feature = "embedded_hal_digital_io_legacy_v1")]
143/// Legacy traits
144/// Digital InputPin
145impl<T,F> hal::digital::v1::InputPin for Spy<T,F>
146where T: hal::digital::v1::InputPin,
147      F: Fn(DataWord)
148 {
149    fn is_high(&self) -> bool{
150        let state = (self.s.borrow_mut()).is_high();
151
152        (self.f.borrow_mut())(DataWord::Byte(state as u8));
153        state
154    }
155    fn is_low(&self) -> bool{
156        let state = (self.s.borrow_mut()).is_low();
157        (self.f.borrow_mut())(DataWord::Byte((!state) as u8));
158        state
159    }
160}
161#[cfg(feature = "embedded_hal_digital_io_legacy_v1")]
162/// Digital OutputPin
163impl<T,F> hal::digital::v1::OutputPin for Spy<T,F>
164where T: hal::digital::v1::OutputPin,
165      F: Fn(DataWord)
166 {
167    fn set_high(&mut self){
168        (self.f.borrow_mut())(DataWord::Byte(1));
169        (self.s.borrow_mut()).set_high()
170    }
171    fn set_low(&mut self){
172        (self.f.borrow_mut())(DataWord::Byte(0));
173        (self.s.borrow_mut()).set_low()
174    }
175}
176#[cfg(feature = "embedded_hal_digital_io_legacy_v1")]
177impl<T,F> hal::digital::v1::ToggleableOutputPin for Spy<T,F>
178where T: hal::digital::v1::ToggleableOutputPin,
179      F: Fn(DataWord)
180 {
181    fn toggle(&mut self){
182        (self.f.borrow_mut())(DataWord::Toggle);
183        (self.s.borrow_mut()).toggle()
184    }
185}
186
187#[cfg(feature = "embedded_hal_digital_io_legacy_v1")]
188impl<T,F> hal::digital::v1::StatefulOutputPin for Spy<T,F>
189where T: hal::digital::v1::StatefulOutputPin,
190      F: Fn(DataWord)
191{
192    fn is_set_high(&self) -> bool{
193        let state = (self.s.borrow_mut()).is_set_high();
194
195        (self.f.borrow_mut())(DataWord::Byte(state as u8));
196        state
197    }
198    fn is_set_low(&self) -> bool{
199        let state = (self.s.borrow_mut()).is_set_low();
200        (self.f.borrow_mut())(DataWord::Byte((!state) as u8));
201        state
202    }
203}
204
205#[cfg(not(feature = "embedded_hal_digital_io_legacy_v1"))]
206// V2 traits
207/// Digital InputPin
208impl<T,F> hal::digital::v2::InputPin for Spy<T,F>
209where T: hal::digital::v2::InputPin,
210      F: Fn(DataWord)
211 {
212    type Error = T::Error;
213    fn is_high(&self) -> Result<bool,Self::Error>{
214        let state = (self.s.borrow_mut()).is_high()?;
215        (self.f.borrow_mut())(DataWord::Byte(state as u8));
216        Ok(state)
217    }
218    fn is_low(&self) -> Result<bool,Self::Error>{
219        let state = (self.s.borrow_mut()).is_low()?;
220        (self.f.borrow_mut())(DataWord::Byte((!state) as u8));
221        Ok(state)
222    }
223}
224#[cfg(not(feature = "embedded_hal_digital_io_legacy_v1"))]
225/// Digital OutputPin
226impl<T,F> hal::digital::v2::OutputPin for Spy<T,F>
227where T: hal::digital::v2::OutputPin,
228      F: Fn(DataWord)
229 {
230    type Error = T::Error;
231    fn set_high(&mut self)->Result<(),T::Error>{
232        (self.f.borrow_mut())(DataWord::Byte(1));
233        (self.s.borrow_mut()).set_high()
234    }
235    fn set_low(&mut self)->Result<(),T::Error>{
236        (self.f.borrow_mut())(DataWord::Byte(0));
237        (self.s.borrow_mut()).set_low()
238    }
239}
240#[cfg(not(feature = "embedded_hal_digital_io_legacy_v1"))]
241impl<T,F> hal::digital::v2::ToggleableOutputPin for Spy<T,F>
242where T: hal::digital::v2::ToggleableOutputPin,
243      F: Fn(DataWord)
244 {
245    type Error = T::Error;
246    fn toggle(&mut self)->Result<(),T::Error>{
247        (self.f.borrow_mut())(DataWord::Toggle);
248        (self.s.borrow_mut()).toggle()
249    }
250}
251
252#[cfg(not(feature = "embedded_hal_digital_io_legacy_v1"))]
253impl<T,F> hal::digital::v2::StatefulOutputPin for Spy<T,F>
254where T: hal::digital::v2::StatefulOutputPin,
255      F: Fn(DataWord)
256{
257    //type Error = T::Error;
258    fn is_set_high(&self) -> Result<bool,T::Error>{
259        let state = (self.s.borrow_mut()).is_set_high()?;
260
261        (self.f.borrow_mut())(DataWord::Byte(state as u8));
262        Ok(state)
263    }
264    fn is_set_low(&self) -> Result<bool,T::Error>{
265        let state = (self.s.borrow_mut()).is_set_low()?;
266        (self.f.borrow_mut())(DataWord::Byte((!state) as u8));
267        Ok(state)
268    }
269}