Skip to main content

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}