use embedded_hal as hal;
use core::fmt;
use crate::constants::ROWS_SIZE;
use crate::types::DisplayDataAddress;
#[derive(Debug)]
pub struct I2cMockError;
#[cfg(feature = "std")]
impl std::error::Error for I2cMockError {}
impl fmt::Display for I2cMockError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "I2c MockError")
}
}
pub struct I2cMock {
pub data_values: [u8; ROWS_SIZE],
}
impl I2cMock {
pub fn new() -> Self {
I2cMock {
data_values: [0; ROWS_SIZE],
}
}
}
impl hal::blocking::i2c::WriteRead for I2cMock {
type Error = I2cMockError;
fn write_read(
&mut self,
_address: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), Self::Error> {
let mut data_offset = (bytes[0] ^ DisplayDataAddress::ROW_0.bits()) as usize;
for value in buffer.iter_mut() {
*value = self.data_values[data_offset];
data_offset = (data_offset + 1) % self.data_values.len();
}
Ok(())
}
}
impl hal::blocking::i2c::Write for I2cMock {
type Error = I2cMockError;
fn write(&mut self, _address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
if bytes.len() == 1 {
return Ok(());
}
let mut data_offset = (bytes[0] ^ DisplayDataAddress::ROW_0.bits()) as usize;
let data = &bytes[1..];
for value in data.iter() {
self.data_values[data_offset] = *value;
data_offset = (data_offset + 1) % self.data_values.len();
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use hal::blocking::i2c::{Write, WriteRead};
const ADDRESS: u8 = 0;
#[test]
fn new() {
let _i2c_mock = I2cMock::new();
}
#[test]
fn write() {
let mut i2c_mock = I2cMock::new();
let write_buffer = [super::DisplayDataAddress::ROW_0.bits(), 1u8, 1u8];
i2c_mock.write(ADDRESS, &write_buffer).unwrap();
for value in 0..i2c_mock.data_values.len() {
match value {
0 | 1 => assert_eq!(
i2c_mock.data_values[value], 1,
"index [{}] should be 1, found [{}]",
value, i2c_mock.data_values[value]
),
_ => assert_eq!(
i2c_mock.data_values[value], 0,
"index [{}] should be 0, found [{}]",
value, i2c_mock.data_values[value]
),
}
}
}
#[test]
fn write_with_offset() {
let mut i2c_mock = I2cMock::new();
let offset = 4u8;
let write_buffer = [super::DisplayDataAddress::ROW_0.bits() | offset, 1u8, 1u8];
i2c_mock.write(ADDRESS, &write_buffer).unwrap();
for value in 0..i2c_mock.data_values.len() {
match value {
4 | 5 => assert_eq!(
i2c_mock.data_values[value], 1,
"index [{}] should be 1, found [{}]",
value, i2c_mock.data_values[value]
),
_ => assert_eq!(
i2c_mock.data_values[value], 0,
"index [{}] should be 0, found [{}]",
value, i2c_mock.data_values[value]
),
}
}
}
#[test]
fn write_with_wraparound() {
let mut i2c_mock = I2cMock::new();
let mut write_buffer = [1u8; super::ROWS_SIZE + 3];
write_buffer[0] = super::DisplayDataAddress::ROW_0.bits();
write_buffer[write_buffer.len() - 1] = 2;
write_buffer[write_buffer.len() - 2] = 2;
i2c_mock.write(ADDRESS, &write_buffer).unwrap();
for value in 0..i2c_mock.data_values.len() {
match value {
0 | 1 => assert_eq!(
i2c_mock.data_values[value], 2,
"index [{}] should be 2, found [{}]",
value, i2c_mock.data_values[value]
),
_ => assert_eq!(
i2c_mock.data_values[value], 1,
"index [{}] should be 1, found [{}]",
value, i2c_mock.data_values[value]
),
}
}
}
#[test]
fn write_with_wraparound_and_offset() {
let mut i2c_mock = I2cMock::new();
let mut write_buffer = [1u8; super::ROWS_SIZE + 3];
let offset = 4u8;
write_buffer[0] = super::DisplayDataAddress::ROW_0.bits() | offset;
write_buffer[write_buffer.len() - 1] = 2;
write_buffer[write_buffer.len() - 2] = 2;
i2c_mock.write(ADDRESS, &write_buffer).unwrap();
for value in 0..i2c_mock.data_values.len() {
match value {
4 | 5 => assert_eq!(
i2c_mock.data_values[value], 2,
"index [{}] should be 2, found [{}]",
value, i2c_mock.data_values[value]
),
_ => assert_eq!(
i2c_mock.data_values[value], 1,
"index [{}] should be 1, found [{}]",
value, i2c_mock.data_values[value]
),
}
}
}
#[test]
fn write_read() {
let mut i2c_mock = I2cMock::new();
i2c_mock.data_values[0] = 1;
i2c_mock.data_values[1] = 1;
let mut read_buffer = [0u8; super::ROWS_SIZE];
i2c_mock
.write_read(
ADDRESS,
&[super::DisplayDataAddress::ROW_0.bits()],
&mut read_buffer,
)
.unwrap();
for value in 0..read_buffer.len() {
match value {
0 | 1 => assert_eq!(
read_buffer[value], 1,
"index [{}] should be 1, found [{}]",
value, read_buffer[value]
),
_ => assert_eq!(
read_buffer[value], 0,
"index [{}] should be 0, found [{}]",
value, read_buffer[value]
),
}
}
}
#[test]
fn write_read_offset() {
let mut i2c_mock = I2cMock::new();
i2c_mock.data_values[2] = 1;
i2c_mock.data_values[3] = 1;
let mut read_buffer = [0u8; 4];
let offset = 2u8;
i2c_mock
.write_read(
ADDRESS,
&[super::DisplayDataAddress::ROW_0.bits() | offset],
&mut read_buffer,
)
.unwrap();
for value in 0..read_buffer.len() {
match value {
0 | 1 => assert_eq!(
read_buffer[value], 1,
"index [{}] should be 1, found [{}]",
value, read_buffer[value]
),
_ => assert_eq!(
read_buffer[value], 0,
"index [{}] should be 0, found [{}]",
value, read_buffer[value]
),
}
}
}
#[test]
fn write_read_wraparound() {
let mut i2c_mock = I2cMock::new();
i2c_mock.data_values[2] = 1;
i2c_mock.data_values[3] = 1;
let mut read_buffer = [0u8; super::ROWS_SIZE + 4];
i2c_mock
.write_read(
ADDRESS,
&[super::DisplayDataAddress::ROW_0.bits()],
&mut read_buffer,
)
.unwrap();
for value in 0..read_buffer.len() {
match value {
2 | 3 | 18 | 19 => assert_eq!(
read_buffer[value], 1,
"index [{}] should be 1, found [{}]",
value, read_buffer[value]
),
_ => assert_eq!(
read_buffer[value], 0,
"index [{}] should be 0, found [{}]",
value, read_buffer[value]
),
}
}
}
#[test]
fn write_read_wraparound_and_offset() {
let mut i2c_mock = I2cMock::new();
i2c_mock.data_values[0] = 1;
i2c_mock.data_values[1] = 1;
let mut read_buffer = [0u8; super::ROWS_SIZE];
let offset = 4u8;
i2c_mock
.write_read(
ADDRESS,
&[super::DisplayDataAddress::ROW_0.bits() | offset],
&mut read_buffer,
)
.unwrap();
for value in 0..read_buffer.len() {
match value {
12 | 13 => assert_eq!(
read_buffer[value], 1,
"index [{}] should be 1, found [{}]",
value, read_buffer[value]
),
_ => assert_eq!(
read_buffer[value], 0,
"index [{}] should be 0, found [{}]",
value, read_buffer[value]
),
}
}
}
}