use crate::flea_scope::CaptureConfigError;
pub struct StringifiedTriggerConfig {
trigger_fields: String,
}
impl StringifiedTriggerConfig {
pub fn into_string(self) -> String {
self.trigger_fields
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BitState {
High,
Low,
DontCare,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DigitalTriggerBehavior {
Auto,
While,
Start,
Stop,
}
impl DigitalTriggerBehavior {
pub fn as_str(&self) -> &'static str {
match self {
DigitalTriggerBehavior::Auto => "~",
DigitalTriggerBehavior::While => "",
DigitalTriggerBehavior::Start => "+",
DigitalTriggerBehavior::Stop => "-",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AnalogTriggerBehavior {
Auto,
Level,
Rising,
Falling,
}
impl AnalogTriggerBehavior {
pub fn as_str(&self) -> &'static str {
match self {
AnalogTriggerBehavior::Auto => "~",
AnalogTriggerBehavior::Level => "",
AnalogTriggerBehavior::Rising => "+",
AnalogTriggerBehavior::Falling => "-",
}
}
}
#[derive(Debug)]
pub struct BitTriggerBuilder {
bit_states: [BitState; 9],
}
impl BitTriggerBuilder {
pub fn new() -> Self {
Self {
bit_states: [BitState::DontCare; 9],
}
}
pub fn set_bit(mut self, bit: usize, state: BitState) -> Self {
if bit >= self.bit_states.len() {
panic!(
"Bit index {} out of range, must be between 0 and {}",
bit,
self.bit_states.len() - 1
);
}
self.bit_states[bit] = state;
self
}
pub fn bit0(self, state: BitState) -> Self {
self.set_bit(0, state)
}
pub fn bit1(self, state: BitState) -> Self {
self.set_bit(1, state)
}
pub fn bit2(self, state: BitState) -> Self {
self.set_bit(2, state)
}
pub fn bit3(self, state: BitState) -> Self {
self.set_bit(3, state)
}
pub fn bit4(self, state: BitState) -> Self {
self.set_bit(4, state)
}
pub fn bit5(self, state: BitState) -> Self {
self.set_bit(5, state)
}
pub fn bit6(self, state: BitState) -> Self {
self.set_bit(6, state)
}
pub fn bit7(self, state: BitState) -> Self {
self.set_bit(7, state)
}
pub fn bit8(self, state: BitState) -> Self {
self.set_bit(8, state)
}
pub fn is_matching(self) -> DigitalTrigger {
DigitalTrigger::new(self.bit_states, DigitalTriggerBehavior::While)
}
pub fn starts_matching(self) -> DigitalTrigger {
DigitalTrigger::new(self.bit_states, DigitalTriggerBehavior::Start)
}
pub fn stops_matching(self) -> DigitalTrigger {
DigitalTrigger::new(self.bit_states, DigitalTriggerBehavior::Stop)
}
pub fn auto(self) -> DigitalTrigger {
DigitalTrigger::new(self.bit_states, DigitalTriggerBehavior::Auto)
}
}
impl Default for BitTriggerBuilder {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct DigitalTrigger {
pub bit_states: [BitState; 9],
pub behavior: DigitalTriggerBehavior,
}
impl DigitalTrigger {
pub fn new(bit_states: [BitState; 9], behavior: DigitalTriggerBehavior) -> Self {
Self {
bit_states,
behavior,
}
}
pub fn start_capturing_when() -> BitTriggerBuilder {
BitTriggerBuilder::new()
}
pub fn into_trigger_fields(&self) -> StringifiedTriggerConfig {
let mut relevant_bits = 0u32;
for (i, state) in self.bit_states.iter().enumerate() {
if *state != BitState::DontCare {
relevant_bits |= 1 << i;
}
}
let mut active_bits = 0u32;
for (i, state) in self.bit_states.iter().enumerate() {
if *state == BitState::High {
active_bits |= 1 << i;
}
}
let trigger_behavior_flag = self.behavior.as_str();
StringifiedTriggerConfig {
trigger_fields: format!(
"{}0x{:02x} 0x{:02x}",
trigger_behavior_flag, active_bits, relevant_bits
),
}
}
}
#[derive(Debug)]
pub struct AnalogTriggerBuilder;
impl AnalogTriggerBuilder {
pub fn rising_edge(&self, volts: f64) -> AnalogTrigger {
AnalogTrigger::new(volts, AnalogTriggerBehavior::Rising)
}
pub fn falling_edge(&self, volts: f64) -> AnalogTrigger {
AnalogTrigger::new(volts, AnalogTriggerBehavior::Falling)
}
pub fn level(&self, volts: f64) -> AnalogTrigger {
AnalogTrigger::new(volts, AnalogTriggerBehavior::Level)
}
pub fn auto(&self, volts: f64) -> AnalogTrigger {
AnalogTrigger::new(volts, AnalogTriggerBehavior::Auto)
}
}
#[derive(Debug, Clone)]
pub struct AnalogTrigger {
pub level: f64,
pub behavior: AnalogTriggerBehavior,
}
impl AnalogTrigger {
pub fn new(level: f64, behavior: AnalogTriggerBehavior) -> Self {
Self { level, behavior }
}
pub fn start_capturing_when() -> AnalogTriggerBuilder {
AnalogTriggerBuilder {}
}
pub fn into_trigger_fields<F>(
&self,
voltage_to_raw: F,
) -> Result<StringifiedTriggerConfig, CaptureConfigError>
where
F: Fn(f64) -> f64,
{
let trigger_behavior_flag = self.behavior.as_str();
let raw_level = (voltage_to_raw(self.level) / 4.0 + 0.5) as i32;
if !(-1023..=1023).contains(&raw_level) {
return Err(CaptureConfigError::VoltageOutOfRange);
}
Ok(StringifiedTriggerConfig {
trigger_fields: format!("{}{} 0", trigger_behavior_flag, raw_level),
})
}
}
#[derive(Debug, Clone)]
pub enum Trigger {
Analog(AnalogTrigger),
Digital(DigitalTrigger),
}
impl From<AnalogTrigger> for Trigger {
fn from(trigger: AnalogTrigger) -> Self {
Self::Analog(trigger)
}
}
impl From<DigitalTrigger> for Trigger {
fn from(trigger: DigitalTrigger) -> Self {
Self::Digital(trigger)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analog_trigger_out_of_range() {
let trigger = AnalogTrigger::start_capturing_when().level(100.0);
let voltage_to_raw = |v: f64| v * 100.0; let result = trigger.into_trigger_fields(voltage_to_raw);
assert!(result.is_err());
}
#[test]
#[should_panic(expected = "Bit index 9 out of range")]
fn test_digital_trigger_builder_panic_on_invalid_bit() {
DigitalTrigger::start_capturing_when().set_bit(9, BitState::High); }
}