-
Notifications
You must be signed in to change notification settings - Fork 11
/
interface.rs
158 lines (138 loc) · 4.28 KB
/
interface.rs
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
//! I2C/SPI interfaces
use crate::{private, Error};
use embedded_hal::{i2c, spi::SpiDevice};
const I2C_DEV_BASE_ADDR: u8 = 0x68;
/// I2C interface
#[derive(Debug)]
pub struct I2cInterface<I2C> {
pub(crate) i2c: I2C,
pub(crate) address: u8,
}
/// SPI interface
#[derive(Debug)]
pub struct SpiInterface<SPI> {
pub(crate) spi: SPI,
}
/// Possible slave addresses
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub enum SlaveAddr {
/// Default slave address
Default,
/// Alternative slave address providing bit value for the SDO pin
Alternative(bool),
}
impl Default for SlaveAddr {
/// Default slave address
fn default() -> Self {
SlaveAddr::Default
}
}
impl SlaveAddr {
/// The numerical address of the device
pub fn addr(self) -> u8 {
match self {
SlaveAddr::Default => I2C_DEV_BASE_ADDR,
SlaveAddr::Alternative(false) => I2C_DEV_BASE_ADDR,
SlaveAddr::Alternative(true) => I2C_DEV_BASE_ADDR | 1,
}
}
}
/// Write data
pub trait WriteData: private::Sealed {
/// Error type
type Error;
/// Write to an u8 register
fn write_register(&mut self, register: u8, data: u8) -> Result<(), Self::Error>;
/// Write data. The first element corresponds to the starting address.
fn write_data(&mut self, payload: &mut [u8]) -> Result<(), Self::Error>;
}
impl<I2C, E> WriteData for I2cInterface<I2C>
where
I2C: i2c::I2c<Error = E>,
{
type Error = Error<E>;
fn write_register(&mut self, register: u8, data: u8) -> Result<(), Self::Error> {
let payload: [u8; 2] = [register, data];
let addr = self.address;
self.i2c.write(addr, &payload).map_err(Error::Comm)
}
fn write_data(&mut self, payload: &mut [u8]) -> Result<(), Self::Error> {
let addr = self.address;
self.i2c.write(addr, payload).map_err(Error::Comm)
}
}
impl<SPI, CommE> WriteData for SpiInterface<SPI>
where
SPI: SpiDevice<u8, Error = CommE>,
{
type Error = Error<CommE>;
fn write_register(&mut self, register: u8, data: u8) -> Result<(), Self::Error> {
let payload: [u8; 2] = [register, data];
self.spi.write(&payload).map_err(Error::Comm)
}
fn write_data(&mut self, payload: &mut [u8]) -> Result<(), Self::Error> {
self.spi.write(payload).map_err(Error::Comm)
}
}
/// Read data
pub trait ReadData: private::Sealed {
/// Error type
type Error;
/// Read an u8 register
fn read_register(&mut self, register: u8) -> Result<u8, Self::Error>;
/// Read some data. The first element corresponds to the starting address.
fn read_data(&mut self, payload: &mut [u8]) -> Result<(), Self::Error>;
}
impl<I2C, E> ReadData for I2cInterface<I2C>
where
I2C: i2c::I2c<Error = E>,
{
type Error = Error<E>;
fn read_register(&mut self, register: u8) -> Result<u8, Self::Error> {
let mut data = [0];
let addr = self.address;
self.i2c
.write_read(addr, &[register], &mut data)
.map_err(Error::Comm)
.and(Ok(data[0]))
}
fn read_data(&mut self, payload: &mut [u8]) -> Result<(), Self::Error> {
let len = payload.len();
let addr = self.address;
self.i2c
.write_read(addr, &[payload[0]], &mut payload[1..len])
.map_err(Error::Comm)
}
}
impl<SPI, CommE> ReadData for SpiInterface<SPI>
where
SPI: SpiDevice<u8, Error = CommE>,
{
type Error = Error<CommE>;
fn read_register(&mut self, register: u8) -> Result<u8, Self::Error> {
let mut data = [register + 0x80, 0];
self.spi.transfer_in_place(&mut data).map_err(Error::Comm)?;
Ok(data[1])
}
fn read_data(&mut self, payload: &mut [u8]) -> Result<(), Self::Error> {
payload[0] += 0x80;
self.spi.transfer_in_place(payload).map_err(Error::Comm)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::SlaveAddr;
use super::I2C_DEV_BASE_ADDR as ADDR;
#[test]
fn can_get_default_address() {
let addr = SlaveAddr::default();
assert_eq!(ADDR, addr.addr());
}
#[test]
fn can_generate_alternative_addresses() {
assert_eq!(ADDR, SlaveAddr::Alternative(false).addr());
assert_eq!(ADDR | 1, SlaveAddr::Alternative(true).addr());
}
}