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