pamoja_hal/sim.rs
1//! A part that is not there, answering from a register map.
2//!
3//! [`script`](crate::script) plays one exact conversation: these transfers, in this order,
4//! and anything else is refused. That is what proves a driver follows a datasheet, and it is
5//! a lot to write out before a driver has been run even once.
6//!
7//! This is the other half. An [`I2cPart`] is a register map with an address on the front of
8//! it: a write puts bytes at a register and the ones after it, a read takes them back, and
9//! the part does not mind what order any of that happens in. Give it a chip id and whatever
10//! a driver reads, and the driver runs against it with nothing plugged in and no transfer
11//! sequence written down.
12//!
13//! Parts come in three shapes, and there is one for each:
14//!
15//! - [`I2cPart`], registers a byte wide, as Bosch's BME280 and BMP280 have.
16//! - [`WordPart`], registers sixteen bits wide, as Texas Instruments' parts have, with bits
17//! the part sets for itself marked read-only.
18//! - `CommandPart` (feature `alloc`), commands and the replies they leave, as Sensirion's
19//! parts take.
20//!
21//! A simulated bus holds any of them as a `Part`, and gives each back as its own kind.
22//!
23//! Which to reach for:
24//!
25//! - A part here, when the question is what a driver does with what it reads, or when you
26//! are writing a driver and want to run it before the hardware arrives.
27//! - A [script](crate::script), when the question is whether the exact transfers a datasheet
28//! prescribes went out, in order and no others.
29//!
30//! Almost every I2C part addresses its registers with one byte and moves through them as it
31//! is read, so a map of 256 registers holds one whole part and needs no allocator.
32
33use embedded_hal::i2c::{
34 ErrorKind, ErrorType, I2c, NoAcknowledgeSource, Operation, SevenBitAddress,
35};
36
37/// How many registers a part holds, which is every address one byte reaches.
38pub const REGISTERS: usize = 256;
39
40/// What a simulated part refuses.
41#[derive(Clone, Copy, Debug, PartialEq, Eq)]
42pub enum PartError {
43 /// A transfer was addressed to something else on the bus.
44 WrongAddress {
45 /// The address the transfer went to.
46 asked: u8,
47 /// The address this part answers to.
48 answers: u8,
49 },
50 /// A transfer asked for a register before saying which one.
51 NoRegister,
52 /// A read reached a part that takes commands when no command had left it a reply, which
53 /// a real part answers by not acknowledging.
54 NoReply,
55}
56
57impl core::fmt::Display for PartError {
58 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
59 match self {
60 PartError::WrongAddress { asked, answers } => write!(
61 f,
62 "a transfer to {asked:#04x} reached the part at {answers:#04x}"
63 ),
64 PartError::NoRegister => {
65 f.write_str("a read came before anything said which register to read")
66 }
67 PartError::NoReply => f.write_str("a read came when no command had left a reply"),
68 }
69 }
70}
71
72impl core::error::Error for PartError {}
73
74impl embedded_hal::i2c::Error for PartError {
75 fn kind(&self) -> ErrorKind {
76 match self {
77 PartError::WrongAddress { .. } => {
78 ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address)
79 }
80 PartError::NoRegister => ErrorKind::Other,
81 PartError::NoReply => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address),
82 }
83 }
84}
85
86/// A part on an I2C bus, answering from its registers.
87///
88/// # Examples
89///
90/// ```
91/// use pamoja_hal::i2c::I2c;
92/// use pamoja_hal::sim::I2cPart;
93///
94/// // A BME280, whose chip id register holds the id its datasheet gives.
95/// const BME280: u8 = 0x76;
96/// const CHIP_ID_REGISTER: u8 = 0xD0;
97/// const BME280_CHIP_ID: u8 = 0x60;
98/// let mut part = I2cPart::new(BME280).holding(CHIP_ID_REGISTER, &[BME280_CHIP_ID]);
99///
100/// let mut id = [0u8; 1];
101/// part.write_read(BME280, &[CHIP_ID_REGISTER], &mut id).unwrap();
102/// assert_eq!(id, [BME280_CHIP_ID]);
103///
104/// // What a driver writes stays written, so a test can read its configuration back: here
105/// // one temperature sample, one pressure sample, and forced mode, in ctrl_meas.
106/// const CTRL_MEAS: u8 = 0xF4;
107/// const FORCED_ONCE: u8 = 0b001_001_01;
108/// part.write(BME280, &[CTRL_MEAS, FORCED_ONCE]).unwrap();
109/// assert_eq!(part.register(CTRL_MEAS), FORCED_ONCE);
110/// ```
111#[derive(Clone, Debug)]
112pub struct I2cPart {
113 address: u8,
114 registers: [u8; REGISTERS],
115 pointer: Option<u8>,
116 transfers: usize,
117 rules: Rules,
118}
119
120/// The rules a part with byte-wide registers keeps beyond plain memory: which writes it takes,
121/// what a read returns, and where its register pointer moves.
122///
123/// [`Rules::MEMORY`] stores every byte written, reads back what it stored, and moves on one
124/// register a byte, which is most parts. A part whose datasheet says otherwise, such as one
125/// that ignores a register while it runs or loads many registers from one write, gives its
126/// own functions. They are plain functions over the register map, so a part that keeps
127/// rules still needs no allocator.
128///
129/// # Examples
130///
131/// ```
132/// use pamoja_hal::i2c::I2c;
133/// use pamoja_hal::sim::{I2cPart, Rules, REGISTERS};
134///
135/// // A PCA9685 takes a new PWM frequency only while it sleeps: its prescale register
136/// // ignores a write unless the SLEEP bit of MODE1 is set.
137/// const PCA9685: u8 = 0x40;
138/// const MODE1: u8 = 0x00;
139/// const SLEEP: u8 = 1 << 4;
140/// const PRE_SCALE: u8 = 0xFE;
141/// fn write(registers: &mut [u8; REGISTERS], register: u8, value: u8) {
142/// if register != PRE_SCALE || registers[usize::from(MODE1)] & SLEEP != 0 {
143/// registers[usize::from(register)] = value;
144/// }
145/// }
146/// let rules = Rules { write, ..Rules::MEMORY };
147///
148/// // Awake, at its power-on prescale of 30, about 200 Hz from its 25 MHz clock.
149/// let mut part = I2cPart::new(PCA9685).following(rules).holding(PRE_SCALE, &[30]);
150///
151/// // 121 is the prescale for the 50 Hz a servo wants.
152/// part.write(PCA9685, &[PRE_SCALE, 121]).unwrap();
153/// assert_eq!(part.register(PRE_SCALE), 30, "ignored while it runs");
154/// part.write(PCA9685, &[MODE1, SLEEP]).unwrap();
155/// part.write(PCA9685, &[PRE_SCALE, 121]).unwrap();
156/// assert_eq!(part.register(PRE_SCALE), 121, "taken while it sleeps");
157/// ```
158#[derive(Clone, Copy, Debug)]
159pub struct Rules {
160 /// Takes one byte a driver wrote to a register: stores it, drops it, or loads it elsewhere.
161 pub write: fn(registers: &mut [u8; REGISTERS], register: u8, value: u8),
162 /// What a read of a register returns.
163 pub read: fn(registers: &[u8; REGISTERS], register: u8) -> u8,
164 /// Where the register pointer goes after a byte at a register is written or read.
165 pub next: fn(registers: &[u8; REGISTERS], register: u8) -> u8,
166}
167
168impl Rules {
169 /// Plain memory: every write stored, every read what was stored, one register a byte.
170 pub const MEMORY: Rules = Rules {
171 write: store,
172 read: stored,
173 next: following,
174 };
175}
176
177fn store(registers: &mut [u8; REGISTERS], register: u8, value: u8) {
178 registers[register as usize] = value;
179}
180
181fn stored(registers: &[u8; REGISTERS], register: u8) -> u8 {
182 registers[register as usize]
183}
184
185fn following(_registers: &[u8; REGISTERS], register: u8) -> u8 {
186 register.wrapping_add(1)
187}
188
189impl I2cPart {
190 /// A part answering at one address, with every register reading zero.
191 ///
192 /// # Arguments
193 ///
194 /// * `address` - the address it answers to.
195 ///
196 /// # Returns
197 ///
198 /// The part.
199 #[must_use]
200 pub const fn new(address: u8) -> I2cPart {
201 I2cPart {
202 address,
203 registers: [0; REGISTERS],
204 pointer: None,
205 transfers: 0,
206 rules: Rules::MEMORY,
207 }
208 }
209
210 /// The same part, keeping its datasheet's rules for writes, reads, and its pointer.
211 ///
212 /// # Arguments
213 ///
214 /// * `rules` - the rules; see [`Rules`].
215 ///
216 /// # Returns
217 ///
218 /// The part.
219 #[must_use]
220 pub const fn following(mut self, rules: Rules) -> I2cPart {
221 self.rules = rules;
222 self
223 }
224
225 /// The same part, holding these bytes from a register on.
226 ///
227 /// # Arguments
228 ///
229 /// * `first` - the register the bytes start at.
230 /// * `bytes` - what to put there. Past the last register it wraps to the first.
231 ///
232 /// # Returns
233 ///
234 /// The part.
235 ///
236 /// # Examples
237 ///
238 /// ```
239 /// use pamoja_hal::sim::I2cPart;
240 ///
241 /// // A 16-bit reading, high byte first, lands in two registers from the first one.
242 /// let [high, low] = 1000u16.to_be_bytes();
243 /// let part = I2cPart::new(0x48).holding(0x00, &[high, low]);
244 /// assert_eq!([part.register(0x00), part.register(0x01)], [high, low]);
245 /// ```
246 #[must_use]
247 pub fn holding(mut self, first: u8, bytes: &[u8]) -> I2cPart {
248 self.load(first, bytes);
249 self
250 }
251
252 /// Puts bytes in the part, from a register on.
253 ///
254 /// # Arguments
255 ///
256 /// * `first` - the register the bytes start at.
257 /// * `bytes` - what to put there. Past the last register it wraps to the first.
258 pub fn load(&mut self, first: u8, bytes: &[u8]) {
259 for (offset, byte) in bytes.iter().enumerate() {
260 let at = first.wrapping_add(offset as u8);
261 self.registers[at as usize] = *byte;
262 }
263 }
264
265 /// What a register holds now.
266 ///
267 /// # Arguments
268 ///
269 /// * `register` - which one.
270 ///
271 /// # Returns
272 ///
273 /// Its value, which is what a driver wrote if it wrote one.
274 #[must_use]
275 pub const fn register(&self, register: u8) -> u8 {
276 self.registers[register as usize]
277 }
278
279 /// The address this part answers to.
280 ///
281 /// # Returns
282 ///
283 /// The address.
284 #[must_use]
285 pub const fn address(&self) -> u8 {
286 self.address
287 }
288
289 /// How many transfers the part has served.
290 ///
291 /// # Returns
292 ///
293 /// The count, one for each transfer a driver made, however many operations it held.
294 #[must_use]
295 pub const fn transfers(&self) -> usize {
296 self.transfers
297 }
298
299 fn check(&self, address: u8) -> Result<(), PartError> {
300 if address == self.address {
301 Ok(())
302 } else {
303 Err(PartError::WrongAddress {
304 asked: address,
305 answers: self.address,
306 })
307 }
308 }
309
310 // A write names a register and then fills it and the ones after it, as the rules allow.
311 fn take_write(&mut self, bytes: &[u8]) {
312 let Some((&first, rest)) = bytes.split_first() else {
313 return;
314 };
315 let mut at = first;
316 for &byte in rest {
317 (self.rules.write)(&mut self.registers, at, byte);
318 at = (self.rules.next)(&self.registers, at);
319 }
320 self.pointer = Some(at);
321 }
322
323 // A read takes from wherever the last write left off, moving on as the rules say.
324 fn take_read(&mut self, buffer: &mut [u8]) -> Result<(), PartError> {
325 let Some(first) = self.pointer else {
326 return Err(PartError::NoRegister);
327 };
328 let mut at = first;
329 for slot in buffer.iter_mut() {
330 *slot = (self.rules.read)(&self.registers, at);
331 at = (self.rules.next)(&self.registers, at);
332 }
333 self.pointer = Some(at);
334 Ok(())
335 }
336}
337
338impl ErrorType for I2cPart {
339 type Error = PartError;
340}
341
342impl I2c<SevenBitAddress> for I2cPart {
343 fn transaction(
344 &mut self,
345 address: SevenBitAddress,
346 operations: &mut [Operation<'_>],
347 ) -> Result<(), Self::Error> {
348 self.check(address)?;
349 self.transfers += 1;
350 for operation in operations {
351 match operation {
352 Operation::Write(bytes) => self.take_write(bytes),
353 Operation::Read(buffer) => self.take_read(buffer)?,
354 }
355 }
356 Ok(())
357 }
358}
359
360/// A part on an I2C bus whose registers are sixteen bits wide, answering from them.
361///
362/// This is how Texas Instruments lays out parts such as the TMP117, the INA219 and INA226,
363/// the OPT3001, the ADS1115, and the HDC1080. A pointer byte names a register and a register
364/// travels most significant byte first. A write of the pointer alone aims the next read; a
365/// write of the pointer and a word stores the word and leaves the pointer where it was; a read
366/// takes words from the pointer on, carrying into the next register when it runs past one, as
367/// an HDC1080 does after a triggered measurement.
368///
369/// Some bits are the part's to set, however a driver writes the register: a conversion-ready
370/// flag, an overflow flag. [`WordPart::read_only`] marks them, and they then read as the part
371/// holds them.
372///
373/// # Examples
374///
375/// ```
376/// use pamoja_hal::i2c::I2c;
377/// use pamoja_hal::sim::WordPart;
378///
379/// // A TMP117, from its datasheet: the device id register reads 0x0117, and Data_Ready,
380/// // bit 13 of the configuration register, is the part's to set.
381/// const TMP117: u8 = 0x48;
382/// const CONFIGURATION: u8 = 0x01;
383/// const DEVICE_ID: u8 = 0x0F;
384/// const DATA_READY: u16 = 1 << 13;
385/// let mut part = WordPart::new(TMP117)
386/// .holding(DEVICE_ID, 0x0117)
387/// .holding(CONFIGURATION, DATA_READY)
388/// .read_only(CONFIGURATION, DATA_READY);
389///
390/// let mut id = [0u8; 2];
391/// part.write_read(TMP117, &[DEVICE_ID], &mut id).unwrap();
392/// assert_eq!(u16::from_be_bytes(id), 0x0117);
393///
394/// // A driver writing the factory configuration leaves the flag as the part holds it.
395/// const CONFIG_RESET: u16 = 0x0220;
396/// let [high, low] = CONFIG_RESET.to_be_bytes();
397/// part.write(TMP117, &[CONFIGURATION, high, low]).unwrap();
398/// assert_eq!(part.word(CONFIGURATION), CONFIG_RESET | DATA_READY);
399/// ```
400#[derive(Clone, Debug)]
401pub struct WordPart {
402 address: u8,
403 registers: [u16; REGISTERS],
404 fixed: [u16; REGISTERS],
405 pointer: Option<u8>,
406 transfers: usize,
407}
408
409impl WordPart {
410 /// A part answering at one address, with every register reading zero.
411 ///
412 /// # Arguments
413 ///
414 /// * `address` - the address it answers to.
415 ///
416 /// # Returns
417 ///
418 /// The part.
419 #[must_use]
420 pub const fn new(address: u8) -> WordPart {
421 WordPart {
422 address,
423 registers: [0; REGISTERS],
424 fixed: [0; REGISTERS],
425 pointer: None,
426 transfers: 0,
427 }
428 }
429
430 /// The same part, holding a value in one register.
431 ///
432 /// # Arguments
433 ///
434 /// * `register` - the register.
435 /// * `value` - what it holds, read-only bits included.
436 ///
437 /// # Returns
438 ///
439 /// The part.
440 #[must_use]
441 pub fn holding(mut self, register: u8, value: u16) -> WordPart {
442 self.set(register, value);
443 self
444 }
445
446 /// The same part, with some bits of one register left as the part holds them however a
447 /// driver writes the register.
448 ///
449 /// # Arguments
450 ///
451 /// * `register` - the register.
452 /// * `mask` - the bits that are the part's to set.
453 ///
454 /// # Returns
455 ///
456 /// The part.
457 #[must_use]
458 pub fn read_only(mut self, register: u8, mask: u16) -> WordPart {
459 self.fixed[register as usize] |= mask;
460 self
461 }
462
463 /// Puts a value in one register, read-only bits included, the way the part itself would.
464 ///
465 /// # Arguments
466 ///
467 /// * `register` - the register.
468 /// * `value` - what it holds.
469 pub fn set(&mut self, register: u8, value: u16) {
470 self.registers[register as usize] = value;
471 }
472
473 /// What one register holds now.
474 ///
475 /// # Arguments
476 ///
477 /// * `register` - which one.
478 ///
479 /// # Returns
480 ///
481 /// Its value, which is what a driver wrote there if it wrote one, apart from the
482 /// read-only bits.
483 #[must_use]
484 pub const fn word(&self, register: u8) -> u16 {
485 self.registers[register as usize]
486 }
487
488 /// The address this part answers to.
489 ///
490 /// # Returns
491 ///
492 /// The address.
493 #[must_use]
494 pub const fn address(&self) -> u8 {
495 self.address
496 }
497
498 /// How many transfers the part has served.
499 ///
500 /// # Returns
501 ///
502 /// The count, one for each transfer a driver made, however many operations it held.
503 #[must_use]
504 pub const fn transfers(&self) -> usize {
505 self.transfers
506 }
507
508 fn check(&self, address: u8) -> Result<(), PartError> {
509 if address == self.address {
510 Ok(())
511 } else {
512 Err(PartError::WrongAddress {
513 asked: address,
514 answers: self.address,
515 })
516 }
517 }
518
519 fn take_write(&mut self, bytes: &[u8]) {
520 let Some((&pointer, words)) = bytes.split_first() else {
521 return;
522 };
523 self.pointer = Some(pointer);
524 let mut at = pointer;
525 for pair in words.as_chunks::<2>().0 {
526 let written = u16::from_be_bytes(*pair);
527 let fixed = self.fixed[at as usize];
528 let held = self.registers[at as usize];
529 self.registers[at as usize] = (written & !fixed) | (held & fixed);
530 at = at.wrapping_add(1);
531 }
532 }
533
534 fn take_read(&mut self, buffer: &mut [u8]) -> Result<(), PartError> {
535 let Some(mut at) = self.pointer else {
536 return Err(PartError::NoRegister);
537 };
538 for pair in buffer.chunks_mut(2) {
539 let bytes = self.registers[at as usize].to_be_bytes();
540 pair.copy_from_slice(&bytes[..pair.len()]);
541 at = at.wrapping_add(1);
542 }
543 Ok(())
544 }
545}
546
547impl ErrorType for WordPart {
548 type Error = PartError;
549}
550
551impl I2c<SevenBitAddress> for WordPart {
552 fn transaction(
553 &mut self,
554 address: SevenBitAddress,
555 operations: &mut [Operation<'_>],
556 ) -> Result<(), Self::Error> {
557 self.check(address)?;
558 self.transfers += 1;
559 for operation in operations {
560 match operation {
561 Operation::Write(bytes) => self.take_write(bytes),
562 Operation::Read(buffer) => self.take_read(buffer)?,
563 }
564 }
565 Ok(())
566 }
567}
568
569/// A part on an I2C bus that takes commands rather than register addresses, answering each
570/// with the reply it was given for that command.
571///
572/// This is how Sensirion lays out parts such as the SHT3x and the SCD4x. A write sends a
573/// command, and any arguments after it; a read then takes the reply that command left, once.
574/// A command given no reply leaves none, and a read then is not acknowledged, which is what
575/// the real parts do when asked for data they do not have. A read longer than the reply gets
576/// `0xFF` for the rest, the level an idle bus reads.
577///
578/// # Examples
579///
580/// ```
581/// use pamoja_hal::i2c::I2c;
582/// use pamoja_hal::sim::CommandPart;
583///
584/// // An SHT3x, from its datasheet: the read-status command answers with the status word,
585/// // 0x8010 after a reset, then that word's CRC.
586/// const SHT3X: u8 = 0x44;
587/// const READ_STATUS: [u8; 2] = 0xF32Du16.to_be_bytes();
588/// const STATUS_AFTER_RESET: [u8; 3] = [0x80, 0x10, 0xE1];
589/// let mut part = CommandPart::new(SHT3X, 2).answering(&READ_STATUS, &STATUS_AFTER_RESET);
590///
591/// part.write(SHT3X, &READ_STATUS).unwrap();
592/// let mut status = [0u8; 3];
593/// part.read(SHT3X, &mut status).unwrap();
594/// assert_eq!(status, STATUS_AFTER_RESET);
595///
596/// // The reply was taken, so a second read finds nothing waiting.
597/// assert!(part.read(SHT3X, &mut status).is_err());
598/// assert_eq!(part.received(), [READ_STATUS.to_vec()]);
599/// ```
600#[cfg(feature = "alloc")]
601#[derive(Clone, Debug)]
602pub struct CommandPart {
603 address: u8,
604 width: usize,
605 replies: alloc::vec::Vec<(alloc::vec::Vec<u8>, alloc::vec::Vec<u8>)>,
606 waiting: Option<alloc::vec::Vec<u8>>,
607 received: alloc::vec::Vec<alloc::vec::Vec<u8>>,
608 transfers: usize,
609}
610
611#[cfg(feature = "alloc")]
612impl CommandPart {
613 /// A part answering at one address that has been given no replies yet.
614 ///
615 /// # Arguments
616 ///
617 /// * `address` - the address it answers to.
618 /// * `width` - how many bytes a command takes: two for Sensirion's 16-bit commands.
619 ///
620 /// # Returns
621 ///
622 /// The part.
623 #[must_use]
624 pub fn new(address: u8, width: usize) -> CommandPart {
625 CommandPart {
626 address,
627 width: width.max(1),
628 replies: alloc::vec::Vec::new(),
629 waiting: None,
630 received: alloc::vec::Vec::new(),
631 transfers: 0,
632 }
633 }
634
635 /// The same part, answering one command with a reply.
636 ///
637 /// # Arguments
638 ///
639 /// * `command` - the command's bytes.
640 /// * `reply` - what a read after it returns, in place of any reply given before.
641 ///
642 /// # Returns
643 ///
644 /// The part.
645 #[must_use]
646 pub fn answering(mut self, command: &[u8], reply: &[u8]) -> CommandPart {
647 self.answer(command, reply);
648 self
649 }
650
651 /// Answers one command with a reply from now on, in place of any reply given before.
652 ///
653 /// # Arguments
654 ///
655 /// * `command` - the command's bytes.
656 /// * `reply` - what a read after it returns.
657 pub fn answer(&mut self, command: &[u8], reply: &[u8]) {
658 match self.replies.iter_mut().find(|(held, _)| held == command) {
659 Some((_, held)) => *held = reply.to_vec(),
660 None => self.replies.push((command.to_vec(), reply.to_vec())),
661 }
662 }
663
664 /// Every write the part has received, oldest first.
665 ///
666 /// # Returns
667 ///
668 /// The writes, each a command and whatever arguments followed it.
669 #[must_use]
670 pub fn received(&self) -> &[alloc::vec::Vec<u8>] {
671 &self.received
672 }
673
674 /// The address this part answers to.
675 ///
676 /// # Returns
677 ///
678 /// The address.
679 #[must_use]
680 pub const fn address(&self) -> u8 {
681 self.address
682 }
683
684 /// How many transfers the part has served.
685 ///
686 /// # Returns
687 ///
688 /// The count, one for each transfer a driver made, however many operations it held.
689 #[must_use]
690 pub const fn transfers(&self) -> usize {
691 self.transfers
692 }
693
694 fn check(&self, address: u8) -> Result<(), PartError> {
695 if address == self.address {
696 Ok(())
697 } else {
698 Err(PartError::WrongAddress {
699 asked: address,
700 answers: self.address,
701 })
702 }
703 }
704
705 fn take_write(&mut self, bytes: &[u8]) {
706 self.received.push(bytes.to_vec());
707 let command = &bytes[..bytes.len().min(self.width)];
708 self.waiting = self
709 .replies
710 .iter()
711 .find(|(held, _)| held == command)
712 .map(|(_, reply)| reply.clone());
713 }
714
715 fn take_read(&mut self, buffer: &mut [u8]) -> Result<(), PartError> {
716 let reply = self.waiting.take().ok_or(PartError::NoReply)?;
717 for (index, slot) in buffer.iter_mut().enumerate() {
718 *slot = reply.get(index).copied().unwrap_or(0xFF);
719 }
720 Ok(())
721 }
722}
723
724#[cfg(feature = "alloc")]
725impl ErrorType for CommandPart {
726 type Error = PartError;
727}
728
729#[cfg(feature = "alloc")]
730impl I2c<SevenBitAddress> for CommandPart {
731 fn transaction(
732 &mut self,
733 address: SevenBitAddress,
734 operations: &mut [Operation<'_>],
735 ) -> Result<(), Self::Error> {
736 self.check(address)?;
737 self.transfers += 1;
738 for operation in operations {
739 match operation {
740 Operation::Write(bytes) => self.take_write(bytes),
741 Operation::Read(buffer) => self.take_read(buffer)?,
742 }
743 }
744 Ok(())
745 }
746}
747
748/// A simulated part of any of the three kinds, as a simulated bus holds it.
749///
750/// A word part carries two maps of 256 sixteen-bit registers, four times what a byte part
751/// holds, so it is boxed to keep every `Part` the size of the smaller two.
752#[cfg(feature = "alloc")]
753#[derive(Clone, Debug)]
754pub enum Part {
755 /// A part whose registers are a byte wide.
756 Bytes(I2cPart),
757 /// A part whose registers are sixteen bits wide.
758 Words(alloc::boxed::Box<WordPart>),
759 /// A part that takes commands.
760 Commands(CommandPart),
761}
762
763#[cfg(feature = "alloc")]
764impl Part {
765 /// The address this part answers to.
766 ///
767 /// # Returns
768 ///
769 /// The address.
770 #[must_use]
771 pub fn address(&self) -> u8 {
772 match self {
773 Part::Bytes(part) => part.address(),
774 Part::Words(part) => part.address(),
775 Part::Commands(part) => part.address(),
776 }
777 }
778
779 /// How many transfers the part has served.
780 ///
781 /// # Returns
782 ///
783 /// The count.
784 #[must_use]
785 pub fn transfers(&self) -> usize {
786 match self {
787 Part::Bytes(part) => part.transfers(),
788 Part::Words(part) => part.transfers(),
789 Part::Commands(part) => part.transfers(),
790 }
791 }
792}
793
794#[cfg(feature = "alloc")]
795impl From<I2cPart> for Part {
796 fn from(part: I2cPart) -> Part {
797 Part::Bytes(part)
798 }
799}
800
801#[cfg(feature = "alloc")]
802impl From<WordPart> for Part {
803 fn from(part: WordPart) -> Part {
804 Part::Words(alloc::boxed::Box::new(part))
805 }
806}
807
808#[cfg(feature = "alloc")]
809impl From<CommandPart> for Part {
810 fn from(part: CommandPart) -> Part {
811 Part::Commands(part)
812 }
813}
814
815#[cfg(feature = "alloc")]
816impl ErrorType for Part {
817 type Error = PartError;
818}
819
820#[cfg(feature = "alloc")]
821impl I2c<SevenBitAddress> for Part {
822 fn transaction(
823 &mut self,
824 address: SevenBitAddress,
825 operations: &mut [Operation<'_>],
826 ) -> Result<(), Self::Error> {
827 match self {
828 Part::Bytes(part) => part.transaction(address, operations),
829 Part::Words(part) => part.transaction(address, operations),
830 Part::Commands(part) => part.transaction(address, operations),
831 }
832 }
833}
834
835/// A kind of simulated part, taken back out of a [`Part`].
836#[cfg(feature = "alloc")]
837pub trait FromPart: Sized {
838 /// The part, when it is this kind.
839 ///
840 /// # Arguments
841 ///
842 /// * `part` - any simulated part.
843 ///
844 /// # Returns
845 ///
846 /// The part as this kind, or `None` when it is another.
847 fn from_part(part: Part) -> Option<Self>;
848}
849
850#[cfg(feature = "alloc")]
851impl FromPart for Part {
852 fn from_part(part: Part) -> Option<Part> {
853 Some(part)
854 }
855}
856
857#[cfg(feature = "alloc")]
858impl FromPart for I2cPart {
859 fn from_part(part: Part) -> Option<I2cPart> {
860 match part {
861 Part::Bytes(part) => Some(part),
862 _ => None,
863 }
864 }
865}
866
867#[cfg(feature = "alloc")]
868impl FromPart for WordPart {
869 fn from_part(part: Part) -> Option<WordPart> {
870 match part {
871 Part::Words(part) => Some(*part),
872 _ => None,
873 }
874 }
875}
876
877#[cfg(feature = "alloc")]
878impl FromPart for CommandPart {
879 fn from_part(part: Part) -> Option<CommandPart> {
880 match part {
881 Part::Commands(part) => Some(part),
882 _ => None,
883 }
884 }
885}
886
887#[cfg(test)]
888mod tests {
889 use super::*;
890
891 #[test]
892 fn a_read_takes_what_a_write_left() {
893 let mut part = I2cPart::new(0x76).holding(0x88, &[1, 2, 3, 4]);
894
895 let mut read = [0u8; 4];
896 part.write_read(0x76, &[0x88], &mut read).unwrap();
897 assert_eq!(read, [1, 2, 3, 4], "a block read walks the registers");
898 }
899
900 #[test]
901 fn what_a_driver_writes_is_what_the_part_holds() {
902 let mut part = I2cPart::new(0x76);
903
904 part.write(0x76, &[0xf4, 0x25]).unwrap();
905 assert_eq!(part.register(0xf4), 0x25);
906
907 // A longer write fills the registers after it, which is how a part takes a block.
908 part.write(0x76, &[0x10, 0xaa, 0xbb, 0xcc]).unwrap();
909 assert_eq!(part.register(0x10), 0xaa);
910 assert_eq!(part.register(0x12), 0xcc);
911 }
912
913 #[test]
914 fn a_transfer_to_another_address_is_refused() {
915 let mut part = I2cPart::new(0x76);
916 let mut read = [0u8; 1];
917
918 assert_eq!(
919 part.write_read(0x77, &[0xd0], &mut read),
920 Err(PartError::WrongAddress {
921 asked: 0x77,
922 answers: 0x76
923 })
924 );
925 }
926
927 #[test]
928 fn a_read_before_any_register_was_named_is_refused() {
929 let mut part = I2cPart::new(0x76);
930 let mut read = [0u8; 1];
931
932 assert_eq!(part.read(0x76, &mut read), Err(PartError::NoRegister));
933 }
934
935 #[test]
936 fn a_plain_read_carries_on_from_the_last_one() {
937 let mut part = I2cPart::new(0x76).holding(0x00, &[10, 20, 30, 40]);
938
939 let mut first = [0u8; 2];
940 part.write_read(0x76, &[0x00], &mut first).unwrap();
941 assert_eq!(first, [10, 20]);
942
943 // The part has moved on, the way a driver reading a burst in pieces expects.
944 let mut next = [0u8; 2];
945 part.read(0x76, &mut next).unwrap();
946 assert_eq!(next, [30, 40]);
947 }
948
949 #[test]
950 fn the_registers_wrap_rather_than_running_off_the_end() {
951 let mut part = I2cPart::new(0x76).holding(0xff, &[0x99]);
952 part.load(0x00, &[0x11]);
953
954 let mut read = [0u8; 2];
955 part.write_read(0x76, &[0xff], &mut read).unwrap();
956 assert_eq!(
957 read,
958 [0x99, 0x11],
959 "past the last register is the first one"
960 );
961 }
962
963 #[test]
964 fn a_word_part_keeps_its_read_only_bits_and_reads_on_into_the_next_register() {
965 let mut part = WordPart::new(0x40)
966 .holding(0x00, 0x6660)
967 .holding(0x01, 0x8A00)
968 .holding(0x02, 0x1000)
969 .read_only(0x02, 0x0003);
970
971 let mut both = [0u8; 4];
972 part.write(0x40, &[0x00]).unwrap();
973 part.read(0x40, &mut both).unwrap();
974 assert_eq!(both, [0x66, 0x60, 0x8A, 0x00], "temperature, then humidity");
975
976 part.write(0x40, &[0x02, 0xFF, 0xFC]).unwrap();
977 assert_eq!(
978 part.word(0x02),
979 0xFFFC,
980 "the read-only bits kept their zeros"
981 );
982 part.set(0x02, 0x0003);
983 assert_eq!(part.word(0x02), 0x0003, "the part itself may set them");
984
985 let mut odd = [0u8; 3];
986 part.write_read(0x40, &[0x00], &mut odd).unwrap();
987 assert_eq!(odd, [0x66, 0x60, 0x8A]);
988 assert_eq!(
989 WordPart::new(0x40).read(0x40, &mut odd),
990 Err(PartError::NoRegister)
991 );
992 assert_eq!(
993 part.write(0x41, &[0x00]),
994 Err(PartError::WrongAddress {
995 asked: 0x41,
996 answers: 0x40
997 })
998 );
999 }
1000
1001 #[test]
1002 fn a_command_part_answers_by_command_and_keeps_every_argument() {
1003 let mut part = CommandPart::new(0x62, 2)
1004 .answering(&[0xE4, 0xB8], &[0x80, 0x06])
1005 .answering(&[0xE4, 0xB8], &[0x80, 0x06, 0x95]);
1006
1007 part.write(0x62, &[0x24, 0x1D, 0x07, 0x92, 0x3A]).unwrap();
1008 let mut ready = [0u8; 4];
1009 assert_eq!(
1010 part.read(0x62, &mut ready),
1011 Err(PartError::NoReply),
1012 "a command with no reply leaves nothing"
1013 );
1014
1015 part.write(0x62, &[0xE4, 0xB8]).unwrap();
1016 part.read(0x62, &mut ready).unwrap();
1017 assert_eq!(
1018 ready,
1019 [0x80, 0x06, 0x95, 0xFF],
1020 "the later reply, then an idle bus"
1021 );
1022 assert_eq!(part.received()[0], [0x24, 0x1D, 0x07, 0x92, 0x3A]);
1023 assert_eq!(part.transfers(), 4);
1024 }
1025
1026 #[test]
1027 fn a_transfer_is_counted_once_however_many_operations_it_holds() {
1028 let mut part = I2cPart::new(0x76).holding(0xd0, &[0x60]);
1029 let mut read = [0u8; 1];
1030
1031 part.write(0x76, &[0xe0, 0xb6]).unwrap();
1032 part.write_read(0x76, &[0xd0], &mut read).unwrap();
1033 assert_eq!(part.transfers(), 2);
1034 }
1035}