1#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14use std::collections::HashSet;
15use std::fmt;
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20pub enum DacType {
21 Helios,
23 EtherDream,
25 Idn,
27 LasercubeWifi,
29 LasercubeUsb,
31 #[cfg(feature = "oscilloscope")]
34 Oscilloscope,
35 Avb,
37 Custom(String),
39}
40
41impl DacType {
42 #[cfg(not(feature = "oscilloscope"))]
44 pub fn all() -> &'static [DacType] {
45 &[
46 DacType::Helios,
47 DacType::EtherDream,
48 DacType::Idn,
49 DacType::LasercubeWifi,
50 DacType::LasercubeUsb,
51 DacType::Avb,
52 ]
53 }
54
55 #[cfg(feature = "oscilloscope")]
57 pub fn all() -> &'static [DacType] {
58 &[
59 DacType::Helios,
60 DacType::EtherDream,
61 DacType::Idn,
62 DacType::LasercubeWifi,
63 DacType::LasercubeUsb,
64 DacType::Avb,
65 DacType::Oscilloscope,
66 ]
67 }
68
69 pub fn display_name(&self) -> &str {
71 match self {
72 DacType::Helios => "Helios",
73 DacType::EtherDream => "Ether Dream",
74 DacType::Idn => "IDN",
75 DacType::LasercubeWifi => "LaserCube WiFi",
76 DacType::LasercubeUsb => "LaserCube USB (Laserdock)",
77 #[cfg(feature = "oscilloscope")]
78 DacType::Oscilloscope => "Oscilloscope",
79 DacType::Avb => "AVB Audio Device",
80 DacType::Custom(name) => name,
81 }
82 }
83
84 pub fn description(&self) -> &'static str {
86 match self {
87 DacType::Helios => "USB laser DAC",
88 DacType::EtherDream => "Network laser DAC",
89 DacType::Idn => "ILDA Digital Network laser DAC",
90 DacType::LasercubeWifi => "WiFi laser DAC",
91 DacType::LasercubeUsb => "USB laser DAC",
92 #[cfg(feature = "oscilloscope")]
93 DacType::Oscilloscope => "Oscilloscope XY output via stereo audio",
94 DacType::Avb => "AVB audio network output",
95 DacType::Custom(_) => "Custom DAC",
96 }
97 }
98}
99
100impl fmt::Display for DacType {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 write!(f, "{}", self.display_name())
103 }
104}
105
106#[derive(Debug, Clone, PartialEq, Eq)]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109pub struct EnabledDacTypes {
110 types: HashSet<DacType>,
111}
112
113impl EnabledDacTypes {
114 pub fn all() -> Self {
116 Self {
117 types: DacType::all().iter().cloned().collect(),
118 }
119 }
120
121 pub fn none() -> Self {
123 Self {
124 types: HashSet::new(),
125 }
126 }
127
128 pub fn is_enabled(&self, dac_type: DacType) -> bool {
130 self.types.contains(&dac_type)
131 }
132
133 pub fn enable(&mut self, dac_type: DacType) -> &mut Self {
149 self.types.insert(dac_type);
150 self
151 }
152
153 pub fn disable(&mut self, dac_type: DacType) -> &mut Self {
169 self.types.remove(&dac_type);
170 self
171 }
172
173 pub fn iter(&self) -> impl Iterator<Item = DacType> + '_ {
175 self.types.iter().cloned()
176 }
177
178 pub fn without(mut self, dac_type: DacType) -> Self {
184 self.types.remove(&dac_type);
185 self
186 }
187
188 pub fn is_empty(&self) -> bool {
190 self.types.is_empty()
191 }
192}
193
194impl Default for EnabledDacTypes {
195 fn default() -> Self {
196 Self::all()
197 }
198}
199
200impl std::iter::FromIterator<DacType> for EnabledDacTypes {
201 fn from_iter<I: IntoIterator<Item = DacType>>(iter: I) -> Self {
202 Self {
203 types: iter.into_iter().collect(),
204 }
205 }
206}
207
208impl Extend<DacType> for EnabledDacTypes {
209 fn extend<I: IntoIterator<Item = DacType>>(&mut self, iter: I) {
210 self.types.extend(iter);
211 }
212}
213
214#[derive(Debug, Clone, PartialEq, Eq, Hash)]
217#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
218pub struct DacDevice {
219 pub name: String,
220 pub dac_type: DacType,
221}
222
223impl DacDevice {
224 pub fn new(name: String, dac_type: DacType) -> Self {
225 Self { name, dac_type }
226 }
227}
228
229#[derive(Debug, Clone, PartialEq, Eq, Hash)]
231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
232pub enum DacConnectionState {
233 Connected { name: String },
235 Stopped { name: String },
237 Lost { name: String, error: Option<String> },
239}
240
241#[derive(Clone, Debug)]
243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
244pub struct DacCapabilities {
245 pub pps_min: u32,
251 pub pps_max: u32,
253 pub max_points_per_chunk: usize,
255 pub output_model: OutputModel,
257}
258
259impl Default for DacCapabilities {
260 fn default() -> Self {
261 Self {
262 pps_min: 1,
263 pps_max: 100_000,
264 max_points_per_chunk: 4096,
265 output_model: OutputModel::NetworkFifo,
266 }
267 }
268}
269
270pub fn caps_for_dac_type(dac_type: &DacType) -> DacCapabilities {
277 match dac_type {
278 #[cfg(feature = "helios")]
279 DacType::Helios => crate::protocols::helios::default_capabilities(),
280 #[cfg(not(feature = "helios"))]
281 DacType::Helios => DacCapabilities::default(),
282
283 #[cfg(feature = "ether-dream")]
284 DacType::EtherDream => crate::protocols::ether_dream::default_capabilities(),
285 #[cfg(not(feature = "ether-dream"))]
286 DacType::EtherDream => DacCapabilities::default(),
287
288 #[cfg(feature = "idn")]
289 DacType::Idn => crate::protocols::idn::default_capabilities(),
290 #[cfg(not(feature = "idn"))]
291 DacType::Idn => DacCapabilities::default(),
292
293 #[cfg(feature = "lasercube-wifi")]
294 DacType::LasercubeWifi => crate::protocols::lasercube_wifi::default_capabilities(),
295 #[cfg(not(feature = "lasercube-wifi"))]
296 DacType::LasercubeWifi => DacCapabilities::default(),
297
298 #[cfg(feature = "lasercube-usb")]
299 DacType::LasercubeUsb => crate::protocols::lasercube_usb::default_capabilities(),
300 #[cfg(not(feature = "lasercube-usb"))]
301 DacType::LasercubeUsb => DacCapabilities::default(),
302
303 #[cfg(feature = "oscilloscope")]
304 DacType::Oscilloscope => DacCapabilities::default(), #[cfg(feature = "avb")]
307 DacType::Avb => crate::protocols::avb::default_capabilities(),
308 #[cfg(not(feature = "avb"))]
309 DacType::Avb => DacCapabilities::default(),
310
311 DacType::Custom(_) => DacCapabilities::default(),
312 }
313}
314
315#[derive(Clone, Debug, PartialEq, Eq)]
317#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
318pub enum OutputModel {
319 UsbFrameSwap,
321 NetworkFifo,
323 UdpTimed,
325}
326
327#[derive(Clone, Debug)]
329#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
330pub struct DacInfo {
331 pub id: String,
333 pub name: String,
335 pub kind: DacType,
337 pub caps: DacCapabilities,
339}
340
341impl DacInfo {
342 pub fn new(
344 id: impl Into<String>,
345 name: impl Into<String>,
346 kind: DacType,
347 caps: DacCapabilities,
348 ) -> Self {
349 Self {
350 id: id.into(),
351 name: name.into(),
352 kind,
353 caps,
354 }
355 }
356}
357
358#[cfg(test)]
359mod tests {
360 use super::*;
361
362 #[test]
367 fn test_dac_type_all_returns_all_builtin_types() {
368 let all_types = DacType::all();
369 #[cfg(not(feature = "oscilloscope"))]
370 assert_eq!(all_types.len(), 6);
371 #[cfg(feature = "oscilloscope")]
372 assert_eq!(all_types.len(), 7);
373 assert!(all_types.contains(&DacType::Helios));
374 assert!(all_types.contains(&DacType::EtherDream));
375 assert!(all_types.contains(&DacType::Idn));
376 assert!(all_types.contains(&DacType::LasercubeWifi));
377 assert!(all_types.contains(&DacType::LasercubeUsb));
378 assert!(all_types.contains(&DacType::Avb));
379 #[cfg(feature = "oscilloscope")]
380 assert!(all_types.contains(&DacType::Oscilloscope));
381 }
382
383 #[test]
384 fn test_dac_type_display_uses_display_name() {
385 assert_eq!(
387 format!("{}", DacType::Helios),
388 DacType::Helios.display_name()
389 );
390 assert_eq!(
391 format!("{}", DacType::EtherDream),
392 DacType::EtherDream.display_name()
393 );
394 }
395
396 #[test]
397 fn test_dac_type_can_be_used_in_hashset() {
398 use std::collections::HashSet;
399
400 let mut set = HashSet::new();
401 set.insert(DacType::Helios);
402 set.insert(DacType::Helios); assert_eq!(set.len(), 1);
405 }
406
407 #[test]
412 fn test_enabled_dac_types_all_enables_everything() {
413 let enabled = EnabledDacTypes::all();
414 for dac_type in DacType::all() {
415 assert!(
416 enabled.is_enabled(dac_type.clone()),
417 "{:?} should be enabled",
418 dac_type
419 );
420 }
421 assert!(!enabled.is_empty());
422 }
423
424 #[test]
425 fn test_enabled_dac_types_none_disables_everything() {
426 let enabled = EnabledDacTypes::none();
427 for dac_type in DacType::all() {
428 assert!(
429 !enabled.is_enabled(dac_type.clone()),
430 "{:?} should be disabled",
431 dac_type
432 );
433 }
434 assert!(enabled.is_empty());
435 }
436
437 #[test]
438 fn test_enabled_dac_types_enable_disable_toggles_correctly() {
439 let mut enabled = EnabledDacTypes::none();
440
441 enabled.enable(DacType::Helios);
443 assert!(enabled.is_enabled(DacType::Helios));
444 assert!(!enabled.is_enabled(DacType::EtherDream));
445
446 enabled.enable(DacType::EtherDream);
448 assert!(enabled.is_enabled(DacType::Helios));
449 assert!(enabled.is_enabled(DacType::EtherDream));
450
451 enabled.disable(DacType::Helios);
453 assert!(!enabled.is_enabled(DacType::Helios));
454 assert!(enabled.is_enabled(DacType::EtherDream));
455 }
456
457 #[test]
458 fn test_enabled_dac_types_iter_only_returns_enabled() {
459 let mut enabled = EnabledDacTypes::none();
460 enabled.enable(DacType::Helios);
461 enabled.enable(DacType::Idn);
462
463 let types: Vec<DacType> = enabled.iter().collect();
464 assert_eq!(types.len(), 2);
465 assert!(types.contains(&DacType::Helios));
466 assert!(types.contains(&DacType::Idn));
467 assert!(!types.contains(&DacType::EtherDream));
468 }
469
470 #[test]
471 fn test_enabled_dac_types_default_enables_all() {
472 let enabled = EnabledDacTypes::default();
473 for dac_type in DacType::all() {
475 assert!(enabled.is_enabled(dac_type.clone()));
476 }
477 }
478
479 #[test]
480 fn test_enabled_dac_types_idempotent_operations() {
481 let mut enabled = EnabledDacTypes::none();
482
483 enabled.enable(DacType::Helios);
485 enabled.enable(DacType::Helios);
486 assert!(enabled.is_enabled(DacType::Helios));
487
488 enabled.disable(DacType::Helios);
490 enabled.disable(DacType::Helios);
491 assert!(!enabled.is_enabled(DacType::Helios));
492 }
493
494 #[test]
495 fn test_enabled_dac_types_chaining() {
496 let mut enabled = EnabledDacTypes::none();
497 enabled
498 .enable(DacType::Helios)
499 .enable(DacType::EtherDream)
500 .disable(DacType::Helios);
501
502 assert!(!enabled.is_enabled(DacType::Helios));
503 assert!(enabled.is_enabled(DacType::EtherDream));
504 }
505
506 #[test]
511 fn test_dac_connection_state_equality() {
512 let s1 = DacConnectionState::Connected {
513 name: "DAC1".to_string(),
514 };
515 let s2 = DacConnectionState::Connected {
516 name: "DAC1".to_string(),
517 };
518 let s3 = DacConnectionState::Connected {
519 name: "DAC2".to_string(),
520 };
521 let s4 = DacConnectionState::Lost {
522 name: "DAC1".to_string(),
523 error: None,
524 };
525
526 assert_eq!(s1, s2);
527 assert_ne!(s1, s3); assert_ne!(s1, s4); }
530}