tango/error.rs
1//! The standard Tango error type.
2
3use std::fmt::{self, Debug, Display};
4use std::panic::Location;
5use std::borrow::Cow;
6use std::error;
7
8
9/// Type alias for a result with the standard [`Tango`] error type.
10pub type Result<T> = std::result::Result<T, Error>;
11
12/// A common error type for all Tango operations, which support metadata and easy to build
13/// chaining of errors.
14#[repr(transparent)]
15pub struct Error {
16 inner: Box<ErrorInner>,
17}
18
19#[derive(Debug)]
20struct ErrorInner {
21 /// The standardized reason of the error.
22 reason: Cow<'static, str>,
23 /// The human readable description of the error.
24 description: Cow<'static, str>,
25 /// The origin, in file/code, of the error.
26 origin: Cow<'static, str>,
27 /// The severity of the error.
28 severity: ErrorSeverity,
29 /// If thre reason was corresponding to a non-raw kind, then it's cached here.
30 kind: Option<ErrorKind<'static>>,
31 /// The source of the error.
32 source: Option<ErrorSource>,
33}
34
35#[derive(Debug)]
36enum ErrorSource {
37 /// The parent of the error is another Tango error.
38 Parent(Error),
39 /// A generic tango error.
40 Generic(Box<dyn error::Error + Send + Sync>),
41}
42
43impl From<std::convert::Infallible> for Error {
44 fn from(never: std::convert::Infallible) -> Self {
45 match never {}
46 }
47}
48
49impl Error {
50
51 /// Create a new error of the given kind, this will grab the origin of the error from
52 /// the caller's location. A default description is written depending on it by default,
53 /// you can append or replace this description later.
54 #[track_caller]
55 pub fn new(kind: ErrorKind<'_>) -> Self {
56 let mut ret = Self {
57 inner: Box::new(ErrorInner {
58 reason: Cow::Borrowed(""),
59 description: Cow::Borrowed(""),
60 origin: Cow::Borrowed(""),
61 severity: ErrorSeverity::Error,
62 kind: None,
63 source: None,
64 })
65 };
66 ret.set_kind(kind);
67 ret.set_origin_from_caller();
68 ret
69 }
70
71 pub(crate) fn not_implemented() -> Self {
72 Self::new(ErrorKind::NotImplemented)
73 }
74
75 /// Return the standardized textual reason.
76 pub fn reason(&self) -> &str {
77 &self.inner.reason
78 }
79
80 /// Get the kind of error, returning the raw reason if not categorized.
81 pub fn kind(&self) -> ErrorKind<'_> {
82 if let Some(kind) = self.inner.kind {
83 kind
84 } else {
85 ErrorKind::Reason(&self.inner.reason)
86 }
87 }
88
89 /// Change the kind of this error, this will also ensures that the associated reason
90 /// is correponding to the new error kind. If the description is empty at this point,
91 /// the description os overriden with a default description.
92 pub fn set_kind(&mut self, kind: ErrorKind<'_>) {
93
94 // Only a fallback: an error that already says something specific keeps saying it.
95 if self.inner.description.is_empty() {
96 self.inner.description = Cow::Borrowed(kind.description());
97 }
98
99 let (reason, kind) = match kind.into_static() {
100 Ok(kind) => (Cow::Borrowed(kind.reason()), Some(kind)),
101 Err(kind) => (Cow::Owned(kind.reason().to_string()), None),
102 };
103
104 self.inner.kind = kind;
105 self.inner.reason = reason;
106
107 }
108
109 /// Change the kind of this error, and return itself.
110 pub fn with_kind(mut self, kind: ErrorKind<'_>) -> Self {
111 self.set_kind(kind);
112 self
113 }
114
115 /// Return the description of the error.
116 pub fn description(&self) -> &str {
117 &self.inner.description
118 }
119
120 /// Append the given additional description to the error's description, if the error
121 /// is currently empty, then this replaces the previous description. If a description
122 /// already exists, it appends the description on a new line.
123 pub fn append_description(&mut self, additional: impl Display) {
124 if self.inner.description.is_empty() {
125 self.inner.description = Cow::Owned(additional.to_string());
126 } else {
127 self.inner.description = Cow::Owned(format!("{}\n{additional}", self.inner.description));
128 }
129 }
130
131 /// Overwrite any existing description with the given one.
132 pub fn set_description(&mut self, description: impl Into<Cow<'static, str>>) {
133 self.inner.description = description.into();
134 }
135
136 /// Same as [`Self::append_description`], and return itself.
137 pub fn with_append_description(mut self, additional: impl Display) -> Self {
138 self.append_description(additional);
139 self
140 }
141
142 /// Overwrite any existing description with the given one, and return itself.
143 pub fn with_description(mut self, description: impl Into<Cow<'static, str>>) -> Self {
144 self.set_description(description);
145 self
146 }
147
148 /// Return the severity of this error.
149 pub fn severity(&self) -> ErrorSeverity {
150 self.inner.severity
151 }
152
153 /// Set the severity of the error.
154 pub fn set_severity(&mut self, severity: ErrorSeverity) {
155 self.inner.severity = severity;
156 }
157
158 /// Set the severity of the error, and return itself.
159 pub fn with_severity(mut self, severity: ErrorSeverity) -> Self {
160 self.set_severity(severity);
161 self
162 }
163
164 /// Return the origin of this error, set by default to the caller's code location.
165 pub fn origin(&self) -> &str {
166 &self.inner.origin
167 }
168
169 /// Append the given additional origin to the existing origin, in order to add
170 /// details, a space is added before insertion. If the origin has been replaced
171 /// and is empty, then no space is added.
172 pub fn append_origin(&mut self, additional: impl Display) {
173 if self.inner.origin.is_empty() {
174 self.inner.origin = Cow::Owned(additional.to_string());
175 } else {
176 self.inner.origin = Cow::Owned(format!("{} {additional}", self.inner.origin));
177 }
178 }
179
180 /// Overwrite any existing origin with the given one.
181 pub fn set_origin(&mut self, origin: impl Into<Cow<'static, str>>) {
182 self.inner.origin = origin.into();
183 }
184
185 /// Same as [`Self::append_origin`], and return itself.
186 pub fn with_append_origin(mut self, additional: impl Display) -> Self {
187 self.append_origin(additional);
188 self
189 }
190
191 /// Overwrite any existing origin with the given one, and return itself.
192 pub fn with_origin(mut self, origin: impl Into<Cow<'static, str>>) -> Self {
193 self.set_origin(origin);
194 self
195 }
196
197 /// Overwrite the existing origin with the current location of the caller.
198 #[track_caller]
199 pub fn set_origin_from_caller(&mut self) {
200 let location = Location::caller();
201 self.set_origin(format!("{location}"));
202 }
203
204 /// Overwrite the existing origin with the current location of the caller, and return
205 /// itself.
206 #[track_caller]
207 pub fn with_origin_from_caller(mut self) -> Self {
208 self.set_origin_from_caller();
209 self
210 }
211
212 /// If the source of this error is a parent Tango error, returns a shared ref to it.
213 /// To get a more generic source for this error, use the standard
214 /// [`error::Error::source`] method.
215 pub fn parent(&self) -> Option<&Error> {
216 if let Some(ErrorSource::Parent(err)) = &self.inner.source {
217 Some(err)
218 } else {
219 None
220 }
221 }
222
223 /// Set the parent source of this error.
224 pub fn set_parent(&mut self, parent: Error) {
225 self.inner.source = Some(ErrorSource::Parent(parent));
226 }
227
228 /// Set the parent source of this error and return itself.
229 pub fn with_parent(mut self, parent: Error) -> Self {
230 self.set_parent(parent);
231 self
232 }
233
234 /// Set the generic source of this error.
235 pub fn set_source(&mut self, source: Box<dyn error::Error + Send + Sync>) {
236 self.inner.source = Some(ErrorSource::Generic(source));
237 }
238
239 /// Set the generic source of this error and return itself.
240 pub fn with_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self {
241 self.set_source(source);
242 self
243 }
244
245 /// A copy of this error and of its whole chain of parents, for an error that is handed
246 /// to several receivers. A generic source cannot be copied, so the copy has its text
247 /// alone as its source.
248 pub(crate) fn duplicate(&self) -> Self {
249
250 let source = match &self.inner.source {
251 Some(ErrorSource::Parent(err)) => Some(ErrorSource::Parent(err.duplicate())),
252 Some(ErrorSource::Generic(err)) => Some(ErrorSource::Generic(Box::new(std::io::Error::other(err.to_string())))),
253 None => None,
254 };
255
256 Self {
257 inner: Box::new(ErrorInner {
258 reason: self.inner.reason.clone(),
259 description: self.inner.description.clone(),
260 origin: self.inner.origin.clone(),
261 severity: self.inner.severity,
262 kind: self.inner.kind,
263 source,
264 }),
265 }
266
267 }
268
269}
270
271impl error::Error for Error {
272
273 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
274 match &self.inner.source {
275 Some(ErrorSource::Parent(err)) => Some(err),
276 Some(ErrorSource::Generic(err)) => Some(&**err),
277 None => None,
278 }
279 }
280
281}
282
283/// The whole chain of this error and its parents, on a single line, each error giving its
284/// reason and its description, escaped so that a description of several lines stays on
285/// that line: this is what a log line carries, see `{:#}` for what a person reads.
286///
287/// The alternate form gives an error per block, the origin of each of them along with
288/// it: a code location is noise in a log line, and the first thing wanted when debugging.
289impl Display for Error {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291
292 let separator = if f.alternate() { "\ncaused by " } else { " <- " };
293
294 let mut error = self;
295 loop {
296
297 let severity = match error.severity() {
298 ErrorSeverity::Warning => "WARNING",
299 ErrorSeverity::Error => "ERROR",
300 ErrorSeverity::Panic => "PANIC",
301 };
302
303 write!(f, "{severity}/{}", error.reason())?;
304
305 if !f.alternate() {
306 if !error.description().is_empty() {
307 write!(f, "({:?})", error.description())?;
308 }
309 } else {
310 if !error.origin().is_empty() {
311 write!(f, " @ {}", error.origin())?;
312 }
313 for line in error.description().lines() {
314 write!(f, "\n {line}")?;
315 }
316 }
317
318 match &error.inner.source {
319 Some(ErrorSource::Parent(parent)) => {
320 f.write_str(separator)?;
321 error = parent;
322 }
323 Some(ErrorSource::Generic(source)) => {
324 // What is not a Tango error is told apart from one, being the cause of
325 // the chain rather than a level of it.
326 let mut source: &dyn error::Error = &**source;
327 loop {
328 write!(f, "{separator}{source}")?;
329 match source.source() {
330 Some(next) => source = next,
331 None => break,
332 }
333 }
334 break Ok(());
335 }
336 None => {
337 break Ok(());
338 }
339 }
340
341 }
342
343 }
344}
345
346/// Written like [`Display`], within `Error(...)`: the derived struct dump is what a `main`
347/// returning a [`Result`] would otherwise print, and it is unreadable. The alternate form
348/// gives the alternate one of [`Display`], one error per block, with their origins.
349impl Debug for Error {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351 if !f.alternate() {
352 write!(f, "Error({self})")
353 } else {
354 f.write_str("Error(\n")?;
355 for line in format!("{self:#}").lines() {
356 writeln!(f, " {line}")?;
357 }
358 f.write_str(")")
359 }
360 }
361}
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq)]
364pub enum ErrorKind<'r> {
365 /// For backends that could not handle a specific operation, this usually means to
366 /// fallback to the next backend to retry.
367 NotHandled,
368 /// For features that are not implemented.
369 NotImplemented,
370 // Database
371 TangoHostNotSet,
372 DatabaseNotConnected,
373 DatabaseNeeded,
374 AliasNotFound,
375 DevNotFound,
376 // Device
377 DevNotConnected,
378 // Server
379 ClassAlreadyDefined,
380 DevAlreadyDefined,
381 DevInitFailed,
382 CommandAlreadyDefined,
383 AttrAlreadyDefined,
384 // Class
385 ClassNotFound,
386 // Command
387 CommandNameInvalid,
388 CommandNotFound,
389 CommandArgumentKindInvalid,
390 // Attr
391 AttrNameInvalid,
392 AttrNotFound,
393 AttrNotWritable,
394 AttrKindInvalid,
395 // Event
396 EventNotConnected,
397 // Misc
398 InvalidIndex,
399 InvalidData,
400 InvalidProp,
401 TimedOut,
402 Corba,
403 Internal,
404 Reason(&'r str),
405}
406
407impl<'r> ErrorKind<'r> {
408
409 fn into_static(self) -> std::result::Result<ErrorKind<'static>, Self> {
410 Ok(match self {
411 ErrorKind::NotHandled => ErrorKind::NotHandled,
412 ErrorKind::NotImplemented => ErrorKind::NotImplemented,
413 ErrorKind::TangoHostNotSet => ErrorKind::TangoHostNotSet,
414 ErrorKind::DatabaseNotConnected => ErrorKind::DatabaseNotConnected,
415 ErrorKind::DatabaseNeeded => ErrorKind::DatabaseNeeded,
416 ErrorKind::AliasNotFound => ErrorKind::AliasNotFound,
417 ErrorKind::DevNotFound => ErrorKind::DevNotFound,
418 ErrorKind::DevNotConnected => ErrorKind::DevNotConnected,
419 ErrorKind::ClassAlreadyDefined => ErrorKind::ClassAlreadyDefined,
420 ErrorKind::DevAlreadyDefined => ErrorKind::DevAlreadyDefined,
421 ErrorKind::DevInitFailed => ErrorKind::DevInitFailed,
422 ErrorKind::CommandAlreadyDefined => ErrorKind::CommandAlreadyDefined,
423 ErrorKind::AttrAlreadyDefined => ErrorKind::AttrAlreadyDefined,
424 ErrorKind::ClassNotFound => ErrorKind::ClassNotFound,
425 ErrorKind::CommandNameInvalid => ErrorKind::CommandNameInvalid,
426 ErrorKind::CommandNotFound => ErrorKind::CommandNotFound,
427 ErrorKind::CommandArgumentKindInvalid => ErrorKind::CommandArgumentKindInvalid,
428 ErrorKind::AttrNameInvalid => ErrorKind::AttrNameInvalid,
429 ErrorKind::AttrNotFound => ErrorKind::AttrNotFound,
430 ErrorKind::AttrNotWritable => ErrorKind::AttrNotWritable,
431 ErrorKind::AttrKindInvalid => ErrorKind::AttrKindInvalid,
432 ErrorKind::EventNotConnected => ErrorKind::EventNotConnected,
433 ErrorKind::InvalidIndex => ErrorKind::InvalidIndex,
434 ErrorKind::InvalidData => ErrorKind::InvalidData,
435 ErrorKind::InvalidProp => ErrorKind::InvalidProp,
436 ErrorKind::TimedOut => ErrorKind::TimedOut,
437 ErrorKind::Corba => ErrorKind::Corba,
438 ErrorKind::Internal => ErrorKind::Internal,
439 ErrorKind::Reason(_) => return Err(self),
440 })
441 }
442
443 /// Return the textual and standard reason for this
444 pub fn reason(&self) -> &'r str {
445 match self {
446 ErrorKind::NotHandled => reason::API_InternalError,
447 ErrorKind::NotImplemented => reason::API_InternalError,
448 ErrorKind::TangoHostNotSet => reason::API_TangoHostNotSet,
449 ErrorKind::DatabaseNotConnected => reason::API_CantConnectToDatabase,
450 ErrorKind::DatabaseNeeded => reason::API_InternalError,
451 ErrorKind::AliasNotFound => reason::API_AliasNotDefined,
452 ErrorKind::DevNotFound => reason::API_DeviceNotExported,
453 ErrorKind::DevNotConnected => reason::API_DeviceNotDefined,
454 ErrorKind::ClassAlreadyDefined => reason::API_InternalError,
455 ErrorKind::DevAlreadyDefined => reason::API_DeviceAlreadyDefined,
456 ErrorKind::DevInitFailed => reason::API_InitThrowsException,
457 ErrorKind::CommandAlreadyDefined => reason::API_InternalError,
458 ErrorKind::AttrAlreadyDefined => reason::API_InternalError,
459 ErrorKind::ClassNotFound => reason::API_ClassNotFound,
460 ErrorKind::CommandNameInvalid => reason::API_InternalError,
461 ErrorKind::CommandNotFound => reason::API_CommandNotFound,
462 ErrorKind::CommandArgumentKindInvalid => reason::API_IncompatibleCmdArgumentType,
463 ErrorKind::AttrNameInvalid => reason::API_InternalError,
464 ErrorKind::AttrNotFound => reason::API_AttrNotFound,
465 ErrorKind::AttrNotWritable => reason::API_AttrNotWritable,
466 ErrorKind::AttrKindInvalid => reason::API_IncompatibleAttrDataType,
467 ErrorKind::EventNotConnected => reason::API_EventNotFound,
468 ErrorKind::InvalidIndex => reason::API_InternalError,
469 ErrorKind::InvalidData => reason::API_InternalError,
470 ErrorKind::InvalidProp => reason::API_InternalError,
471 ErrorKind::TimedOut => reason::API_DeviceTimedOut,
472 ErrorKind::Corba => reason::API_CorbaException,
473 ErrorKind::Internal => reason::API_InternalError,
474 ErrorKind::Reason(reason) => reason,
475 }
476 }
477
478 /// Return a statically defined description of the error.
479 pub fn description(&self) -> &'static str {
480 match self {
481 ErrorKind::NotHandled => "The backend is not able to handle such request",
482 ErrorKind::NotImplemented => "This functionnality is not yet implemented",
483 ErrorKind::TangoHostNotSet => "The TANGO_HOST variable is not set, or its syntax is incorrect, it should hold a comma separated list of 'host:port'",
484 ErrorKind::DatabaseNotConnected => "Not able to connect to the Tango database",
485 ErrorKind::DatabaseNeeded => "This operation is only allowed if the device is connected through a database",
486 ErrorKind::AliasNotFound => "Alias was not found in the database",
487 ErrorKind::DevNotFound => "Device was not found in the database",
488 ErrorKind::DevNotConnected => "Device was not found on its device server",
489 ErrorKind::ClassAlreadyDefined => "Class is already defined on the server",
490 ErrorKind::DevAlreadyDefined => "Device is already defined on the server",
491 ErrorKind::DevInitFailed => "Device initialization failed",
492 ErrorKind::CommandAlreadyDefined => "Command is already defined in the device",
493 ErrorKind::AttrAlreadyDefined => "Attribute is already defined in the device",
494 ErrorKind::ClassNotFound => "Class was not found on the server",
495 ErrorKind::CommandNameInvalid => "Command name may contain invalid characters or is too long",
496 ErrorKind::CommandNotFound => "The command was not found on the device",
497 ErrorKind::CommandArgumentKindInvalid => "Invalid command argument data kind",
498 ErrorKind::AttrNameInvalid => "Attribute name may contain invalid characters or is too long",
499 ErrorKind::AttrNotFound => "The attribute was not found on the device",
500 ErrorKind::AttrNotWritable => "The attribute is not writable",
501 ErrorKind::AttrKindInvalid => "Invalid attribute data kind",
502 ErrorKind::EventNotConnected => "Not able to connect to an event for subscribing",
503 ErrorKind::InvalidIndex => "Invalid index for data",
504 ErrorKind::InvalidData => "Failed to handle data",
505 ErrorKind::InvalidProp => "Failed to handle property",
506 ErrorKind::TimedOut => "The network operation timed out",
507 ErrorKind::Corba => "An error happened in the CORBA backend",
508 ErrorKind::Internal => "Internal error in the library, this is most likely a bug",
509 ErrorKind::Reason(_) => "",
510 }
511 }
512
513}
514
515#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
516pub enum ErrorSeverity {
517 Warning,
518 Error,
519 Panic,
520}
521
522/// Standard device failed reasons, documented after their usage in cppTango and `Databaseds`;
523/// the ones noted as *not used by cppTango* only exist there as a constant.
524#[allow(non_upper_case_globals)]
525pub mod reason {
526
527 macro_rules! define_reasons {
528 ( $( $(#[$meta:meta])* $reason:ident ),* $(,)? ) => {
529 $( $(#[$meta])* pub const $reason: &str = stringify!($reason); )*
530 };
531 }
532
533 define_reasons![
534 /// The device or attribute alias is not defined in the database.
535 API_AliasNotDefined,
536 /// The command or attribute is already in the polling list of the device.
537 API_AlreadyPolled,
538 /// The reply of an asynchronous call has not arrived yet.
539 API_AsynReplyNotArrived,
540 /// Attribute configuration could not be read or applied.
541 API_AttrConfig,
542 /// Attribute event properties are wrong or cannot be set. Not used by cppTango.
543 API_AttrEventProp,
544 /// Wrapper reason stacked on the real error when reading or writing an attribute failed.
545 API_AttributeFailed,
546 /// A `data_ready` event was asked on an attribute not data ready enabled.
547 API_AttributeNotDataReadyEnabled,
548 /// An event was asked but the polling needed to push it is not started.
549 API_AttributePollingNotStarted,
550 /// Incorrect number of elements given when writing an attribute value.
551 API_AttrIncorrectDataNumber,
552 /// Alarm information was asked on an attribute which has no alarm defined.
553 API_AttrNoAlarm,
554 /// The attribute operation is forbidden, e.g. a property not changeable at run time.
555 API_AttrNotAllowed,
556 /// The attribute does not exist on the device or in its class.
557 API_AttrNotFound,
558 /// Attribute history or cached value was asked while the attribute is not polled.
559 API_AttrNotPolled,
560 /// A write was attempted on an attribute which is not `READ_WRITE`/`READ_WITH_WRITE`.
561 API_AttrNotWritable,
562 /// Problem with the attribute value or its optional properties: null pointer, bad type.
563 API_AttrOptProp,
564 /// The numeric representation of an attribute property value has not been set.
565 API_AttrPropValueNotSet,
566 /// The attribute value was never updated, it cannot be read nor pushed as an event.
567 API_AttrValueNotSet,
568 /// The attribute is badly defined in its class: bad data type, association, memorized.
569 API_AttrWrongDefined,
570 /// The memorized value stored in the database for this attribute has an incorrect format.
571 API_AttrWrongMemValue,
572 /// The asynchronous callback request being looked up does not exist.
573 API_BadAsyn,
574 /// Invalid asynchronous request identifier given for the polling model.
575 API_BadAsynPollId,
576 /// The asynchronous request type is incompatible with the call made on it.
577 API_BadAsynReqType,
578 /// A device configuration property has a wrong syntax, e.g. `polled_attr`.
579 API_BadConfigurationProperty,
580 /// The argument given to read the black box is out of range.
581 API_BlackBoxArgument,
582 /// Nothing is stored in the device black box yet.
583 API_BlackBoxEmpty,
584 /// The access control device could not be imported, rights cannot be checked.
585 API_CannotCheckAccessControl,
586 /// A file could not be opened, in cppTango the device server logging file.
587 API_CannotOpenFile,
588 /// Activation of the CORBA POA manager failed. Not used by cppTango.
589 API_CantActivatePOAManager,
590 /// The database device could not be reached on the given host and port.
591 API_CantConnectToDatabase,
592 /// The connection to the device could not be built, e.g. nil reference or dead server.
593 API_CantConnectToDevice,
594 /// Creation of the CORBA POA of a device class failed. Not used by cppTango.
595 API_CantCreateClassPoa,
596 /// The thread keeping a device lock alive could not be created.
597 API_CantCreateLockingThread,
598 /// The device to remove is not in the device list of its Tango class.
599 API_CantDestroyDevice,
600 /// No locking thread was found for that device, e.g. unlocking a non locked device.
601 API_CantFindLockingThread,
602 /// The client identification, required by the lock commands, could not be retrieved.
603 API_CantGetClientIdent,
604 /// The CORBA reference id of a device could not be obtained.
605 API_CantGetDevObjectId,
606 /// Installing a signal handler failed, bad signal number or OS error.
607 API_CantInstallSignal,
608 /// The addresses of a host could not be resolved. Specific to rstango: cppTango has
609 /// no such reason.
610 API_CantResolveHost,
611 /// The Tango class of a device could not be retrieved.
612 API_CantRetrieveClass,
613 /// The class list of a device server could not be retrieved. Not used by cppTango.
614 API_CantRetrieveClassList,
615 /// The device class could not be inserted in the client side class cache.
616 API_CantStoreDeviceClass,
617 /// The Tango class is not known by the device server process.
618 API_ClassNotFound,
619 /// The client Tango release is too old for events or device locking.
620 API_ClientTooOld,
621 /// The command argument data type is not handled by this code path.
622 API_CmdArgumentTypeNotSupported,
623 /// Command history or cached result was asked while the command is not polled.
624 API_CmdNotPolled,
625 /// Wrapper reason stacked on the real error when a `command_inout` failed.
626 API_CommandFailed,
627 /// The command is not allowed in the current device state.
628 API_CommandNotAllowed,
629 /// The command does not exist in the command list of the device class.
630 API_CommandNotFound,
631 /// A server side timeout expired on a serialization monitor or a blocked polling thread.
632 API_CommandTimedOut,
633 /// The network exchange with the device failed, wraps the transport error.
634 API_CommunicationFailed,
635 /// A connection to a peer failed, in cppTango the log consumer device.
636 API_ConnectionFailed,
637 /// A CORBA user exception was received and translated into a Tango error.
638 API_CorbaException,
639 /// A CORBA system exception was caught, an unexpected ORB or transport failure.
640 API_CorbaSysException,
641 /// The database returned inconsistent attribute or pipe properties.
642 API_CorruptedDatabase,
643 /// An error occurred while reading from or writing to the database.
644 API_DatabaseAccess,
645 /// The entry is not available from the database cache built at server startup.
646 API_DatabaseCacheAccess,
647 /// Error with the file database used in `-file=` mode: syntax, access or missing class.
648 API_DatabaseFileError,
649 /// Decoding of a `DevEncoded` payload failed.
650 API_DecodeErr,
651 /// Encoding of a `DevEncoded` payload failed.
652 API_EncodeErr,
653 /// A deprecated admin command was called, e.g. `SetTraceLevel`.
654 API_DeprecatedCommand,
655 /// The device is already defined in the database. Not used by cppTango.
656 API_DeviceAlreadyDefined,
657 /// The device is locked by another client, the request is refused.
658 API_DeviceLocked,
659 /// The device is not defined in the database, it cannot be imported.
660 API_DeviceNotDefined,
661 /// The device is defined but not exported, its device server is not running.
662 API_DeviceNotExported,
663 /// The device was not found in the device list of the server.
664 API_DeviceNotFound,
665 /// The operation requires the device to be locked first.
666 API_DeviceNotLocked,
667 /// The device, or one of its objects, is not polled.
668 API_DeviceNotPolled,
669 /// The client side timeout expired while waiting for the device answer.
670 API_DeviceTimedOut,
671 /// The device cannot be locked at all, e.g. the admin or database device.
672 API_DeviceUnlockable,
673 /// The lock owned on the device has been released, reported to its holder.
674 API_DeviceUnlocked,
675 /// The `DServer` class singleton is not initialised yet.
676 API_DServerClassNotInitialised,
677 /// The device server refused or failed the event registration.
678 API_DSFailedRegisteringEvent,
679 /// Placeholder reason with no meaning, used internally and never propagated.
680 API_DummyException,
681 /// The pipe data element is empty, it holds no value to extract.
682 API_EmptyDataElement,
683 /// The `DbDatum` holds no data, the requested extraction is impossible.
684 API_EmptyDbDatum,
685 /// Same as [`API_EmptyDbDatum`], kept because of a historical typo in cppTango.
686 API_EmptyDbDbDatum,
687 /// The `DeviceAttribute` holds no data, the read failed or it is uninitialised.
688 API_EmptyDeviceAttribute,
689 /// The `DeviceData` holds no data, the requested extraction is impossible.
690 API_EmptyDeviceData,
691 /// The notifd event channel could not be found, no notifd runs on that host.
692 API_EventChannelNotExported,
693 /// No event consumer object is available, no subscription was done before.
694 API_EventConsumer,
695 /// The given event id is unknown, on unsubscribe or event queue access.
696 API_EventNotFound,
697 /// The event properties needed by the requested event are not configured.
698 API_EventPropertiesNotSet,
699 /// Misuse of the event queue: none configured, or no event available to return.
700 API_EventQueues,
701 /// The event supplier of the server is not created yet.
702 API_EventSupplierNotConstructed,
703 /// No event was received within the keep alive period, pushed to the callback.
704 API_EventTimeout,
705 /// Internal inconsistency in the forwarded attribute registry maps.
706 API_FwdAttrInconsistency,
707 /// The forwarded attribute has no valid root. Not used by cppTango, see [`API_AttrConfig`].
708 API_FwdAttrNotConfigured,
709 /// The history data received is invalid, its format could not be interpreted.
710 API_HistoryInvalid,
711 /// The data received from the database device is not what the client expected.
712 API_IncoherentDbData,
713 /// The data received from the device is not coherent with the type extracted.
714 API_IncoherentDevData,
715 /// Two related property values are incoherent, e.g. `min` greater than `max`.
716 API_IncoherentValues,
717 /// The argument type is incompatible with the target type, e.g. for an enum.
718 API_IncompatibleArgumentType,
719 /// The extracted type does not match the `DeviceAttribute` content.
720 API_IncompatibleAttrArgumentType,
721 /// The provided value data type does not match the attribute data type.
722 API_IncompatibleAttrDataType,
723 /// The command argument type does not match the type the command expects.
724 API_IncompatibleCmdArgumentType,
725 /// No `init_device` method found for the class. Not used by cppTango.
726 API_InitMethodNotFound,
727 /// The `init_device` method is not public and cannot be called. Not used by cppTango.
728 API_InitNotPublic,
729 /// `init_device()` threw, so the device is no longer available.
730 API_InitThrowsException,
731 /// Unexpected internal state of the library, and generic fallback reason.
732 API_InternalError,
733 /// An invalid argument was given to a library call or on the server command line.
734 API_InvalidArgs,
735 /// The received CORBA `Any` has an unexpected kind and cannot be interpreted.
736 API_InvalidCorbaAny,
737 /// A Java runtime security error occurred. JTango only.
738 API_JavaRuntimeSecurityException,
739 /// Writing a memorized attribute failed during the device startup sequence.
740 API_MemAttFailedDuringInit,
741 /// A memory allocation failed in the server or in the client.
742 API_MemoryAllocation,
743 /// A method argument is missing, of the wrong type, or in the wrong number.
744 API_MethodArgument,
745 /// The requested method was not found. JTango and PyTango only.
746 API_MethodNotFound,
747 /// Some events were lost, e.g. ZMQ high water mark reached, pushed to the callback.
748 API_MissedEvents,
749 /// Polling is configured but its cache holds no data yet for that object.
750 API_NoDataYet,
751 /// The method requires a database, but the device was built without one.
752 API_NonDatabaseDevice,
753 /// No write (set) value is available in the `DeviceAttribute`.
754 API_NoSetValueAvailable,
755 /// The notifd notification service failed, e.g. its factory import.
756 API_NotificationServiceFailed,
757 /// The operation is not supported in this context, e.g. polling not externally triggered.
758 API_NotSupported,
759 /// The peer does not support the feature, its IDL release is too old.
760 API_NotSupportedFeature,
761 /// The polling cache data is not refreshed any more, polling stopped or in error.
762 API_NotUpdatedAnyMore,
763 /// Creation of the Windows debug or main output window failed.
764 API_NtDebugWindowError,
765 /// Command or method overloading is not supported. PyTango and JTango only.
766 API_OverloadingNotSupported,
767 /// Data element not found in the pipe blob. Not used by cppTango, see [`API_PipeWrongArg`].
768 API_PipeDataEltNotFound,
769 /// Two data elements of the same pipe blob have the same name.
770 API_PipeDuplicateDEName,
771 /// Wrapper reason stacked on the real error when reading or writing a pipe failed.
772 API_PipeFailed,
773 /// No data element is available in the pipe blob for insertion or extraction.
774 API_PipeNoDataElement,
775 /// Reading or writing the pipe is currently not allowed, e.g. by the serial model.
776 API_PipeNotAllowed,
777 /// The pipe does not exist on the device or in its class.
778 API_PipeNotFound,
779 /// A write was attempted on a pipe which is not writable.
780 API_PipeNotWritable,
781 /// Problem with a pipe data element property, e.g. a null data pointer.
782 API_PipeOptProp,
783 /// The pipe value was never updated by the device, it cannot be read.
784 API_PipeValueNotSet,
785 /// Wrong argument used on a pipe blob: bad index, bad data type, or blob never received.
786 API_PipeWrongArg,
787 /// Wrong number of data elements given for a pipe. Not used by cppTango.
788 API_PipeWrongArgNumber,
789 /// The polling pool is full and the device is not in the pool configuration.
790 API_PolledDeviceNotInPoolConf,
791 /// The polling pool is full and the device is missing from the polled map.
792 API_PolledDeviceNotInPoolMap,
793 /// No polling thread was found for that device or thread id.
794 API_PollingThreadNotFound,
795 /// The command or attribute is not in the polled object list of the device.
796 API_PollObjNotFound,
797 /// Not enough data is stored yet in the polling ring buffer.
798 API_PollRingBufferEmpty,
799 /// The polling thread lost its schedule and is out of sync.
800 API_PollThreadOutOfSync,
801 /// Access control refused the request, the client only has read access.
802 API_ReadOnlyMode,
803 /// Root attribute access failed. Not used by cppTango, see [`API_AttributeFailed`].
804 API_RootAttrFailed,
805 /// The device server process is not running, reported without database.
806 API_ServerNotRunning,
807 /// The device server is shutting down and refuses the request.
808 API_ShutdownInProgress,
809 /// The signal number is out of range or cannot be handled by a user handler.
810 API_SignalOutOfRange,
811 /// An error occurred in the device server startup sequence.
812 API_StartupSequence,
813 /// A `std::exception` was caught and translated into a Tango error.
814 API_StdException,
815 /// A system call failed, e.g. socket creation or `getifaddrs()`.
816 API_SystemCallFailed,
817 /// The `TANGO_HOST` variable is not set, or its syntax is incorrect.
818 API_TangoHostNotSet,
819 /// Generic reason for an exception thrown on purpose. Not used by cppTango.
820 API_ThrowException,
821 /// The attribute is not supported by the device.
822 API_UnsupportedAttribute,
823 /// Unsupported database modifier in a name, only `#dbase=no|yes` are valid.
824 API_UnsupportedDBaseModifier,
825 /// The feature is absent from this build, e.g. a Tango built without jpeg.
826 API_UnsupportedFeature,
827 /// Unsupported protocol prefix in a name, only `tango://` is supported.
828 API_UnsupportedProtocol,
829 /// The `Util` singleton is not created, Tango is not initialised.
830 API_UtilSingletonNotCreated,
831 /// The `Util` singleton was inherited through a `fork()` without `exec()`.
832 API_UtilSingletonPoisoned,
833 /// The written value is outside the attribute limits, or is NaN/Inf, or too large.
834 API_WAttrOutsideLimit,
835 /// A property is already defined in the wizard configuration of the class.
836 API_WizardConfError,
837 /// Invalid attribute name syntax, four fields or a plain alias are expected.
838 API_WrongAttributeNameSyntax,
839 /// Wrong command line arguments given to the device server.
840 API_WrongCmdLineArgs,
841 /// Invalid device name syntax, `domain/family/member` is expected.
842 API_WrongDeviceNameSyntax,
843 /// The event data received is malformed and cannot be turned into a value.
844 API_WrongEventData,
845 /// The `DevEncoded` data is not in the expected image format.
846 API_WrongFormat,
847 /// The history data buffer received from the server is not valid.
848 API_WrongHistoryDataBuffer,
849 /// The locking status returned by the server is invalid.
850 API_WrongLockingStatus,
851 /// Wrong number of arguments given to a command, mostly the admin ones.
852 API_WrongNumberOfArgs,
853 /// Wrong use of wildcards in a pattern, only one `*` is allowed.
854 API_WrongWildcardUsage,
855 /// A ZMQ call failed at run time, when binding or pushing an event or heartbeat.
856 API_ZmqFailed,
857 /// ZMQ initialisation failed, on context creation or socket bind at startup.
858 API_ZmqInitFailed,
859 /// `Databaseds`: no alias for that device/attribute, or nothing matches that alias.
860 DB_AliasNotDefined,
861 /// The Tango class was not found in the startup database cache.
862 DB_ClassNotFoundInCache,
863 /// `Databaseds`: device, server, event or class not defined in the database.
864 DB_DeviceNotDefined,
865 /// The device or object was not found in the startup database cache.
866 DB_DeviceNotFoundInCache,
867 /// `Databaseds`: a MySQL query, a stored procedure or the given SQL command failed.
868 DB_SQLError,
869 /// The database stored procedure is too old, e.g. pipes need release 1.9.
870 DB_TooOldStoredProc,
871 ];
872
873}