pub mod ak8963;
pub mod fram;
pub mod i2c;
pub mod icm20608;
mod invensense;
pub mod lis3mdl;
pub mod memory_card;
pub mod mpu9250;
pub mod ms5611;
pub mod nmea;
pub mod sd;
pub mod spi;
pub mod uart;
use crate::snapshot::{Error, Reader, Store, Writer};
#[derive(Debug)]
pub struct Place<T: ?Sized> {
chip: Box<T>,
silent: bool,
waiting: Option<bool>,
open: bool,
ended: u64,
flip: u64,
lose: u32,
losing: bool,
}
impl<T: Store + ?Sized> Store for Place<T> {
fn store(&self, to: &mut Writer) -> Result<(), Error> {
let Self {
chip,
silent,
waiting,
open,
ended,
flip,
lose,
losing,
} = self;
to.put(silent)?;
to.put(waiting)?;
to.put(open)?;
to.put(ended)?;
to.put(flip)?;
to.put(lose)?;
to.put(losing)?;
chip.store(to)
}
fn load(&mut self, from: &mut Reader) -> Result<(), Error> {
let Self {
chip,
silent,
waiting,
open,
ended,
flip,
lose,
losing,
} = self;
*silent = from.take()?;
*waiting = from.take()?;
*open = from.take()?;
*ended = from.take()?;
*flip = from.take()?;
*lose = from.take()?;
*losing = from.take()?;
chip.load(from)
}
}
impl<T: ?Sized> Place<T> {
#[must_use]
pub fn new(chip: Box<T>) -> Self {
Self {
chip,
silent: false,
waiting: None,
open: false,
ended: 0,
flip: 0,
lose: 0,
losing: false,
}
}
pub fn answering(&mut self) -> Option<&mut T> {
(!self.silent && !self.losing).then_some(&mut *self.chip)
}
#[must_use]
pub fn chip(&self) -> &T {
&self.chip
}
pub fn chip_mut(&mut self) -> &mut T {
&mut self.chip
}
pub fn silence(&mut self, silent: bool) {
self.silent = silent;
self.waiting = None;
}
pub fn silence_at_release(&mut self, silent: bool) {
self.waiting = Some(silent);
}
pub fn begin(&mut self) {
self.open = true;
if self.lose > 0 {
self.lose -= 1;
self.losing = true;
}
}
pub fn release(&mut self) {
if std::mem::take(&mut self.open) {
self.ended += 1;
}
self.losing = false;
if let Some(silent) = self.waiting.take() {
self.silent = silent;
}
}
pub fn answered(&mut self, word: u32) -> u32 {
let flip = std::mem::take(&mut self.flip) & u64::from(u32::MAX);
word ^ u32::try_from(flip).expect("masked to the word's width")
}
pub fn sent(&mut self, word: u32) -> Option<u32> {
self.begin();
let word = (!self.losing).then(|| self.answered(word));
self.release();
word
}
}
pub trait Placed {
fn ended(&self) -> u64;
fn flip(&mut self, mask: u64);
fn drop_next(&mut self);
}
impl<T: ?Sized> Placed for Place<T> {
fn ended(&self) -> u64 {
self.ended
}
fn flip(&mut self, mask: u64) {
self.flip ^= mask;
}
fn drop_next(&mut self) {
self.lose += 1;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_silent_place_keeps_its_chip_from_the_controller_and_not_from_the_board() {
let mut place = Place::new(Box::new(7_u8));
assert_eq!(place.answering().copied(), Some(7));
place.silence(true);
assert_eq!(place.answering(), None);
*place.chip_mut() = 8;
assert_eq!(*place.chip(), 8, "the board still reaches it");
place.silence(false);
assert_eq!(place.answering().copied(), Some(8), "and it answers again");
}
#[test]
fn a_place_counts_the_transactions_that_end_and_a_release_with_none_open_counts_nothing() {
let mut place = Place::new(Box::new(7_u8));
place.release();
assert_eq!(place.ended(), 0);
place.begin();
assert_eq!(place.ended(), 0, "not until it ends");
place.release();
place.release();
assert_eq!(place.ended(), 1);
}
#[test]
fn a_flip_takes_the_next_word_alone() {
let mut place = Place::new(Box::new(7_u8));
assert_eq!(place.answered(0x1234), 0x1234);
place.flip(0x0101);
assert_eq!(place.answered(0x1234), 0x1335);
assert_eq!(place.answered(0x1234), 0x1234, "once");
}
#[test]
fn a_drop_takes_the_next_transaction_whole_and_lets_the_one_under_way_finish() {
let mut place = Place::new(Box::new(7_u8));
place.begin();
place.drop_next();
assert_eq!(place.answering().copied(), Some(7), "the one under way");
place.release();
place.begin();
assert_eq!(place.answering(), None, "the next is lost");
place.release();
place.begin();
assert_eq!(place.answering().copied(), Some(7), "and only that one");
place.release();
assert_eq!(place.ended(), 3, "a lost transaction still happened");
}
#[test]
fn a_drop_during_a_lost_transaction_loses_the_next_too_and_two_flips_compose() {
let mut place = Place::new(Box::new(7_u8));
place.drop_next();
place.begin();
place.drop_next();
assert_eq!(place.answering(), None, "the one under way stays lost");
place.release();
place.begin();
assert_eq!(place.answering(), None, "and so is the next");
place.release();
place.begin();
assert_eq!(place.answering().copied(), Some(7));
place.flip(0x3);
place.flip(0x1);
assert_eq!(place.answered(0), 0x2, "a bit flipped twice is as it was");
}
#[test]
fn a_word_on_a_serial_line_is_a_transaction_that_a_drop_loses_and_a_flip_changes() {
let mut place = Place::new(Box::new(7_u8));
assert_eq!(place.sent(0x41), Some(0x41));
place.drop_next();
place.flip(0x01);
assert_eq!(place.sent(0x41), None, "lost, and the flip waits");
assert_eq!(place.sent(0x41), Some(0x40));
assert_eq!(place.ended(), 3);
}
#[test]
fn a_silence_asked_for_mid_transaction_waits_for_its_release() {
let mut place = Place::new(Box::new(7_u8));
place.silence_at_release(true);
assert_eq!(
place.answering().copied(),
Some(7),
"the transaction finishes"
);
place.release();
assert_eq!(place.answering(), None);
place.silence_at_release(false);
place.silence(true);
place.release();
assert_eq!(
place.answering(),
None,
"a silence from now on replaces one waiting"
);
}
}