use deku::prelude::*;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, DekuRead, DekuWrite)]
#[deku(id_type = "u8", endian = "endian", ctx = "endian: deku::ctx::Endian")]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u8)]
pub enum SampleFrameIndicator {
#[deku(id = 0x0)]
NotApplicable = 0,
#[deku(id = 0x1)]
FirstDataPacket = 1,
#[deku(id = 0x2)]
MiddleDataPacket = 2,
#[deku(id = 0x3)]
FinalDataPacket = 3,
}
impl TryFrom<u32> for SampleFrameIndicator {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::NotApplicable),
1 => Ok(Self::FirstDataPacket),
2 => Ok(Self::MiddleDataPacket),
3 => Ok(Self::FinalDataPacket),
_ => Err(()),
}
}
}
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, DekuRead, DekuWrite,
)]
#[deku(endian = "endian", ctx = "endian: deku::ctx::Endian")]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Trailer(u32);
impl Trailer {
pub fn new() -> Self {
Default::default()
}
pub fn as_u32(self) -> u32 {
self.0
}
pub fn cal_time_enabled(&self) -> bool {
self.0 & (1 << 31) > 0
}
pub fn valid_data_enabled(&self) -> bool {
self.0 & (1 << 30) > 0
}
pub fn reference_lock_enabled(&self) -> bool {
self.0 & (1 << 29) > 0
}
pub fn agc_enabled(&self) -> bool {
self.0 & (1 << 28) > 0
}
pub fn detected_signal_enabled(&self) -> bool {
self.0 & (1 << 27) > 0
}
pub fn spectral_inversion_enabled(&self) -> bool {
self.0 & (1 << 26) > 0
}
pub fn over_range_enabled(&self) -> bool {
self.0 & (1 << 25) > 0
}
pub fn sample_loss_enabled(&self) -> bool {
self.0 & (1 << 24) > 0
}
pub fn sample_frame_enabled(&self) -> bool {
self.0 & (1 << 23) > 0 && self.0 & (1 << 22) > 0
}
pub fn user_defined_enabled(&self) -> bool {
self.0 & (1 << 21) > 0 && self.0 & (1 << 20) > 0
}
pub fn associated_context_packet_count_enabled(&self) -> bool {
self.0 & (1 << 7) > 0
}
pub fn cal_time_indicator(&self) -> Option<bool> {
self.cal_time_enabled().then_some(self.0 & (1 << 19) > 0)
}
pub fn set_cal_time_indicator(&mut self, value: Option<bool>) {
self.0 &= !(1 << 31) & !(1 << 19);
if let Some(v) = value {
self.0 |= 1 << 31;
self.0 |= (v as u32) << 19;
}
}
pub fn valid_data_indicator(&self) -> Option<bool> {
self.valid_data_enabled().then_some(self.0 & (1 << 18) > 0)
}
pub fn set_valid_data_indicator(&mut self, value: Option<bool>) {
self.0 &= !(1 << 30) & !(1 << 18);
if let Some(v) = value {
self.0 |= 1 << 30;
self.0 |= (v as u32) << 18;
}
}
pub fn reference_lock_indicator(&self) -> Option<bool> {
self.reference_lock_enabled()
.then_some(self.0 & (1 << 17) > 0)
}
pub fn set_reference_lock_indicator(&mut self, value: Option<bool>) {
self.0 &= !(1 << 29) & !(1 << 17);
if let Some(v) = value {
self.0 |= 1 << 29;
self.0 |= (v as u32) << 17;
}
}
pub fn agc_indicator(&self) -> Option<bool> {
self.agc_enabled().then_some(self.0 & (1 << 16) > 0)
}
pub fn set_agc_indicator(&mut self, value: Option<bool>) {
self.0 &= !(1 << 28) & !(1 << 16);
if let Some(v) = value {
self.0 |= 1 << 28;
self.0 |= (v as u32) << 16;
}
}
pub fn detected_signal_indicator(&self) -> Option<bool> {
self.detected_signal_enabled()
.then_some(self.0 & (1 << 15) > 0)
}
pub fn set_detected_signal_indicator(&mut self, value: Option<bool>) {
self.0 &= !(1 << 27) & !(1 << 15);
if let Some(v) = value {
self.0 |= 1 << 27;
self.0 |= (v as u32) << 15;
}
}
pub fn spectral_inversion_indicator(&self) -> Option<bool> {
self.spectral_inversion_enabled()
.then_some(self.0 & (1 << 14) > 0)
}
pub fn set_spectral_inversion_indicator(&mut self, value: Option<bool>) {
self.0 &= !(1 << 26) & !(1 << 14);
if let Some(v) = value {
self.0 |= 1 << 26;
self.0 |= (v as u32) << 14;
}
}
pub fn over_range_indicator(&self) -> Option<bool> {
self.over_range_enabled().then_some(self.0 & (1 << 13) > 0)
}
pub fn set_over_range_indicator(&mut self, value: Option<bool>) {
self.0 &= !(1 << 25) & !(1 << 13);
if let Some(v) = value {
self.0 |= 1 << 25;
self.0 |= (v as u32) << 13;
}
}
pub fn sample_loss_indicator(&self) -> Option<bool> {
self.sample_loss_enabled().then_some(self.0 & (1 << 12) > 0)
}
pub fn set_sample_loss_indicator(&mut self, value: Option<bool>) {
self.0 &= !(1 << 24) & !(1 << 12);
if let Some(v) = value {
self.0 |= 1 << 24;
self.0 |= (v as u32) << 12;
}
}
pub fn sample_frame_indicator(&self) -> Option<SampleFrameIndicator> {
self.sample_frame_enabled()
.then(|| ((self.0 >> 10) & 0b11).try_into().unwrap_or_else(|_|
unreachable!("0b11 mask guarantees a value in 0..=3, all of which are valid SampleFrameIndicator variants")
))
}
pub fn set_sample_frame_indicator(&mut self, value: Option<SampleFrameIndicator>) {
self.0 &= !(0b11 << 22) & !(0b11 << 10);
if let Some(v) = value {
self.0 |= 0b11 << 22;
self.0 |= (v as u32) << 10;
}
}
pub fn user_defined_indicator(&self) -> Option<u8> {
self.user_defined_enabled()
.then_some(((self.0 >> 8) & 0b11) as u8)
}
pub fn set_user_defined_indicator(&mut self, value: Option<u8>) {
debug_assert!(
value.map_or(true, |n| n <= 3),
"user-defined indicator must be in 0..=3"
);
self.0 &= !(0b11 << 20) & !(0b11 << 8);
if let Some(v) = value {
self.0 |= 0b11 << 20;
self.0 |= (u32::from(v) & 0b11) << 8;
}
}
pub fn associated_context_packet_count(&self) -> Option<u8> {
self.associated_context_packet_count_enabled()
.then_some((self.0 & 0x7F) as u8)
}
pub fn set_associated_context_packet_count(&mut self, value: Option<u8>) {
debug_assert!(
value.map_or(true, |n| n <= 127),
"associated context packet count must be in 0..=127"
);
self.0 &= !0xFF;
if let Some(n) = value {
self.0 |= 1 << 7;
self.0 |= u32::from(n) & 0x7F;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn trailer(raw: u32) -> Trailer {
Trailer(raw)
}
macro_rules! test_bool_indicator {
($mod:ident, $get:ident, $set:ident, enable = $en:literal, indicator = $ind:literal) => {
mod $mod {
use super::*;
#[test]
fn disabled_returns_none() {
assert_eq!(trailer(0).$get(), None);
}
#[test]
fn enabled_clear_returns_some_false() {
assert_eq!(trailer(1u32 << $en).$get(), Some(false));
}
#[test]
fn enabled_set_returns_some_true() {
assert_eq!(trailer((1u32 << $en) | (1u32 << $ind)).$get(), Some(true));
}
#[test]
fn setter_round_trips() {
let mut t = trailer(0);
t.$set(Some(true));
assert_eq!(t.$get(), Some(true));
t.$set(Some(false));
assert_eq!(t.$get(), Some(false));
t.$set(None);
assert_eq!(t.$get(), None);
}
#[test]
fn setter_none_clears_only_its_bits() {
let mask = (1u32 << $en) | (1u32 << $ind);
let mut t = trailer(u32::MAX);
t.$set(None);
assert_eq!(t.as_u32() & mask, 0, "enable/indicator bits not cleared");
assert_eq!(
t.as_u32() & !mask,
u32::MAX & !mask,
"unrelated bits were disturbed"
);
}
}
};
}
test_bool_indicator!(
cal_time,
cal_time_indicator,
set_cal_time_indicator,
enable = 31,
indicator = 19
);
test_bool_indicator!(
valid_data,
valid_data_indicator,
set_valid_data_indicator,
enable = 30,
indicator = 18
);
test_bool_indicator!(
reference_lock,
reference_lock_indicator,
set_reference_lock_indicator,
enable = 29,
indicator = 17
);
test_bool_indicator!(
agc,
agc_indicator,
set_agc_indicator,
enable = 28,
indicator = 16
);
test_bool_indicator!(
detected_signal,
detected_signal_indicator,
set_detected_signal_indicator,
enable = 27,
indicator = 15
);
test_bool_indicator!(
spectral_inversion,
spectral_inversion_indicator,
set_spectral_inversion_indicator,
enable = 26,
indicator = 14
);
test_bool_indicator!(
over_range,
over_range_indicator,
set_over_range_indicator,
enable = 25,
indicator = 13
);
test_bool_indicator!(
sample_loss,
sample_loss_indicator,
set_sample_loss_indicator,
enable = 24,
indicator = 12
);
mod sample_frame {
use super::*;
use SampleFrameIndicator::*;
const ENABLE: u32 = (1 << 23) | (1 << 22);
const MASK: u32 = ENABLE | (0b11 << 10);
#[test]
fn disabled_returns_none() {
assert_eq!(trailer(0).sample_frame_indicator(), None);
}
#[test]
fn only_one_enable_bit_set_returns_none() {
assert_eq!(trailer(1 << 23).sample_frame_indicator(), None);
assert_eq!(trailer(1 << 22).sample_frame_indicator(), None);
}
#[test]
fn all_variants_round_trip_via_raw_bits() {
for v in [
NotApplicable,
FirstDataPacket,
MiddleDataPacket,
FinalDataPacket,
] {
let t = trailer(ENABLE | ((v as u32) << 10));
assert_eq!(t.sample_frame_indicator(), Some(v), "{v:?}");
}
}
#[test]
fn setter_round_trips_all_variants() {
let mut t = trailer(0);
for v in [
NotApplicable,
FirstDataPacket,
MiddleDataPacket,
FinalDataPacket,
] {
t.set_sample_frame_indicator(Some(v));
assert_eq!(t.sample_frame_indicator(), Some(v), "{v:?}");
}
t.set_sample_frame_indicator(None);
assert_eq!(t.sample_frame_indicator(), None);
}
#[test]
fn setter_none_clears_only_its_bits() {
let mut t = trailer(u32::MAX);
t.set_sample_frame_indicator(None);
assert_eq!(t.as_u32() & MASK, 0, "enable/indicator bits not cleared");
assert_eq!(
t.as_u32() & !MASK,
u32::MAX & !MASK,
"unrelated bits were disturbed"
);
}
}
mod user_defined {
use super::*;
const ENABLE: u32 = (1 << 21) | (1 << 20);
const MASK: u32 = ENABLE | (0b11 << 8);
#[test]
fn disabled_returns_none() {
assert_eq!(trailer(0).user_defined_indicator(), None);
}
#[test]
fn only_one_enable_bit_set_returns_none() {
assert_eq!(trailer(1 << 21).user_defined_indicator(), None);
assert_eq!(trailer(1 << 20).user_defined_indicator(), None);
}
#[test]
fn all_two_bit_values_round_trip_via_raw_bits() {
for v in 0u8..=3 {
let t = trailer(ENABLE | (u32::from(v) << 8));
assert_eq!(t.user_defined_indicator(), Some(v), "value={v}");
}
}
#[test]
fn setter_round_trips_all_two_bit_values() {
let mut t = trailer(0);
for v in 0u8..=3 {
t.set_user_defined_indicator(Some(v));
assert_eq!(t.user_defined_indicator(), Some(v));
}
t.set_user_defined_indicator(None);
assert_eq!(t.user_defined_indicator(), None);
}
#[test]
fn setter_none_clears_only_its_bits() {
let mut t = trailer(u32::MAX);
t.set_user_defined_indicator(None);
assert_eq!(t.as_u32() & MASK, 0, "enable/indicator bits not cleared");
assert_eq!(
t.as_u32() & !MASK,
u32::MAX & !MASK,
"unrelated bits were disturbed"
);
}
}
mod context_packet_count {
use super::*;
const MASK: u32 = 0xFF;
#[test]
fn disabled_returns_none() {
assert_eq!(trailer(0).associated_context_packet_count(), None);
}
#[test]
fn count_without_enable_bit_returns_none() {
assert_eq!(trailer(0x7F).associated_context_packet_count(), None);
}
#[test]
fn boundary_values_round_trip_via_raw_bits() {
for n in [0u8, 1, 63, 127] {
let t = trailer((1 << 7) | u32::from(n));
assert_eq!(t.associated_context_packet_count(), Some(n), "n={n}");
}
}
#[test]
fn setter_round_trips_boundary_values() {
let mut t = trailer(0);
for n in [0u8, 1, 63, 127] {
t.set_associated_context_packet_count(Some(n));
assert_eq!(t.associated_context_packet_count(), Some(n), "n={n}");
}
t.set_associated_context_packet_count(None);
assert_eq!(t.associated_context_packet_count(), None);
}
#[test]
fn setter_none_clears_only_its_bits() {
let mut t = trailer(u32::MAX);
t.set_associated_context_packet_count(None);
assert_eq!(t.as_u32() & MASK, 0, "enable/count bits not cleared");
assert_eq!(
t.as_u32() & !MASK,
u32::MAX & !MASK,
"unrelated bits were disturbed"
);
}
}
}