use derive_new::new;
use std::{convert::Infallible, num::NonZeroU16};
use crate::{
firmware::{
fpga::{SilencerTarget, SILENCER_STEPS_INTENSITY_DEFAULT, SILENCER_STEPS_PHASE_DEFAULT},
operation::{
NullOp, OperationGenerator, SilencerFixedCompletionStepsOp, SilencerFixedUpdateRateOp,
},
},
geometry::{Device, Geometry},
};
use super::Datagram;
pub trait SilencerConfig: std::fmt::Debug + Clone + Copy {}
impl SilencerConfig for () {}
#[cfg(not(feature = "dynamic_freq"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FixedCompletionTime {
pub intensity: std::time::Duration,
pub phase: std::time::Duration,
pub strict_mode: bool,
}
#[cfg(not(feature = "dynamic_freq"))]
impl SilencerConfig for FixedCompletionTime {}
#[cfg(not(feature = "dynamic_freq"))]
impl Default for FixedCompletionTime {
fn default() -> Self {
FixedCompletionTime {
intensity: SILENCER_STEPS_INTENSITY_DEFAULT as u32
* autd3_core::defined::ultrasound_period(),
phase: SILENCER_STEPS_PHASE_DEFAULT as u32 * autd3_core::defined::ultrasound_period(),
strict_mode: true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct FixedCompletionSteps {
pub intensity: NonZeroU16,
pub phase: NonZeroU16,
pub strict_mode: bool,
}
impl SilencerConfig for FixedCompletionSteps {}
impl Default for FixedCompletionSteps {
fn default() -> Self {
FixedCompletionSteps {
intensity: NonZeroU16::new(SILENCER_STEPS_INTENSITY_DEFAULT).unwrap(),
phase: NonZeroU16::new(SILENCER_STEPS_PHASE_DEFAULT).unwrap(),
strict_mode: true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct FixedUpdateRate {
pub intensity: NonZeroU16,
pub phase: NonZeroU16,
}
impl SilencerConfig for FixedUpdateRate {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, new)]
pub struct Silencer<T: SilencerConfig> {
pub config: T,
pub target: SilencerTarget,
}
impl Silencer<()> {
pub const fn disable() -> Silencer<FixedCompletionSteps> {
Silencer {
config: FixedCompletionSteps {
intensity: NonZeroU16::MIN,
phase: NonZeroU16::MIN,
strict_mode: true,
},
target: SilencerTarget::Intensity,
}
}
}
impl Default for Silencer<FixedCompletionSteps> {
fn default() -> Self {
Silencer {
config: Default::default(),
target: Default::default(),
}
}
}
pub struct SilencerOpGenerator<T: SilencerConfig> {
config: T,
target: SilencerTarget,
}
impl OperationGenerator for SilencerOpGenerator<FixedUpdateRate> {
type O1 = SilencerFixedUpdateRateOp;
type O2 = NullOp;
fn generate(&mut self, _: &Device) -> (Self::O1, Self::O2) {
(
Self::O1::new(self.config.intensity, self.config.phase, self.target),
Self::O2 {},
)
}
}
#[cfg(not(feature = "dynamic_freq"))]
impl OperationGenerator for SilencerOpGenerator<FixedCompletionTime> {
type O1 = crate::firmware::operation::SilencerFixedCompletionTimeOp;
type O2 = NullOp;
fn generate(&mut self, _: &Device) -> (Self::O1, Self::O2) {
(
Self::O1::new(
self.config.intensity,
self.config.phase,
self.config.strict_mode,
self.target,
),
Self::O2 {},
)
}
}
impl OperationGenerator for SilencerOpGenerator<FixedCompletionSteps> {
type O1 = SilencerFixedCompletionStepsOp;
type O2 = NullOp;
fn generate(&mut self, _: &Device) -> (Self::O1, Self::O2) {
(
Self::O1::new(
self.config.intensity,
self.config.phase,
self.config.strict_mode,
self.target,
),
Self::O2 {},
)
}
}
impl<T: SilencerConfig> Datagram for Silencer<T>
where
SilencerOpGenerator<T>: OperationGenerator,
{
type G = SilencerOpGenerator<T>;
type Error = Infallible;
fn operation_generator(self, _: &Geometry, _: bool) -> Result<Self::G, Self::Error> {
Ok(Self::G {
config: self.config,
target: self.target,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn disable() {
let s = Silencer::disable();
assert_eq!(1, s.config.intensity.get());
assert_eq!(1, s.config.phase.get());
assert!(s.config.strict_mode);
assert_eq!(SilencerTarget::Intensity, s.target);
}
#[test]
fn fixed_completion_steps_default() {
let s: Silencer<FixedCompletionSteps> = Silencer::default();
assert_eq!(10, s.config.intensity.get());
assert_eq!(40, s.config.phase.get());
assert!(s.config.strict_mode);
assert_eq!(SilencerTarget::Intensity, s.target);
}
#[test]
#[cfg(not(feature = "dynamic_freq"))]
fn fixed_completion_time_default() {
let s: Silencer<FixedCompletionTime> = Silencer {
config: Default::default(),
target: Default::default(),
};
assert_eq!(std::time::Duration::from_micros(250), s.config.intensity);
assert_eq!(std::time::Duration::from_micros(1000), s.config.phase);
assert!(s.config.strict_mode);
assert_eq!(SilencerTarget::Intensity, s.target);
}
}