1use thiserror::Error;
2
3use crate::mirror::{BankLoop, SilencerAxis};
4use crate::value::{PulseWidthError, SamplingConfigError, TransitionMode};
5
6#[derive(Debug, Error)]
7pub enum Error {
8 #[error("device {device} firmware error {code:#04x}: {}", crate::protocol::describe_device_error(*code))]
9 DeviceError { device: usize, code: u8 },
10
11 #[error(
12 "device {device}: strict silencer {axis:?} completion {completion_steps} steps exceeds sampling divider {sampling_div}"
13 )]
14 SilencerConstraint {
15 device: usize,
16 axis: SilencerAxis,
17 completion_steps: u16,
18 sampling_div: u16,
19 },
20
21 #[error(
22 "device {device}: transition mode {transition_mode:?} is invalid for a {bank_loop:?} loop bank"
23 )]
24 TransitionConstraint {
25 device: usize,
26 transition_mode: TransitionMode,
27 bank_loop: BankLoop,
28 },
29
30 #[error("ack timeout after {cycles} cycles")]
31 Timeout { cycles: u32 },
32
33 #[error("link error: {0}")]
34 Link(String),
35
36 #[error("invalid payload: {0}")]
37 InvalidPayload(PayloadError),
38
39 #[error("client RT worker is no longer alive")]
40 RtClosed,
41}
42
43#[derive(Clone, Copy, Debug, PartialEq, Error)]
44pub enum PayloadError {
45 #[error("max_inflight must be <= {max}")]
46 MaxInFlightTooLarge { max: usize },
47
48 #[error("link must expose 1..={max} devices, got {got}")]
49 DeviceCountOutOfRange { got: usize, max: usize },
50
51 #[error("geometry has {geometry} device(s) but link exposes {link}")]
52 GeometryDeviceMismatch { geometry: usize, link: usize },
53
54 #[error("expected {expected} datagram(s) (one per device), got {got}")]
55 DatagramCountMismatch { expected: usize, got: usize },
56
57 #[error("focus coordinate {axis} = {value} out of range {min}..={max}")]
58 FocusOutOfRange {
59 axis: &'static str,
60 value: i32,
61 min: i32,
62 max: i32,
63 },
64
65 #[error("modulation size {size} out of range 1..={max}")]
66 ModulationSizeOutOfRange { size: usize, max: usize },
67
68 #[error("modulation data must not be empty")]
69 ModulationDataEmpty,
70
71 #[error("modulation offset {offset} must be even (word-write-only RAM)")]
72 ModulationOffsetNotEven { offset: usize },
73
74 #[error("modulation write [{offset}, {end}) exceeds buffer capacity {capacity}")]
75 ModulationWriteExceedsCapacity {
76 offset: usize,
77 end: usize,
78 capacity: usize,
79 },
80
81 #[error("modulation sample count exceeds usize")]
82 SampleCountOverflow,
83
84 #[error("sine modulation value is out of range [0, 255]")]
85 SineValueOutOfRange,
86
87 #[error("square duty {duty} must be in range 0..=1")]
88 DutyOutOfRange { duty: f32 },
89
90 #[error("fourier components must not be empty")]
91 FourierComponentsEmpty,
92
93 #[error("all fourier components must have the same sampling config")]
94 FourierSamplingConfigMismatch,
95
96 #[error("fourier modulation value is out of range [0, 255]")]
97 FourierValueOutOfRange,
98
99 #[error("foci must not be empty")]
100 FociEmpty,
101
102 #[error("foci write [{offset}, {end}) exceeds capacity {capacity}")]
103 FociWriteExceedsCapacity {
104 offset: usize,
105 end: usize,
106 capacity: usize,
107 },
108
109 #[error("xor_hash data too large: max {max} bytes, got {len}")]
110 XorHashDataTooLarge { len: usize, max: usize },
111
112 #[error("silencer completion time {0:?} must be a multiple of the ultrasound period")]
113 SilencerCompletionTimeNotMultiple(core::time::Duration),
114
115 #[error("silencer completion time {0:?} is out of range (1..=65535 ultrasound periods)")]
116 SilencerCompletionTimeOutOfRange(core::time::Duration),
117
118 #[error("pattern size must be >= 1")]
119 PatternSizeZero,
120
121 #[error("num_foci {num_foci} out of range 1..={max}")]
122 NumFociOutOfRange { num_foci: u8, max: u8 },
123
124 #[error("STM size {size} x num_foci {num_foci} exceeds capacity {capacity}")]
125 StmFociExceedCapacity {
126 size: usize,
127 num_foci: u8,
128 capacity: usize,
129 },
130
131 #[error("sound_speed must be >= 1")]
132 SoundSpeedZero,
133
134 #[error("STM size {size} out of range 1..={max}")]
135 StmSizeOutOfRange { size: usize, max: usize },
136
137 #[error("emissions has {len} entr(ies) but device {device} was requested")]
138 EmissionsDeviceOutOfRange { device: usize, len: usize },
139
140 #[error("device {device} has {got} transducer entr(ies) but {expected} are required")]
141 TransducerCountMismatch {
142 device: usize,
143 got: usize,
144 expected: usize,
145 },
146
147 #[error("pattern STM index {index} out of range 0..{max}")]
148 PatternIndexOutOfRange { index: usize, max: usize },
149
150 #[error("device {device} has no group key")]
151 GroupKeyMissing { device: usize },
152
153 #[error("device {device} maps to an unknown key")]
154 GroupKeyUnknown { device: usize },
155
156 #[error("frequency {hz} Hz is equal to or greater than the Nyquist frequency ({nyquist} Hz)")]
157 FrequencyAboveNyquist { hz: f64, nyquist: f32 },
158
159 #[error("modulation frequency must not be zero")]
160 FrequencyZero,
161
162 #[error("frequency {hz} Hz must be a valid positive value")]
163 FrequencyNotPositive { hz: f32 },
164
165 #[error("frequency {hz} Hz cannot be output with the current sampling config")]
166 FrequencyNotRepresentable { hz: f32 },
167
168 #[error("modulation frequency must be a valid value")]
169 FrequencyNaN,
170
171 #[error(transparent)]
172 SamplingConfig(#[from] SamplingConfigError),
173
174 #[error(transparent)]
175 PulseWidth(#[from] PulseWidthError),
176}