1use std::{convert::Infallible, time::Duration};
2
3use autd3_core::{
4 datagram::CombinedError,
5 firmware::{
6 FOCI_STM_BUF_SIZE_MAX, FOCI_STM_FOCI_NUM_MAX, FOCI_STM_FOCI_NUM_MIN, FOCI_STM_LOWER_X,
7 FOCI_STM_LOWER_Y, FOCI_STM_LOWER_Z, FOCI_STM_UPPER_X, FOCI_STM_UPPER_Y, FOCI_STM_UPPER_Z,
8 GAIN_STM_BUF_SIZE_MAX, MOD_BUF_SIZE_MAX, MOD_BUF_SIZE_MIN, PulseWidthError,
9 STM_BUF_SIZE_MIN, SamplingConfigError,
10 },
11 gain::GainError,
12 link::LinkError,
13 modulation::ModulationError,
14};
15
16#[derive(Debug, PartialEq, Clone)]
18#[non_exhaustive]
19pub enum AUTDDriverError {
20 InvalidSilencerCompletionTime(Duration),
22 SilencerCompletionTimeOutOfRange(Duration),
24 SamplingConfig(SamplingConfigError),
26
27 STMPeriodInvalid(usize, Duration),
29
30 ModulationSizeOutOfRange(usize),
32
33 FociSTMTotalSizeOutOfRange(usize),
35 FociSTMNumFociOutOfRange(usize),
37 FociSTMPointOutOfRange(f32, f32, f32),
39 GainSTMSizeOutOfRange(usize),
41
42 UnsupportedGPIOOutputType(String),
44
45 PulseWidth(PulseWidthError),
47
48 Modulation(ModulationError),
50 Gain(GainError),
52 Link(LinkError),
54
55 UnknownKey(String),
57 UnusedKey(String),
59
60 ConfirmResponseFailed,
62
63 ReadFirmwareVersionFailed(Vec<bool>),
65
66 InvalidDateTime,
68
69 FirmwareVersionMismatch,
71
72 UnsupportedOperation,
74 UnsupportedFirmware,
76
77 NotSupportedTag,
81 #[doc(hidden)]
82 InvalidMessageID,
83 #[doc(hidden)]
84 InvalidInfoType,
85 #[doc(hidden)]
86 InvalidGainSTMMode,
87 #[doc(hidden)]
88 UnknownFirmwareError(u8),
89 InvalidSegmentTransition,
91 InvalidTransitionMode,
93 MissTransitionTime,
95 InvalidSilencerSettings,
97}
98
99impl From<SamplingConfigError> for AUTDDriverError {
100 fn from(e: SamplingConfigError) -> Self {
101 AUTDDriverError::SamplingConfig(e)
102 }
103}
104
105impl From<PulseWidthError> for AUTDDriverError {
106 fn from(e: PulseWidthError) -> Self {
107 AUTDDriverError::PulseWidth(e)
108 }
109}
110
111impl From<ModulationError> for AUTDDriverError {
112 fn from(e: ModulationError) -> Self {
113 AUTDDriverError::Modulation(e)
114 }
115}
116
117impl From<GainError> for AUTDDriverError {
118 fn from(e: GainError) -> Self {
119 AUTDDriverError::Gain(e)
120 }
121}
122
123impl From<LinkError> for AUTDDriverError {
124 fn from(e: LinkError) -> Self {
125 AUTDDriverError::Link(e)
126 }
127}
128
129impl std::fmt::Display for AUTDDriverError {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 match self {
132 AUTDDriverError::InvalidSilencerCompletionTime(d) => write!(
133 f,
134 "Silencer completion time ({:?}) must be a multiple of the ultrasound period",
135 d
136 ),
137 AUTDDriverError::SilencerCompletionTimeOutOfRange(d) => {
138 write!(f, "Silencer completion time ({:?}) is out of range", d)
139 }
140 AUTDDriverError::SamplingConfig(e) => write!(f, "{}", e),
141 AUTDDriverError::STMPeriodInvalid(size, period) => write!(
142 f,
143 "STM sampling period ({:?}/{}) must be integer",
144 period, size
145 ),
146 AUTDDriverError::ModulationSizeOutOfRange(size) => write!(
147 f,
148 "Modulation buffer size ({}) is out of range ([{}, {}])",
149 size, MOD_BUF_SIZE_MIN, MOD_BUF_SIZE_MAX
150 ),
151 AUTDDriverError::FociSTMTotalSizeOutOfRange(size) => write!(
152 f,
153 "The number of total foci ({}) is out of range ([{}, {}])",
154 size, STM_BUF_SIZE_MIN, FOCI_STM_BUF_SIZE_MAX
155 ),
156 AUTDDriverError::FociSTMNumFociOutOfRange(size) => write!(
157 f,
158 "Number of foci ({}) is out of range ([{}, {}])",
159 size, FOCI_STM_FOCI_NUM_MIN, FOCI_STM_FOCI_NUM_MAX
160 ),
161 AUTDDriverError::FociSTMPointOutOfRange(x, y, z) => write!(
162 f,
163 "Point coordinate ({}, {}, {}) is out of range ([{}, {}], [{}, {}], [{}, {}])",
164 x,
165 y,
166 z,
167 FOCI_STM_LOWER_X,
168 FOCI_STM_UPPER_X,
169 FOCI_STM_LOWER_Y,
170 FOCI_STM_UPPER_Y,
171 FOCI_STM_LOWER_Z,
172 FOCI_STM_UPPER_Z,
173 ),
174 AUTDDriverError::GainSTMSizeOutOfRange(size) => write!(
175 f,
176 "GainSTM size ({}) is out of range ([{}, {}])",
177 size, STM_BUF_SIZE_MIN, GAIN_STM_BUF_SIZE_MAX
178 ),
179 AUTDDriverError::UnsupportedGPIOOutputType(t) => {
180 write!(f, "GPIO output type ({}) is not supported", t)
181 }
182 AUTDDriverError::PulseWidth(e) => write!(f, "{}", e),
183 AUTDDriverError::Modulation(e) => write!(f, "{}", e),
184 AUTDDriverError::Gain(e) => write!(f, "{}", e),
185 AUTDDriverError::Link(e) => write!(f, "{}", e),
186 AUTDDriverError::UnknownKey(key) => write!(f, "Unknown group key({})", key),
187 AUTDDriverError::UnusedKey(key) => write!(f, "Unused group key({})", key),
188 AUTDDriverError::ConfirmResponseFailed => {
189 write!(f, "Failed to confirm the response from the device")
190 }
191 AUTDDriverError::ReadFirmwareVersionFailed(versions) => write!(
192 f,
193 "Read firmware info failed: {}",
194 versions
195 .iter()
196 .enumerate()
197 .filter(|&(_, &b)| !b)
198 .map(|(i, _)| i.to_string())
199 .collect::<Vec<_>>()
200 .join(", ")
201 ),
202 AUTDDriverError::InvalidDateTime => write!(f, "The input data is invalid."),
203 AUTDDriverError::FirmwareVersionMismatch => write!(f, "Firmware version mismatch"),
204 AUTDDriverError::UnsupportedOperation => write!(f, "Unsupported operation"),
205 AUTDDriverError::UnsupportedFirmware => write!(f, "Unsupported firmware"),
206 AUTDDriverError::NotSupportedTag => write!(f, "Not supported tag"),
207 AUTDDriverError::InvalidMessageID => write!(f, "Invalid message ID"),
208 AUTDDriverError::InvalidInfoType => write!(f, "Invalid info type"),
209 AUTDDriverError::InvalidGainSTMMode => write!(f, "Invalid GainSTM mode"),
210 AUTDDriverError::UnknownFirmwareError(e) => write!(f, "Unknown firmware error: {}", e),
211 AUTDDriverError::InvalidSegmentTransition => write!(f, "Invalid segment transition"),
212 AUTDDriverError::InvalidTransitionMode => write!(f, "Invalid transition mode"),
213 AUTDDriverError::MissTransitionTime => write!(f, "Miss transition time"),
214 AUTDDriverError::InvalidSilencerSettings => write!(
215 f,
216 "Silencer cannot complete phase/intensity interpolation in the specified sampling period. Please lower the sampling frequency or make the completion time of Silencer longer than the sampling period of the AM/STM."
217 ),
218 }
219 }
220}
221
222impl std::error::Error for AUTDDriverError {
223 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
224 match self {
225 AUTDDriverError::SamplingConfig(e) => Some(e),
226 AUTDDriverError::PulseWidth(e) => Some(e),
227 AUTDDriverError::Modulation(e) => Some(e),
228 AUTDDriverError::Gain(e) => Some(e),
229 AUTDDriverError::Link(e) => Some(e),
230 AUTDDriverError::InvalidSilencerCompletionTime(_)
231 | AUTDDriverError::SilencerCompletionTimeOutOfRange(_)
232 | AUTDDriverError::STMPeriodInvalid(_, _)
233 | AUTDDriverError::ModulationSizeOutOfRange(_)
234 | AUTDDriverError::FociSTMTotalSizeOutOfRange(_)
235 | AUTDDriverError::FociSTMNumFociOutOfRange(_)
236 | AUTDDriverError::FociSTMPointOutOfRange(_, _, _)
237 | AUTDDriverError::GainSTMSizeOutOfRange(_)
238 | AUTDDriverError::UnsupportedGPIOOutputType(_)
239 | AUTDDriverError::UnknownKey(_)
240 | AUTDDriverError::UnusedKey(_)
241 | AUTDDriverError::ConfirmResponseFailed
242 | AUTDDriverError::ReadFirmwareVersionFailed(_)
243 | AUTDDriverError::InvalidDateTime
244 | AUTDDriverError::FirmwareVersionMismatch
245 | AUTDDriverError::UnsupportedOperation
246 | AUTDDriverError::UnsupportedFirmware
247 | AUTDDriverError::NotSupportedTag
248 | AUTDDriverError::InvalidMessageID
249 | AUTDDriverError::InvalidInfoType
250 | AUTDDriverError::InvalidGainSTMMode
251 | AUTDDriverError::UnknownFirmwareError(_)
252 | AUTDDriverError::InvalidSegmentTransition
253 | AUTDDriverError::InvalidTransitionMode
254 | AUTDDriverError::MissTransitionTime
255 | AUTDDriverError::InvalidSilencerSettings => None,
256 }
257 }
258}
259
260impl From<Infallible> for AUTDDriverError {
261 fn from(_: Infallible) -> Self {
262 unreachable!()
263 }
264}
265
266impl<E1, E2> From<CombinedError<E1, E2>> for AUTDDriverError
267where
268 E1: std::error::Error,
269 E2: std::error::Error,
270 AUTDDriverError: From<E1> + From<E2>,
271{
272 fn from(err: CombinedError<E1, E2>) -> Self {
273 match err {
274 CombinedError::E1(e) => AUTDDriverError::from(e),
275 CombinedError::E2(e) => AUTDDriverError::from(e),
276 }
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use std::error::Error;
283
284 use super::*;
285
286 #[rstest::rstest]
287 #[case(SamplingConfigError::FreqInvalid(1 * autd3_core::common::Hz), AUTDDriverError::SamplingConfig(SamplingConfigError::FreqInvalid(1 * autd3_core::common::Hz)))]
288 #[case(
289 PulseWidthError::PulseWidthOutOfRange(1),
290 AUTDDriverError::PulseWidth(PulseWidthError::PulseWidthOutOfRange(1))
291 )]
292 #[case(
293 ModulationError::new("test"),
294 AUTDDriverError::Modulation(ModulationError::new("test"))
295 )]
296 #[case(GainError::new("test"), AUTDDriverError::Gain(GainError::new("test")))]
297 #[case(LinkError::new("test"), AUTDDriverError::Link(LinkError::new("test")))]
298 fn from<E>(#[case] source: E, #[case] expected: AUTDDriverError)
299 where
300 E: std::error::Error + Clone,
301 AUTDDriverError: From<E>,
302 {
303 let err: AUTDDriverError = source.clone().into();
304 assert_eq!(expected, err);
305 }
306
307 #[rstest::rstest]
308 #[case(
309 "Silencer completion time (1ms) must be a multiple of the ultrasound period",
310 AUTDDriverError::InvalidSilencerCompletionTime(Duration::from_millis(1))
311 )]
312 #[case(
313 "Silencer completion time (1ms) is out of range",
314 AUTDDriverError::SilencerCompletionTimeOutOfRange(Duration::from_millis(1))
315 )]
316 #[case(
317 "Sampling frequency (1 Hz) must divide the ultrasound frequency",
318 AUTDDriverError::SamplingConfig(SamplingConfigError::FreqInvalid(1 * autd3_core::common::Hz))
319 )]
320 #[case(
321 "STM sampling period (1ms/10) must be integer",
322 AUTDDriverError::STMPeriodInvalid(10, Duration::from_millis(1))
323 )]
324 #[case(
325 "Modulation buffer size (0) is out of range ([2, 65536])",
326 AUTDDriverError::ModulationSizeOutOfRange(0)
327 )]
328 #[case(
329 "The number of total foci (0) is out of range ([2, 65536])",
330 AUTDDriverError::FociSTMTotalSizeOutOfRange(0)
331 )]
332 #[case(
333 "Number of foci (0) is out of range ([1, 8])",
334 AUTDDriverError::FociSTMNumFociOutOfRange(0)
335 )]
336 #[case(
337 &format!("Point coordinate (1, 2, 3) is out of range ([{}, {}], [{}, {}], [{}, {}])", FOCI_STM_LOWER_X, FOCI_STM_UPPER_X, FOCI_STM_LOWER_Y, FOCI_STM_UPPER_Y, FOCI_STM_LOWER_Z, FOCI_STM_UPPER_Z),
338 AUTDDriverError::FociSTMPointOutOfRange(1.0, 2.0, 3.0)
339 )]
340 #[case(
341 "GainSTM size (0) is out of range ([2, 1024])",
342 AUTDDriverError::GainSTMSizeOutOfRange(0)
343 )]
344 #[case(
345 "GPIO output type (test) is not supported",
346 AUTDDriverError::UnsupportedGPIOOutputType("test".to_string())
347 )]
348 #[case(
349 "Pulse width (1) is out of range [0, 512)",
350 AUTDDriverError::PulseWidth(PulseWidthError::PulseWidthOutOfRange(1))
351 )]
352 #[case("test", AUTDDriverError::Modulation(ModulationError::new("test")))]
353 #[case("test", AUTDDriverError::Gain(GainError::new("test")))]
354 #[case("test", AUTDDriverError::Link(LinkError::new("test")))]
355 #[case(
356 "Unknown group key(test_key)",
357 AUTDDriverError::UnknownKey("test_key".to_string())
358 )]
359 #[case(
360 "Unused group key(test_key)",
361 AUTDDriverError::UnusedKey("test_key".to_string())
362 )]
363 #[case(
364 "Failed to confirm the response from the device",
365 AUTDDriverError::ConfirmResponseFailed
366 )]
367 #[case(
368 "Read firmware info failed: 0, 2",
369 AUTDDriverError::ReadFirmwareVersionFailed(vec![false, true, false])
370 )]
371 #[case("The input data is invalid.", AUTDDriverError::InvalidDateTime)]
372 #[case("Firmware version mismatch", AUTDDriverError::FirmwareVersionMismatch)]
373 #[case("Unsupported operation", AUTDDriverError::UnsupportedOperation)]
374 #[case("Unsupported firmware", AUTDDriverError::UnsupportedFirmware)]
375 #[case("Not supported tag", AUTDDriverError::NotSupportedTag)]
376 #[case("Invalid message ID", AUTDDriverError::InvalidMessageID)]
377 #[case("Invalid info type", AUTDDriverError::InvalidInfoType)]
378 #[case("Invalid GainSTM mode", AUTDDriverError::InvalidGainSTMMode)]
379 #[case(
380 "Unknown firmware error: 42",
381 AUTDDriverError::UnknownFirmwareError(42)
382 )]
383 #[case(
384 "Invalid segment transition",
385 AUTDDriverError::InvalidSegmentTransition
386 )]
387 #[case("Invalid transition mode", AUTDDriverError::InvalidTransitionMode)]
388 #[case("Miss transition time", AUTDDriverError::MissTransitionTime)]
389 #[case(
390 "Silencer cannot complete phase/intensity interpolation in the specified sampling period. Please lower the sampling frequency or make the completion time of Silencer longer than the sampling period of the AM/STM.",
391 AUTDDriverError::InvalidSilencerSettings
392 )]
393 fn display(#[case] msg: &str, #[case] err: AUTDDriverError) {
394 assert_eq!(msg, format!("{}", err))
395 }
396
397 #[rstest::rstest]
398 #[case(
399 false,
400 AUTDDriverError::InvalidSilencerCompletionTime(Duration::from_millis(1))
401 )]
402 #[case(
403 false,
404 AUTDDriverError::SilencerCompletionTimeOutOfRange(Duration::from_millis(1))
405 )]
406 #[case(true, AUTDDriverError::SamplingConfig(SamplingConfigError::FreqInvalid(1 * autd3_core::common::Hz)))]
407 #[case(false, AUTDDriverError::STMPeriodInvalid(10, Duration::from_millis(1)))]
408 #[case(false, AUTDDriverError::ModulationSizeOutOfRange(0))]
409 #[case(false, AUTDDriverError::FociSTMTotalSizeOutOfRange(0))]
410 #[case(false, AUTDDriverError::FociSTMNumFociOutOfRange(0))]
411 #[case(false, AUTDDriverError::FociSTMPointOutOfRange(1.0, 2.0, 3.0))]
412 #[case(false, AUTDDriverError::GainSTMSizeOutOfRange(0))]
413 #[case(false, AUTDDriverError::UnsupportedGPIOOutputType("test".to_string()))]
414 #[case(
415 true,
416 AUTDDriverError::PulseWidth(PulseWidthError::PulseWidthOutOfRange(1))
417 )]
418 #[case(true, AUTDDriverError::Modulation(ModulationError::new("test")))]
419 #[case(true, AUTDDriverError::Gain(GainError::new("test")))]
420 #[case(true, AUTDDriverError::Link(LinkError::new("test")))]
421 #[case(false, AUTDDriverError::UnknownKey("test_key".to_string()))]
422 #[case(false, AUTDDriverError::UnusedKey("test_key".to_string()))]
423 #[case(false, AUTDDriverError::ConfirmResponseFailed)]
424 #[case(false, AUTDDriverError::ReadFirmwareVersionFailed(vec![false, true, false]))]
425 #[case(false, AUTDDriverError::InvalidDateTime)]
426 #[case(false, AUTDDriverError::FirmwareVersionMismatch)]
427 #[case(false, AUTDDriverError::UnsupportedOperation)]
428 #[case(false, AUTDDriverError::UnsupportedFirmware)]
429 #[case(false, AUTDDriverError::NotSupportedTag)]
430 #[case(false, AUTDDriverError::InvalidMessageID)]
431 #[case(false, AUTDDriverError::InvalidInfoType)]
432 #[case(false, AUTDDriverError::InvalidGainSTMMode)]
433 #[case(false, AUTDDriverError::UnknownFirmwareError(42))]
434 #[case(false, AUTDDriverError::InvalidSegmentTransition)]
435 #[case(false, AUTDDriverError::InvalidTransitionMode)]
436 #[case(false, AUTDDriverError::MissTransitionTime)]
437 #[case(false, AUTDDriverError::InvalidSilencerSettings)]
438 fn source(#[case] has_source: bool, #[case] err: AUTDDriverError) {
439 assert_eq!(has_source, err.source().is_some());
440 }
441
442 #[test]
443 fn from_combined_error() {
444 let mod_err = ModulationError::new("modulation error");
445 let gain_err = GainError::new("gain error");
446 let combined_mod: CombinedError<ModulationError, GainError> =
447 CombinedError::E1(mod_err.clone());
448 let combined_gain: CombinedError<ModulationError, GainError> =
449 CombinedError::E2(gain_err.clone());
450
451 assert_eq!(AUTDDriverError::Modulation(mod_err), combined_mod.into());
452 assert_eq!(AUTDDriverError::Gain(gain_err), combined_gain.into());
453 }
454}