1use embedded_hal::i2c::I2c;
7use rusty_esp_core::error::{Error, Result};
8
9use crate::sensor::{RegOp, Register, SensorDesc};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum RegWidth {
14 U8,
16 U16,
18}
19
20#[derive(Debug)]
22pub struct Sccb<I> {
23 i2c: I,
24 addr: u8,
25 width: RegWidth,
26}
27
28impl<I: I2c> Sccb<I> {
29 pub fn new(i2c: I, addr: u8, width: RegWidth) -> Self {
31 Sccb { i2c, addr, width }
32 }
33
34 pub fn for_sensor(i2c: I, desc: &SensorDesc) -> Self {
36 Sccb::new(i2c, desc.sccb_addr, desc.reg_width)
37 }
38
39 #[must_use]
41 pub fn addr(&self) -> u8 {
42 self.addr
43 }
44
45 pub fn release(self) -> I {
47 self.i2c
48 }
49
50 fn addr_bytes(&self, reg: u16) -> ([u8; 2], usize) {
51 match self.width {
52 RegWidth::U8 => ([reg as u8, 0], 1),
53 RegWidth::U16 => (reg.to_be_bytes(), 2),
54 }
55 }
56
57 pub fn write(&mut self, reg: u16, value: u8) -> Result<()> {
59 let (a, n) = self.addr_bytes(reg);
60 let mut buf = [0u8; 3];
61 buf[..n].copy_from_slice(&a[..n]);
62 buf[n] = value;
63 self.i2c
64 .write(self.addr, &buf[..=n])
65 .map_err(|_| Error::Hardware)
66 }
67
68 pub fn write_reg(&mut self, reg: Register) -> Result<()> {
70 self.write(reg.addr, reg.value)
71 }
72
73 pub fn read(&mut self, reg: u16) -> Result<u8> {
75 let (a, n) = self.addr_bytes(reg);
76 self.i2c
77 .write(self.addr, &a[..n])
78 .map_err(|_| Error::Hardware)?;
79 let mut v = [0u8; 1];
80 self.i2c
81 .read(self.addr, &mut v)
82 .map_err(|_| Error::Hardware)?;
83 Ok(v[0])
84 }
85
86 pub fn apply(&mut self, table: &[RegOp], mut delay_ms: impl FnMut(u16)) -> Result<usize> {
90 let mut written = 0;
91 for op in table {
92 match *op {
93 RegOp::Write { addr, value } => {
94 self.write(addr, value)?;
95 written += 1;
96 }
97 RegOp::DelayMs(ms) => delay_ms(ms),
98 }
99 }
100 Ok(written)
101 }
102
103 pub fn probe(&mut self, desc: &SensorDesc) -> Result<bool> {
105 let pid = match desc.pid_len {
106 1 => u16::from(self.read(desc.pid_reg)?),
107 2 => {
108 let hi = self.read(desc.pid_reg)?;
109 let lo = self.read(desc.pid_reg + 1)?;
110 u16::from_be_bytes([hi, lo])
111 }
112 _ => return Err(Error::InvalidFormat),
113 };
114 Ok(pid == desc.pid)
115 }
116}
117
118#[cfg(test)]
119pub(crate) mod fake {
120 use core::convert::Infallible;
124
125 use embedded_hal::i2c::{ErrorType, I2c, Operation, SevenBitAddress};
126
127 #[derive(Debug, Default)]
128 pub struct FakeSensor {
129 pub regs: std::collections::BTreeMap<u16, u8>,
130 pub last_addr: Option<u16>,
131 pub writes: std::vec::Vec<(u16, u8)>,
132 pub width16: bool,
133 }
134
135 impl ErrorType for FakeSensor {
136 type Error = Infallible;
137 }
138
139 impl I2c<SevenBitAddress> for FakeSensor {
140 fn transaction(
141 &mut self,
142 _address: SevenBitAddress,
143 operations: &mut [Operation<'_>],
144 ) -> Result<(), Infallible> {
145 for op in operations {
146 match op {
147 Operation::Write(bytes) => {
148 let (reg, rest) = if self.width16 {
149 (u16::from_be_bytes([bytes[0], bytes[1]]), &bytes[2..])
150 } else {
151 (u16::from(bytes[0]), &bytes[1..])
152 };
153 self.last_addr = Some(reg);
154 if let Some(&v) = rest.first() {
155 self.regs.insert(reg, v);
156 self.writes.push((reg, v));
157 }
158 }
159 Operation::Read(buf) => {
160 let reg = self.last_addr.unwrap_or(0);
161 for (i, b) in buf.iter_mut().enumerate() {
162 *b = *self.regs.get(&(reg + i as u16)).unwrap_or(&0);
163 }
164 }
165 }
166 }
167 Ok(())
168 }
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::fake::FakeSensor;
175 use super::*;
176 use crate::sensor::{SensorId, describe, ov2640, ov5640};
177
178 #[test]
179 fn write_read_apply_probe_8bit() {
180 let desc = describe(SensorId::Ov2640).unwrap();
181 let mut bus = Sccb::for_sensor(FakeSensor::default(), desc);
182 assert_eq!(bus.addr(), 0x30);
183 bus.write(0x12, 0x80).unwrap();
184 assert_eq!(bus.read(0x12).unwrap(), 0x80);
185 let mut delays = 0;
186 let n = bus
187 .apply(
188 &[
189 RegOp::Write {
190 addr: 0x0A,
191 value: 0x26,
192 },
193 RegOp::DelayMs(5),
194 RegOp::Write {
195 addr: 0x0B,
196 value: 0x42,
197 },
198 ],
199 |_| delays += 1,
200 )
201 .unwrap();
202 assert_eq!((n, delays), (2, 1));
203 assert!(bus.probe(desc).unwrap());
204 bus.write(0x0A, 0x00).unwrap();
205 assert!(!bus.probe(desc).unwrap());
206 let n = bus.apply(ov2640::SETTINGS_CIF, |_| {}).unwrap();
208 assert_eq!(n, ov2640::SETTINGS_CIF.len());
209 let inner = bus.release();
210 assert!(inner.writes.len() > 100);
211 }
212
213 #[test]
214 fn sixteen_bit_addresses() {
215 let desc = describe(SensorId::Ov5640).unwrap();
216 let mut bus = Sccb::for_sensor(
217 FakeSensor {
218 width16: true,
219 ..FakeSensor::default()
220 },
221 desc,
222 );
223 bus.write(0x300A, 0x56).unwrap();
224 bus.write(0x300B, 0x40).unwrap();
225 assert_eq!(bus.read(0x300A).unwrap(), 0x56);
226 assert!(bus.probe(desc).unwrap());
227 let mut delays = std::vec::Vec::new();
228 let n = bus
229 .apply(ov5640::DEFAULT_REGS, |ms| delays.push(ms))
230 .unwrap();
231 let writes = ov5640::DEFAULT_REGS
232 .iter()
233 .filter(|op| matches!(op, RegOp::Write { .. }))
234 .count();
235 assert_eq!(n, writes);
236 assert_eq!(
237 delays.len(),
238 ov5640::DEFAULT_REGS.len() - writes,
239 "every delay step reached the caller's clock"
240 );
241 }
242}