i2cdev/
mock.rs

1// Copyright 2015, Paul Osborne <osbpau@gmail.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/license/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option.  This file may not be copied, modified, or distributed
7// except according to those terms.
8use core::{I2CDevice, I2CMessage, I2CTransfer};
9use std::convert::TryFrom;
10use std::io;
11
12/// I2C mock result type
13pub type I2CResult<T> = io::Result<T>;
14
15/// Mock I2C device register map
16pub struct I2CRegisterMap {
17    registers: [u8; 0xFF],
18    offset: usize,
19}
20
21impl Default for I2CRegisterMap {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl I2CRegisterMap {
28    /// Create new mock I2C register map
29    pub fn new() -> I2CRegisterMap {
30        I2CRegisterMap {
31            registers: [0x00; 0xFF],
32            offset: 0,
33        }
34    }
35
36    /// Set several registers starting at the given offset
37    pub fn write_regs(&mut self, offset: usize, data: &[u8]) {
38        println!("WRITE | 0x{:X} : {:?}", offset, data);
39        self.registers[offset..(data.len() + offset)].clone_from_slice(data);
40    }
41}
42
43impl I2CRegisterMap {
44    /// Read data from the device to fill the provided slice
45    fn read(&mut self, data: &mut [u8]) -> I2CResult<()> {
46        let len = data.len();
47        data.clone_from_slice(&self.registers[self.offset..(self.offset + len)]);
48        println!(
49            "READ  | 0x{:X} : {:?}",
50            isize::try_from(self.offset).unwrap_or(0xBAD)
51                - isize::try_from(data.len()).unwrap_or(0xBAD),
52            data
53        );
54        Ok(())
55    }
56
57    /// Write the provided buffer to the device
58    fn write(&mut self, data: &[u8]) -> I2CResult<()> {
59        // ASSUMPTION: first byte sets the offset
60        // ASSUMPTION: write has length of at least one (will panic)
61        let offset = data[0] as usize;
62        let remdata = &data[1..];
63        self.write_regs(offset, remdata);
64        self.offset = offset + remdata.len();
65        Ok(())
66    }
67}
68
69/// Mock I2C device exposing a register map
70#[derive(Default)]
71pub struct MockI2CDevice {
72    /// I2C register map
73    pub regmap: I2CRegisterMap,
74}
75
76impl MockI2CDevice {
77    /// Create a new mock I2C device
78    pub fn new() -> MockI2CDevice {
79        MockI2CDevice {
80            regmap: I2CRegisterMap::new(),
81        }
82    }
83}
84
85impl I2CDevice for MockI2CDevice {
86    type Error = io::Error;
87
88    fn read(&mut self, data: &mut [u8]) -> I2CResult<()> {
89        self.regmap.read(data)
90    }
91
92    fn write(&mut self, data: &[u8]) -> I2CResult<()> {
93        self.regmap.write(data)
94    }
95
96    fn smbus_write_quick(&mut self, _bit: bool) -> I2CResult<()> {
97        unimplemented!()
98    }
99
100    fn smbus_read_block_data(&mut self, _register: u8) -> I2CResult<Vec<u8>> {
101        unimplemented!()
102    }
103
104    fn smbus_write_block_data(&mut self, _register: u8, _values: &[u8]) -> I2CResult<()> {
105        unimplemented!()
106    }
107
108    fn smbus_process_block(&mut self, _register: u8, _values: &[u8]) -> I2CResult<Vec<u8>> {
109        unimplemented!()
110    }
111
112    fn smbus_read_i2c_block_data(&mut self, _register: u8, _len: u8) -> I2CResult<Vec<u8>> {
113        unimplemented!()
114    }
115
116    fn smbus_write_i2c_block_data(&mut self, _register: u8, _values: &[u8]) -> I2CResult<()> {
117        unimplemented!()
118    }
119}
120
121#[derive(Debug)]
122enum MessageType<'a> {
123    Write(&'a [u8]),
124    Read(&'a mut [u8]),
125}
126
127/// Mock I2C message
128pub struct MockI2CMessage<'a> {
129    msg_type: MessageType<'a>,
130}
131
132impl<'a> I2CMessage<'a> for MockI2CMessage<'a> {
133    fn read(data: &'a mut [u8]) -> Self {
134        Self {
135            msg_type: MessageType::Read(data),
136        }
137    }
138
139    /// Write data to device
140    fn write(data: &'a [u8]) -> Self {
141        Self {
142            msg_type: MessageType::Write(data),
143        }
144    }
145}
146
147impl<'a> I2CTransfer<'a> for MockI2CDevice
148where
149    MockI2CDevice: I2CDevice,
150{
151    type Error = io::Error;
152    type Message = MockI2CMessage<'a>;
153
154    /// Issue the provided sequence of I2C transactions
155    fn transfer(&mut self, messages: &'a mut [Self::Message]) -> Result<u32, Self::Error> {
156        for msg in messages.iter_mut() {
157            match &mut msg.msg_type {
158                MessageType::Read(data) => self.read(data)?,
159                MessageType::Write(data) => self.write(data)?,
160            }
161        }
162        Ok(messages.len() as u32)
163    }
164}
165
166#[cfg(test)]
167mod test {
168    use super::*;
169
170    #[test]
171    fn test_can_read_at_zero_offset() {
172        let mut mock_device = MockI2CDevice::new();
173        mock_device.regmap.write_regs(0x0, &[0x1u8; 4]);
174        mock_device.read(&mut [0x0u8; 4]).unwrap();
175    }
176}