use serde::{Deserialize, Serialize};
#[derive(Default, Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct AlpideStats {
readout_flags: ReadoutFlags,
}
impl AlpideStats {
pub(crate) fn log_readout_flags(&mut self, chip_trailer: u8) {
self.readout_flags.log(chip_trailer);
}
pub fn readout_flags(&self) -> &ReadoutFlags {
&self.readout_flags
}
pub(crate) fn sum(&mut self, other: AlpideStats) {
self.readout_flags = self.readout_flags.sum(other.readout_flags);
}
pub(crate) fn validate_other(&self, other: &Self) -> Result<(), Vec<String>> {
let mut errs: Vec<String> = vec![];
if let Err(mut sub_errs) = self.readout_flags.validate_other(&other.readout_flags) {
errs.append(&mut sub_errs);
}
let _other = Self {
readout_flags: ReadoutFlags::default(),
};
if errs.is_empty() {
Ok(())
} else {
Err(errs)
}
}
}
#[derive(Default, Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct ReadoutFlags {
chip_trailers_seen: u32,
busy_violations: u32, data_overrun: u32, transmission_in_fatal: u32, flushed_incomplete: u32, strobe_extended: u32, busy_transitions: u32, }
impl ReadoutFlags {
const CHIP_TRAILER_BUSY_VIOLATION: u8 = 0b1011_1000;
const CHIP_TRAILER_DATA_OVERRUN: u8 = 0b1011_1100;
const CHIP_TRAILER_TRANSMISSION_IN_FATAL: u8 = 0b1011_1110;
pub fn log(&mut self, chip_trailer: u8) {
self.chip_trailers_seen += 1;
match chip_trailer {
Self::CHIP_TRAILER_BUSY_VIOLATION => self.busy_violations += 1,
Self::CHIP_TRAILER_DATA_OVERRUN => self.data_overrun += 1,
Self::CHIP_TRAILER_TRANSMISSION_IN_FATAL => self.transmission_in_fatal += 1,
val => {
self.flushed_incomplete += (val & 0b0000_0100 == 0b0000_0100) as u32;
self.strobe_extended += (val & 0b0000_0010 == 0b0000_0010) as u32;
self.busy_transitions += (val & 0b0000_0001 == 0b0000_0001) as u32;
}
}
}
pub fn chip_trailers_seen(&self) -> u32 {
self.chip_trailers_seen
}
pub fn busy_violations(&self) -> u32 {
self.busy_violations
}
pub fn flushed_incomplete(&self) -> u32 {
self.flushed_incomplete
}
pub fn strobe_extended(&self) -> u32 {
self.strobe_extended
}
pub fn busy_transitions(&self) -> u32 {
self.busy_transitions
}
pub fn data_overrun(&self) -> u32 {
self.data_overrun
}
pub fn transmission_in_fatal(&self) -> u32 {
self.transmission_in_fatal
}
fn sum(self, other: ReadoutFlags) -> Self {
Self {
chip_trailers_seen: self.chip_trailers_seen + other.chip_trailers_seen,
busy_violations: self.busy_violations + other.busy_violations,
flushed_incomplete: self.flushed_incomplete + other.flushed_incomplete,
strobe_extended: self.strobe_extended + other.strobe_extended,
busy_transitions: self.busy_transitions + other.busy_transitions,
data_overrun: self.data_overrun + other.data_overrun,
transmission_in_fatal: self.transmission_in_fatal + other.transmission_in_fatal,
}
}
pub(super) fn validate_other(&self, other: &Self) -> Result<(), Vec<String>> {
let other = Self {
chip_trailers_seen: other.chip_trailers_seen,
busy_violations: other.busy_violations,
flushed_incomplete: other.flushed_incomplete,
strobe_extended: other.strobe_extended,
busy_transitions: other.busy_transitions,
data_overrun: other.data_overrun,
transmission_in_fatal: other.transmission_in_fatal,
};
self.validate_fields(&other)
}
crate::validate_fields!(
ReadoutFlags,
chip_trailers_seen,
busy_violations,
flushed_incomplete,
strobe_extended,
busy_transitions,
data_overrun,
transmission_in_fatal
);
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_serde_consistency() {
let mut alpide_stats = AlpideStats::default();
alpide_stats.log_readout_flags(ReadoutFlags::CHIP_TRAILER_BUSY_VIOLATION);
let alpide_stats_ser_json = serde_json::to_string(&alpide_stats).unwrap();
let alpide_stats_de_json: AlpideStats =
serde_json::from_str(&alpide_stats_ser_json).unwrap();
assert_eq!(alpide_stats, alpide_stats_de_json);
println!("{}", serde_json::to_string_pretty(&alpide_stats).unwrap());
let alpide_stats_ser_toml = toml::to_string(&alpide_stats).unwrap();
let alpide_stats_de_toml: AlpideStats = toml::from_str(&alpide_stats_ser_toml).unwrap();
assert_eq!(alpide_stats, alpide_stats_de_toml);
println!("{alpide_stats_ser_toml}");
}
}