1use std::{
6 error::Error,
7 fmt::Display,
8 io::{Read, Write},
9};
10
11use crate::{DecodingOptions, SimpleBinaryDecodable, UaNullable};
12
13use super::encoding::{read_u32, write_u32, EncodingResult, SimpleBinaryEncodable};
14
15#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
16pub struct StatusCode(u32);
19
20impl UaNullable for StatusCode {
21 fn is_ua_null(&self) -> bool {
22 self.0 == 0
23 }
24}
25
26#[cfg(feature = "json")]
27mod json {
28 use crate::json::*;
29 use std::io::{Read, Write};
30
31 use super::StatusCode;
32
33 impl JsonEncodable for StatusCode {
34 fn encode(
35 &self,
36 stream: &mut JsonStreamWriter<&mut dyn Write>,
37 _ctx: &crate::json::Context<'_>,
38 ) -> crate::EncodingResult<()> {
39 Ok(stream.number_value(self.0)?)
40 }
41 }
42
43 impl JsonDecodable for StatusCode {
44 fn decode(
45 stream: &mut JsonStreamReader<&mut dyn Read>,
46 _ctx: &Context<'_>,
47 ) -> crate::EncodingResult<Self> {
48 Ok(Self::from(stream.next_number::<u32>()??))
49 }
50 }
51}
52
53#[cfg(feature = "xml")]
54mod xml {
55 use crate::xml::*;
56 use std::io::{Read, Write};
57
58 use super::StatusCode;
59
60 impl XmlType for StatusCode {
61 const TAG: &'static str = "StatusCode";
62 }
63
64 impl XmlEncodable for StatusCode {
65 fn encode(
66 &self,
67 writer: &mut XmlStreamWriter<&mut dyn Write>,
68 context: &Context<'_>,
69 ) -> Result<(), Error> {
70 writer.encode_child("Code", &self.0, context)
71 }
72 }
73
74 impl XmlDecodable for StatusCode {
75 fn decode(
76 read: &mut XmlStreamReader<&mut dyn Read>,
77 context: &Context<'_>,
78 ) -> Result<Self, Error>
79 where
80 Self: Sized,
81 {
82 Ok(Self::from(
83 read.decode_single_child::<u32>("Code", context)?
84 .unwrap_or_default(),
85 ))
86 }
87 }
88}
89
90const SUBCODE_MASK: u32 = 0xffff_0000;
91const INFO_BITS_MASK: u32 = 0b0011_1111_1111;
92
93impl StatusCode {
94 pub fn is_good(&self) -> bool {
96 matches!(self.severity(), StatusCodeSeverity::Good)
97 }
98
99 pub fn is_bad(&self) -> bool {
101 matches!(self.severity(), StatusCodeSeverity::Bad)
102 }
103
104 pub fn is_uncertain(&self) -> bool {
106 matches!(self.severity(), StatusCodeSeverity::Uncertain)
107 }
108
109 pub fn bits(&self) -> u32 {
111 self.0
112 }
113
114 pub fn from_category(category: SubStatusCode) -> Self {
116 Self(category as u32)
117 }
118
119 fn get_bool(&self, offset: u8) -> bool {
120 (self.0 & (1 << offset)) != 0
121 }
122
123 #[must_use = "Status code is copied, not modified in place."]
124 fn set_bool(mut self, value: bool, offset: u8) -> Self {
125 self.0 = self.0 & !(1 << offset) | ((value as u32) << offset);
126 self
127 }
128
129 pub fn severity(&self) -> StatusCodeSeverity {
131 StatusCodeSeverity::from_value((self.0 >> 30) & 0b11).unwrap_or(StatusCodeSeverity::Bad)
133 }
134
135 #[must_use = "Status code is copied, not modified in place."]
139 pub fn set_severity(mut self, value: StatusCodeSeverity) -> Self {
140 self.0 = self.0 & !SUBCODE_MASK | ((value as u32) << 30);
143 self
144 }
145
146 pub fn structure_changed(&self) -> bool {
148 self.get_bool(15)
149 }
150
151 #[must_use = "Status code is copied, not modified in place."]
153 pub fn set_structure_changed(self, value: bool) -> Self {
154 self.set_bool(value, 15)
155 }
156
157 pub fn semantics_changed(&self) -> bool {
159 self.get_bool(14)
160 }
161
162 #[must_use = "Status code is copied, not modified in place."]
164 pub fn set_semantics_changed(self, value: bool) -> Self {
165 self.set_bool(value, 14)
166 }
167
168 pub fn sub_code(&self) -> SubStatusCode {
170 SubStatusCode::from_value(self.0 & SUBCODE_MASK).unwrap_or(SubStatusCode::Invalid)
171 }
172
173 #[must_use = "Status code is copied, not modified in place."]
175 pub fn set_sub_code(mut self, value: SubStatusCode) -> Self {
176 self.0 = self.0 & !SUBCODE_MASK | ((value as u32) & SUBCODE_MASK);
177 self
178 }
179
180 pub fn info_type(&self) -> StatusCodeInfoType {
182 StatusCodeInfoType::from_value((self.0 >> 10) & 1).unwrap_or(StatusCodeInfoType::NotUsed)
183 }
184
185 #[must_use = "Status code is copied, not modified in place."]
187 pub fn set_info_type(mut self, value: StatusCodeInfoType) -> Self {
188 self.0 = self.0 & !(1 << 10) | (((value as u32) & 1) << 10);
189 if matches!(value, StatusCodeInfoType::NotUsed) {
191 self.0 &= !INFO_BITS_MASK;
192 }
193 self
194 }
195
196 pub fn limit(&self) -> StatusCodeLimit {
198 StatusCodeLimit::from_value((self.0 >> 8) & 0b11).unwrap_or_default()
200 }
201
202 #[must_use = "Status code is copied, not modified in place."]
204 pub fn set_limit(mut self, limit: StatusCodeLimit) -> Self {
205 self.0 = self.0 & !(0b11 << 8) | ((limit as u32) << 8);
206 self
207 }
208
209 pub fn overflow(&self) -> bool {
211 self.get_bool(7)
212 }
213
214 #[must_use = "Status code is copied, not modified in place."]
216 pub fn set_overflow(self, value: bool) -> Self {
217 self.set_bool(value, 7)
218 }
219
220 pub fn multi_value(&self) -> bool {
222 self.get_bool(4)
223 }
224
225 #[must_use = "Status code is copied, not modified in place."]
227 pub fn set_multi_value(self, value: bool) -> Self {
228 self.set_bool(value, 4)
229 }
230
231 pub fn extra_data(&self) -> bool {
233 self.get_bool(3)
234 }
235
236 #[must_use = "Status code is copied, not modified in place."]
238 pub fn set_extra_data(self, value: bool) -> Self {
239 self.set_bool(value, 3)
240 }
241
242 pub fn partial(&self) -> bool {
244 self.get_bool(2)
245 }
246
247 #[must_use = "Status code is copied, not modified in place."]
249 pub fn set_partial(self, value: bool) -> Self {
250 self.set_bool(value, 2)
251 }
252
253 pub fn value_type(&self) -> StatusCodeValueType {
255 StatusCodeValueType::from_value(self.0 & 0b11).unwrap_or(StatusCodeValueType::Undefined)
256 }
257
258 #[must_use = "Status code is copied, not modified in place."]
260 pub fn set_value_type(mut self, value: StatusCodeValueType) -> Self {
261 self.0 = self.0 & !0b11 | ((value as u32) & 0b11);
262 self
263 }
264
265 pub fn validate(&self) -> Result<(), StatusCodeValidationError> {
270 if self.0 >> 30 == 0b11 {
271 return Err(StatusCodeValidationError::InvalidSeverity);
272 }
273
274 if self.0 & (0b11 << 28) != 0 || self.0 & (0b111 << 11) != 0 || self.0 & (0b11 << 5) != 0 {
275 return Err(StatusCodeValidationError::UsedReservedBit);
276 }
277
278 if self.sub_code() == SubStatusCode::Invalid {
279 return Err(StatusCodeValidationError::UnknownSubCode);
280 }
281
282 if matches!(self.info_type(), StatusCodeInfoType::NotUsed) && self.0 & INFO_BITS_MASK != 0 {
283 return Err(StatusCodeValidationError::InvalidInfoBits);
284 }
285
286 Ok(())
287 }
288}
289
290impl Display for StatusCode {
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 if self.0 == 0 {
294 return write!(f, "Good");
295 }
296
297 write!(f, "{}", self.sub_code())?;
298 if self.structure_changed() {
299 write!(f, ", StructureChanged")?;
300 }
301 if self.semantics_changed() {
302 write!(f, ", SemanticsChanged")?;
303 }
304 if self.limit() != StatusCodeLimit::None {
305 write!(f, ", {}", self.limit())?;
306 }
307 if self.overflow() {
308 write!(f, ", Overflow")?;
309 }
310 if self.multi_value() {
311 write!(f, ", MultiValue")?;
312 }
313 if self.extra_data() {
314 write!(f, ", ExtraData")?;
315 }
316 if self.partial() {
317 write!(f, ", Partial")?;
318 }
319 if self.value_type() != StatusCodeValueType::Raw {
320 write!(f, ", {}", self.value_type())?;
321 }
322 Ok(())
323 }
324}
325
326impl std::fmt::Debug for StatusCode {
327 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
328 write!(f, "{} ({})", self, self.0)
329 }
330}
331
332impl SimpleBinaryEncodable for StatusCode {
333 fn byte_len(&self) -> usize {
334 4
335 }
336
337 fn encode<S: Write + ?Sized>(&self, stream: &mut S) -> EncodingResult<()> {
338 write_u32(stream, self.bits())
339 }
340}
341
342impl SimpleBinaryDecodable for StatusCode {
343 fn decode<S: Read + ?Sized>(
344 stream: &mut S,
345 _decoding_options: &DecodingOptions,
346 ) -> EncodingResult<Self> {
347 Ok(StatusCode(read_u32(stream)?))
348 }
349}
350
351impl From<u32> for StatusCode {
352 fn from(value: u32) -> Self {
353 StatusCode(value)
354 }
355}
356
357impl From<StatusCode> for std::io::Error {
358 fn from(value: StatusCode) -> Self {
359 std::io::Error::other(format!("StatusCode {value}"))
360 }
361}
362
363impl Error for StatusCode {}
364
365#[derive(Debug, Clone)]
366pub enum StatusCodeValidationError {
368 InvalidSeverity,
370 UsedReservedBit,
372 UnknownSubCode,
374 InvalidInfoBits,
376}
377
378macro_rules! value_enum_impl {
383 (#[doc = $edoc:literal] $type:ident, $(#[doc = $doc:literal] $code:ident = $val:literal),* $(,)?) => {
384 value_enum_impl!(#[doc = $edoc] $type, _enum $($doc $code = $val),*);
385 value_enum_impl!($type, _name $($code),*);
386 value_enum_impl!($type, _from_val $($code = $val),*);
387 value_enum_impl!($type, _description $($doc $code),*);
388 };
389
390 (#[doc = $edoc:literal] $type:ident, _enum $($comment:literal $code:ident = $val:literal),*) => {
391 #[allow(non_camel_case_types)]
392 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
393 #[doc = $edoc]
394 #[repr(u32)]
395 pub enum $type {
396 $(#[doc = $comment] $code = $val),*
397 }
398
399 impl std::fmt::Debug for $type {
400 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
401 write!(f, "{} ({})", self.name(), (*self) as u32)
402 }
403 }
404 };
405
406 ($type:ident, _enum $($comment:literal $code:ident = $val:literal),*) => {
407 #[allow(non_camel_case_types)]
408 #[derive(Debug, Copy, Clone)]
409 pub enum $type {
410 $($(#[doc = $comment])? $code = $val),*
411 }
412 };
413
414 ($type:ident, _name $($code:ident),*) => {
415 impl $type {
416 pub fn name(&self) -> &'static str {
418 match self {
419 $(Self::$code => stringify!($code)),*
420 }
421 }
422 }
423
424 impl std::str::FromStr for $type {
425 type Err = ();
426
427 fn from_str(s: &str) -> Result<Self, Self::Err> {
428 match s {
429 $(stringify!($code) => Ok(Self::$code)),*,
430 _ => Err(())
431 }
432 }
433 }
434
435 impl std::fmt::Display for $type {
436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437 write!(f, "{}", self.name())
438 }
439 }
440 };
441
442 ($type:ident, _description $($comment:literal $code:ident),*) => {
443 impl $type {
444 pub fn description(&self) -> &'static str {
446 match self {
447 $(Self::$code => $comment),*
448 }
449 }
450 }
451 };
452
453 ($type:ident, _from_val $($code:ident = $val:literal),*) => {
454 impl $type {
455 pub fn from_value(val: u32) -> Option<Self> {
457 match val {
458 $($val => Some(Self::$code)),*,
459 _ => None
460 }
461 }
462 }
463 }
464}
465
466value_enum_impl!(
472 StatusCodeLimit,
474 Constant = 0b11,
476 High = 0b10,
478 Low = 0b01,
480 None = 0b00,
482);
483
484#[allow(clippy::derivable_impls)]
485impl Default for StatusCodeLimit {
486 fn default() -> Self {
487 Self::None
488 }
489}
490
491value_enum_impl!(
492 StatusCodeSeverity,
494 Good = 0b00,
496 Uncertain = 0b01,
498 Bad = 0b10,
500);
501
502#[allow(clippy::derivable_impls)]
503impl Default for StatusCodeSeverity {
504 fn default() -> Self {
505 Self::Good
506 }
507}
508
509value_enum_impl!(
510 StatusCodeValueType,
512 Raw = 0b00,
514 Calculated = 0b01,
516 Interpolated = 0b10,
518 Undefined = 0b11
520);
521
522value_enum_impl!(
523 StatusCodeInfoType,
525 NotUsed = 0,
527 DataValue = 1,
529);
530
531macro_rules! sub_code_impl {
536 ($($code:ident,$val:literal,$doc:literal)*) => {
537 value_enum_impl!(
538 SubStatusCode,
540 $(#[doc = $doc] $code = $val),*
541 );
542 sub_code_impl!(_code_consts $($doc $code = $val),*);
543 };
544
545 (_code_consts $($comment:literal $code:ident = $val:literal),*) => {
546 #[allow(non_upper_case_globals)]
547 impl StatusCode {
548 $(#[doc = $comment] pub const $code: StatusCode = StatusCode($val);)*
549 }
550 };
551}
552
553sub_code_impl! {
554 Good,0x00000000,"The operation succeeded."
555 Uncertain,0x40000000,"The operation was uncertain."
556 Bad,0x80000000,"The operation failed."
557 BadUnexpectedError,0x80010000,"An unexpected error occurred."
558 BadInternalError,0x80020000,"An internal error occurred as a result of a programming or configuration error."
559 BadOutOfMemory,0x80030000,"Not enough memory to complete the operation."
560 BadResourceUnavailable,0x80040000,"An operating system resource is not available."
561 BadCommunicationError,0x80050000,"A low level communication error occurred."
562 BadEncodingError,0x80060000,"Encoding halted because of invalid data in the objects being serialized."
563 BadDecodingError,0x80070000,"Decoding halted because of invalid data in the stream."
564 BadEncodingLimitsExceeded,0x80080000,"The message encoding/decoding limits imposed by the stack have been exceeded."
565 BadRequestTooLarge,0x80B80000,"The request message size exceeds limits set by the server."
566 BadResponseTooLarge,0x80B90000,"The response message size exceeds limits set by the client or server."
567 BadUnknownResponse,0x80090000,"An unrecognized response was received from the server."
568 BadTimeout,0x800A0000,"The operation timed out."
569 BadServiceUnsupported,0x800B0000,"The server does not support the requested service."
570 BadShutdown,0x800C0000,"The operation was cancelled because the application is shutting down."
571 BadServerNotConnected,0x800D0000,"The operation could not complete because the client is not connected to the server."
572 BadServerHalted,0x800E0000,"The server has stopped and cannot process any requests."
573 BadNothingToDo,0x800F0000,"No processing could be done because there was nothing to do."
574 BadTooManyOperations,0x80100000,"The request could not be processed because it specified too many operations."
575 BadTooManyMonitoredItems,0x80DB0000,"The request could not be processed because there are too many monitored items in the subscription."
576 BadDataTypeIdUnknown,0x80110000,"The extension object cannot be (de)serialized because the data type id is not recognized."
577 BadCertificateInvalid,0x80120000,"The certificate provided as a parameter is not valid."
578 BadSecurityChecksFailed,0x80130000,"An error occurred verifying security."
579 BadCertificatePolicyCheckFailed,0x81140000,"The certificate does not meet the requirements of the security policy."
580 BadCertificateTimeInvalid,0x80140000,"The certificate has expired or is not yet valid."
581 BadCertificateIssuerTimeInvalid,0x80150000,"An issuer certificate has expired or is not yet valid."
582 BadCertificateHostNameInvalid,0x80160000,"The HostName used to connect to a server does not match a HostName in the certificate."
583 BadCertificateUriInvalid,0x80170000,"The URI specified in the ApplicationDescription does not match the URI in the certificate."
584 BadCertificateUseNotAllowed,0x80180000,"The certificate may not be used for the requested operation."
585 BadCertificateIssuerUseNotAllowed,0x80190000,"The issuer certificate may not be used for the requested operation."
586 BadCertificateUntrusted,0x801A0000,"The certificate is not trusted."
587 BadCertificateRevocationUnknown,0x801B0000,"It was not possible to determine if the certificate has been revoked."
588 BadCertificateIssuerRevocationUnknown,0x801C0000,"It was not possible to determine if the issuer certificate has been revoked."
589 BadCertificateRevoked,0x801D0000,"The certificate has been revoked."
590 BadCertificateIssuerRevoked,0x801E0000,"The issuer certificate has been revoked."
591 BadCertificateChainIncomplete,0x810D0000,"The certificate chain is incomplete."
592 BadUserAccessDenied,0x801F0000,"User does not have permission to perform the requested operation."
593 BadIdentityTokenInvalid,0x80200000,"The user identity token is not valid."
594 BadIdentityTokenRejected,0x80210000,"The user identity token is valid but the server has rejected it."
595 BadSecureChannelIdInvalid,0x80220000,"The specified secure channel is no longer valid."
596 BadInvalidTimestamp,0x80230000,"The timestamp is outside the range allowed by the server."
597 BadNonceInvalid,0x80240000,"The nonce does appear to be not a random value or it is not the correct length."
598 BadSessionIdInvalid,0x80250000,"The session id is not valid."
599 BadSessionClosed,0x80260000,"The session was closed by the client."
600 BadSessionNotActivated,0x80270000,"The session cannot be used because ActivateSession has not been called."
601 BadSubscriptionIdInvalid,0x80280000,"The subscription id is not valid."
602 BadRequestHeaderInvalid,0x802A0000,"The header for the request is missing or invalid."
603 BadTimestampsToReturnInvalid,0x802B0000,"The timestamps to return parameter is invalid."
604 BadRequestCancelledByClient,0x802C0000,"The request was cancelled by the client."
605 BadTooManyArguments,0x80E50000,"Too many arguments were provided."
606 BadLicenseExpired,0x810E0000,"The server requires a license to operate in general or to perform a service or operation, but existing license is expired."
607 BadLicenseLimitsExceeded,0x810F0000,"The server has limits on number of allowed operations / objects, based on installed licenses, and these limits where exceeded."
608 BadLicenseNotAvailable,0x81100000,"The server does not have a license which is required to operate in general or to perform a service or operation."
609 BadServerTooBusy,0x80EE0000,"The Server does not have the resources to process the request at this time."
610 GoodPasswordChangeRequired,0x00EF0000,"The log-on for the user succeeded but the user is required to change the password."
611 GoodSubscriptionTransferred,0x002D0000,"The subscription was transferred to another session."
612 GoodCompletesAsynchronously,0x002E0000,"The processing will complete asynchronously."
613 GoodOverload,0x002F0000,"Sampling has slowed down due to resource limitations."
614 GoodClamped,0x00300000,"The value written was accepted but was clamped."
615 BadNoCommunication,0x80310000,"Communication with the data source is defined, but not established, and there is no last known value available."
616 BadWaitingForInitialData,0x80320000,"Waiting for the server to obtain values from the underlying data source."
617 BadNodeIdInvalid,0x80330000,"The syntax the node id is not valid or refers to a node that is not valid for the operation."
618 BadNodeIdUnknown,0x80340000,"The node id refers to a node that does not exist in the server address space."
619 BadAttributeIdInvalid,0x80350000,"The attribute is not supported for the specified Node."
620 BadIndexRangeInvalid,0x80360000,"The syntax of the index range parameter is invalid."
621 BadIndexRangeNoData,0x80370000,"No data exists within the range of indexes specified."
622 BadIndexRangeDataMismatch,0x80EA0000,"The written data does not match the IndexRange specified."
623 BadDataEncodingInvalid,0x80380000,"The data encoding is invalid."
624 BadDataEncodingUnsupported,0x80390000,"The server does not support the requested data encoding for the node."
625 BadNotReadable,0x803A0000,"The access level does not allow reading or subscribing to the Node."
626 BadNotWritable,0x803B0000,"The access level does not allow writing to the Node."
627 BadOutOfRange,0x803C0000,"The value was out of range."
628 BadNotSupported,0x803D0000,"The requested operation is not supported."
629 BadNotFound,0x803E0000,"A requested item was not found or a search operation ended without success."
630 BadObjectDeleted,0x803F0000,"The object cannot be used because it has been deleted."
631 BadNotImplemented,0x80400000,"Requested operation is not implemented."
632 BadMonitoringModeInvalid,0x80410000,"The monitoring mode is invalid."
633 BadMonitoredItemIdInvalid,0x80420000,"The monitoring item id does not refer to a valid monitored item."
634 BadMonitoredItemFilterInvalid,0x80430000,"The monitored item filter parameter is not valid."
635 BadMonitoredItemFilterUnsupported,0x80440000,"The server does not support the requested monitored item filter."
636 BadFilterNotAllowed,0x80450000,"A monitoring filter cannot be used in combination with the attribute specified."
637 BadStructureMissing,0x80460000,"A mandatory structured parameter was missing or null."
638 BadEventFilterInvalid,0x80470000,"The event filter is not valid."
639 BadContentFilterInvalid,0x80480000,"The content filter is not valid."
640 BadFilterOperatorInvalid,0x80C10000,"An unrecognized operator was provided in a filter."
641 BadFilterOperatorUnsupported,0x80C20000,"A valid operator was provided, but the server does not provide support for this filter operator."
642 BadFilterOperandCountMismatch,0x80C30000,"The number of operands provided for the filter operator was less then expected for the operand provided."
643 BadFilterOperandInvalid,0x80490000,"The operand used in a content filter is not valid."
644 BadFilterElementInvalid,0x80C40000,"The referenced element is not a valid element in the content filter."
645 BadFilterLiteralInvalid,0x80C50000,"The referenced literal is not a valid value."
646 BadContinuationPointInvalid,0x804A0000,"The continuation point provide is longer valid."
647 BadNoContinuationPoints,0x804B0000,"The operation could not be processed because all continuation points have been allocated."
648 BadReferenceTypeIdInvalid,0x804C0000,"The reference type id does not refer to a valid reference type node."
649 BadBrowseDirectionInvalid,0x804D0000,"The browse direction is not valid."
650 BadNodeNotInView,0x804E0000,"The node is not part of the view."
651 BadNumericOverflow,0x81120000,"The number was not accepted because of a numeric overflow."
652 BadLocaleNotSupported,0x80ED0000,"The locale in the requested write operation is not supported."
653 BadNoValue,0x80F00000,"The variable has no default value and no initial value."
654 BadServerUriInvalid,0x804F0000,"The ServerUri is not a valid URI."
655 BadServerNameMissing,0x80500000,"No ServerName was specified."
656 BadDiscoveryUrlMissing,0x80510000,"No DiscoveryUrl was specified."
657 BadSempahoreFileMissing,0x80520000,"The semaphore file specified by the client is not valid."
658 BadRequestTypeInvalid,0x80530000,"The security token request type is not valid."
659 BadSecurityModeRejected,0x80540000,"The security mode does not meet the requirements set by the server."
660 BadSecurityPolicyRejected,0x80550000,"The security policy does not meet the requirements set by the server."
661 BadTooManySessions,0x80560000,"The server has reached its maximum number of sessions."
662 BadUserSignatureInvalid,0x80570000,"The user token signature is missing or invalid."
663 BadApplicationSignatureInvalid,0x80580000,"The signature generated with the client certificate is missing or invalid."
664 BadNoValidCertificates,0x80590000,"The client did not provide at least one software certificate that is valid and meets the profile requirements for the server."
665 BadIdentityChangeNotSupported,0x80C60000,"The server does not support changing the user identity assigned to the session."
666 BadRequestCancelledByRequest,0x805A0000,"The request was cancelled by the client with the Cancel service."
667 BadParentNodeIdInvalid,0x805B0000,"The parent node id does not to refer to a valid node."
668 BadReferenceNotAllowed,0x805C0000,"The reference could not be created because it violates constraints imposed by the data model."
669 BadNodeIdRejected,0x805D0000,"The requested node id was reject because it was either invalid or server does not allow node ids to be specified by the client."
670 BadNodeIdExists,0x805E0000,"The requested node id is already used by another node."
671 BadNodeClassInvalid,0x805F0000,"The node class is not valid."
672 BadBrowseNameInvalid,0x80600000,"The browse name is invalid."
673 BadBrowseNameDuplicated,0x80610000,"The browse name is not unique among nodes that share the same relationship with the parent."
674 BadNodeAttributesInvalid,0x80620000,"The node attributes are not valid for the node class."
675 BadTypeDefinitionInvalid,0x80630000,"The type definition node id does not reference an appropriate type node."
676 BadSourceNodeIdInvalid,0x80640000,"The source node id does not reference a valid node."
677 BadTargetNodeIdInvalid,0x80650000,"The target node id does not reference a valid node."
678 BadDuplicateReferenceNotAllowed,0x80660000,"The reference type between the nodes is already defined."
679 BadInvalidSelfReference,0x80670000,"The server does not allow this type of self reference on this node."
680 BadReferenceLocalOnly,0x80680000,"The reference type is not valid for a reference to a remote server."
681 BadNoDeleteRights,0x80690000,"The server will not allow the node to be deleted."
682 UncertainReferenceNotDeleted,0x40BC0000,"The server was not able to delete all target references."
683 BadServerIndexInvalid,0x806A0000,"The server index is not valid."
684 BadViewIdUnknown,0x806B0000,"The view id does not refer to a valid view node."
685 BadViewTimestampInvalid,0x80C90000,"The view timestamp is not available or not supported."
686 BadViewParameterMismatch,0x80CA0000,"The view parameters are not consistent with each other."
687 BadViewVersionInvalid,0x80CB0000,"The view version is not available or not supported."
688 UncertainNotAllNodesAvailable,0x40C00000,"The list of references may not be complete because the underlying system is not available."
689 GoodResultsMayBeIncomplete,0x00BA0000,"The server should have followed a reference to a node in a remote server but did not. The result set may be incomplete."
690 BadNotTypeDefinition,0x80C80000,"The provided Nodeid was not a type definition nodeid."
691 UncertainReferenceOutOfServer,0x406C0000,"One of the references to follow in the relative path references to a node in the address space in another server."
692 BadTooManyMatches,0x806D0000,"The requested operation has too many matches to return."
693 BadQueryTooComplex,0x806E0000,"The requested operation requires too many resources in the server."
694 BadNoMatch,0x806F0000,"The requested operation has no match to return."
695 BadMaxAgeInvalid,0x80700000,"The max age parameter is invalid."
696 BadSecurityModeInsufficient,0x80E60000,"The operation is not permitted over the current secure channel."
697 BadHistoryOperationInvalid,0x80710000,"The history details parameter is not valid."
698 BadHistoryOperationUnsupported,0x80720000,"The server does not support the requested operation."
699 BadInvalidTimestampArgument,0x80BD0000,"The defined timestamp to return was invalid."
700 BadWriteNotSupported,0x80730000,"The server does not support writing the combination of value, status and timestamps provided."
701 BadTypeMismatch,0x80740000,"The value supplied for the attribute is not of the same type as the attribute's value."
702 BadMethodInvalid,0x80750000,"The method id does not refer to a method for the specified object."
703 BadArgumentsMissing,0x80760000,"The client did not specify all of the input arguments for the method."
704 BadNotExecutable,0x81110000,"The executable attribute does not allow the execution of the method."
705 BadTooManySubscriptions,0x80770000,"The server has reached its maximum number of subscriptions."
706 BadTooManyPublishRequests,0x80780000,"The server has reached the maximum number of queued publish requests."
707 BadNoSubscription,0x80790000,"There is no subscription available for this session."
708 BadSequenceNumberUnknown,0x807A0000,"The sequence number is unknown to the server."
709 GoodRetransmissionQueueNotSupported,0x00DF0000,"The Server does not support retransmission queue and acknowledgement of sequence numbers is not available."
710 BadMessageNotAvailable,0x807B0000,"The requested notification message is no longer available."
711 BadInsufficientClientProfile,0x807C0000,"The client of the current session does not support one or more Profiles that are necessary for the subscription."
712 BadStateNotActive,0x80BF0000,"The sub-state machine is not currently active."
713 BadAlreadyExists,0x81150000,"An equivalent rule already exists."
714 BadTcpServerTooBusy,0x807D0000,"The server cannot process the request because it is too busy."
715 BadTcpMessageTypeInvalid,0x807E0000,"The type of the message specified in the header invalid."
716 BadTcpSecureChannelUnknown,0x807F0000,"The SecureChannelId and/or TokenId are not currently in use."
717 BadTcpMessageTooLarge,0x80800000,"The size of the message chunk specified in the header is too large."
718 BadTcpNotEnoughResources,0x80810000,"There are not enough resources to process the request."
719 BadTcpInternalError,0x80820000,"An internal error occurred."
720 BadTcpEndpointUrlInvalid,0x80830000,"The server does not recognize the QueryString specified."
721 BadRequestInterrupted,0x80840000,"The request could not be sent because of a network interruption."
722 BadRequestTimeout,0x80850000,"Timeout occurred while processing the request."
723 BadSecureChannelClosed,0x80860000,"The secure channel has been closed."
724 BadSecureChannelTokenUnknown,0x80870000,"The token has expired or is not recognized."
725 BadSequenceNumberInvalid,0x80880000,"The sequence number is not valid."
726 BadProtocolVersionUnsupported,0x80BE0000,"The applications do not have compatible protocol versions."
727 BadConfigurationError,0x80890000,"There is a problem with the configuration that affects the usefulness of the value."
728 BadNotConnected,0x808A0000,"The variable should receive its value from another variable, but has never been configured to do so."
729 BadDeviceFailure,0x808B0000,"There has been a failure in the device/data source that generates the value that has affected the value."
730 BadSensorFailure,0x808C0000,"There has been a failure in the sensor from which the value is derived by the device/data source."
731 BadOutOfService,0x808D0000,"The source of the data is not operational."
732 BadDeadbandFilterInvalid,0x808E0000,"The deadband filter is not valid."
733 UncertainNoCommunicationLastUsableValue,0x408F0000,"Communication to the data source has failed. The variable value is the last value that had a good quality."
734 UncertainLastUsableValue,0x40900000,"Whatever was updating this value has stopped doing so."
735 UncertainSubstituteValue,0x40910000,"The value is an operational value that was manually overwritten."
736 UncertainInitialValue,0x40920000,"The value is an initial value for a variable that normally receives its value from another variable."
737 UncertainSensorNotAccurate,0x40930000,"The value is at one of the sensor limits."
738 UncertainEngineeringUnitsExceeded,0x40940000,"The value is outside of the range of values defined for this parameter."
739 UncertainSubNormal,0x40950000,"The data value is derived from multiple sources and has less than the required number of Good sources."
740 GoodLocalOverride,0x00960000,"The value has been overridden."
741 GoodSubNormal,0x00EB0000,"The value is derived from multiple sources and has the required number of Good sources, but less than the full number of Good sources."
742 BadRefreshInProgress,0x80970000,"This Condition refresh failed, a Condition refresh operation is already in progress."
743 BadConditionAlreadyDisabled,0x80980000,"This condition has already been disabled."
744 BadConditionAlreadyEnabled,0x80CC0000,"This condition has already been enabled."
745 BadConditionDisabled,0x80990000,"Property not available, this condition is disabled."
746 BadEventIdUnknown,0x809A0000,"The specified event id is not recognized."
747 BadEventNotAcknowledgeable,0x80BB0000,"The event cannot be acknowledged."
748 BadDialogNotActive,0x80CD0000,"The dialog condition is not active."
749 BadDialogResponseInvalid,0x80CE0000,"The response is not valid for the dialog."
750 BadConditionBranchAlreadyAcked,0x80CF0000,"The condition branch has already been acknowledged."
751 BadConditionBranchAlreadyConfirmed,0x80D00000,"The condition branch has already been confirmed."
752 BadConditionAlreadyShelved,0x80D10000,"The condition has already been shelved."
753 BadConditionNotShelved,0x80D20000,"The condition is not currently shelved."
754 BadShelvingTimeOutOfRange,0x80D30000,"The shelving time not within an acceptable range."
755 BadNoData,0x809B0000,"No data exists for the requested time range or event filter."
756 BadBoundNotFound,0x80D70000,"No data found to provide upper or lower bound value."
757 BadBoundNotSupported,0x80D80000,"The server cannot retrieve a bound for the variable."
758 BadDataLost,0x809D0000,"Data is missing due to collection started/stopped/lost."
759 BadDataUnavailable,0x809E0000,"Expected data is unavailable for the requested time range due to an un-mounted volume, an off-line archive or tape, or similar reason for temporary unavailability."
760 BadEntryExists,0x809F0000,"The data or event was not successfully inserted because a matching entry exists."
761 BadNoEntryExists,0x80A00000,"The data or event was not successfully updated because no matching entry exists."
762 BadTimestampNotSupported,0x80A10000,"The Client requested history using a TimestampsToReturn the Server does not support."
763 GoodEntryInserted,0x00A20000,"The data or event was successfully inserted into the historical database."
764 GoodEntryReplaced,0x00A30000,"The data or event field was successfully replaced in the historical database."
765 UncertainDataSubNormal,0x40A40000,"The aggregate value is derived from multiple values and has less than the required number of Good values."
766 GoodNoData,0x00A50000,"No data exists for the requested time range or event filter."
767 GoodMoreData,0x00A60000,"More data is available in the time range beyond the number of values requested."
768 BadAggregateListMismatch,0x80D40000,"The requested number of Aggregates does not match the requested number of NodeIds."
769 BadAggregateNotSupported,0x80D50000,"The requested Aggregate is not support by the server."
770 BadAggregateInvalidInputs,0x80D60000,"The aggregate value could not be derived due to invalid data inputs."
771 BadAggregateConfigurationRejected,0x80DA0000,"The aggregate configuration is not valid for specified node."
772 GoodDataIgnored,0x00D90000,"The request specifies fields which are not valid for the EventType or cannot be saved by the historian."
773 BadRequestNotAllowed,0x80E40000,"The request was rejected by the server because it did not meet the criteria set by the server."
774 BadRequestNotComplete,0x81130000,"The request has not been processed by the server yet."
775 BadTransactionPending,0x80E80000,"The operation is not allowed because a transaction is in progress."
776 BadTicketRequired,0x811F0000,"The device identity needs a ticket before it can be accepted."
777 BadTicketInvalid,0x81200000,"The device identity needs a ticket before it can be accepted."
778 BadLocked,0x80E90000,"The requested operation is not allowed, because the Node is locked by a different application."
779 BadRequiresLock,0x80EC0000,"The requested operation is not allowed, because the Node is not locked by the application."
780 GoodEdited,0x00DC0000,"The value does not come from the real source and has been edited by the server."
781 GoodPostActionFailed,0x00DD0000,"There was an error in execution of these post-actions."
782 UncertainDominantValueChanged,0x40DE0000,"The related EngineeringUnit has been changed but the Variable Value is still provided based on the previous unit."
783 GoodDependentValueChanged,0x00E00000,"A dependent value has been changed but the change has not been applied to the device."
784 BadDominantValueChanged,0x80E10000,"The related EngineeringUnit has been changed but this change has not been applied to the device. The Variable Value is still dependent on the previous unit but its status is currently Bad."
785 UncertainDependentValueChanged,0x40E20000,"A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is uncertain."
786 BadDependentValueChanged,0x80E30000,"A dependent value has been changed but the change has not been applied to the device. The quality of the dominant variable is Bad."
787 GoodEdited_DependentValueChanged,0x01160000,"It is delivered with a dominant Variable value when a dependent Variable has changed but the change has not been applied."
788 GoodEdited_DominantValueChanged,0x01170000,"It is delivered with a dependent Variable value when a dominant Variable has changed but the change has not been applied."
789 GoodEdited_DominantValueChanged_DependentValueChanged,0x01180000,"It is delivered with a dependent Variable value when a dominant or dependent Variable has changed but change has not been applied."
790 BadEdited_OutOfRange,0x81190000,"It is delivered with a Variable value when Variable has changed but the value is not legal."
791 BadInitialValue_OutOfRange,0x811A0000,"It is delivered with a Variable value when a source Variable has changed but the value is not legal."
792 BadOutOfRange_DominantValueChanged,0x811B0000,"It is delivered with a dependent Variable value when a dominant Variable has changed and the value is not legal."
793 BadEdited_OutOfRange_DominantValueChanged,0x811C0000,"It is delivered with a dependent Variable value when a dominant Variable has changed, the value is not legal and the change has not been applied."
794 BadOutOfRange_DominantValueChanged_DependentValueChanged,0x811D0000,"It is delivered with a dependent Variable value when a dominant or dependent Variable has changed and the value is not legal."
795 BadEdited_OutOfRange_DominantValueChanged_DependentValueChanged,0x811E0000,"It is delivered with a dependent Variable value when a dominant or dependent Variable has changed, the value is not legal and the change has not been applied."
796 GoodCommunicationEvent,0x00A70000,"The communication layer has raised an event."
797 GoodShutdownEvent,0x00A80000,"The system is shutting down."
798 GoodCallAgain,0x00A90000,"The operation is not finished and needs to be called again."
799 GoodNonCriticalTimeout,0x00AA0000,"A non-critical timeout occurred."
800 BadInvalidArgument,0x80AB0000,"One or more arguments are invalid."
801 BadConnectionRejected,0x80AC0000,"Could not establish a network connection to remote server."
802 BadDisconnect,0x80AD0000,"The server has disconnected from the client."
803 BadConnectionClosed,0x80AE0000,"The network connection has been closed."
804 BadInvalidState,0x80AF0000,"The operation cannot be completed because the object is closed, uninitialized or in some other invalid state."
805 BadEndOfStream,0x80B00000,"Cannot move beyond end of the stream."
806 BadNoDataAvailable,0x80B10000,"No data is currently available for reading from a non-blocking stream."
807 BadWaitingForResponse,0x80B20000,"The asynchronous operation is waiting for a response."
808 BadOperationAbandoned,0x80B30000,"The asynchronous operation was abandoned by the caller."
809 BadExpectedStreamToBlock,0x80B40000,"The stream did not return all data requested (possibly because it is a non-blocking stream)."
810 BadWouldBlock,0x80B50000,"Non blocking behaviour is required and the operation would block."
811 BadSyntaxError,0x80B60000,"A value had an invalid syntax."
812 BadMaxConnectionsReached,0x80B70000,"The operation could not be finished because all available connections are in use."
813 UncertainTransducerInManual,0x42080000,"The value may not be accurate because the transducer is in manual mode."
814 UncertainSimulatedValue,0x42090000,"The value is simulated."
815 UncertainSensorCalibration,0x420A0000,"The value may not be accurate due to a sensor calibration fault."
816 UncertainConfigurationError,0x420F0000,"The value may not be accurate due to a configuration issue."
817 GoodCascadeInitializationAcknowledged,0x04010000,"The value source supports cascade handshaking and the value has been Initialized based on an initialization request from a cascade secondary."
818 GoodCascadeInitializationRequest,0x04020000,"The value source supports cascade handshaking and is requesting initialization of a cascade primary."
819 GoodCascadeNotInvited,0x04030000,"The value source supports cascade handshaking, however, the source’s current state does not allow for cascade."
820 GoodCascadeNotSelected,0x04040000,"The value source supports cascade handshaking, however, the source has not selected the corresponding cascade primary for use."
821 GoodFaultStateActive,0x04070000,"There is a fault state condition active in the value source."
822 GoodInitiateFaultState,0x04080000,"A fault state condition is being requested of the destination."
823 GoodCascade,0x04090000,"The value is accurate, and the signal source supports cascade handshaking."
824 BadDataSetIdInvalid,0x80E70000,"The DataSet specified for the DataSetWriter creation is invalid."
825
826 Invalid,0xFFFFFFFF,"Invalid status code"
827}
828#[cfg(test)]
831mod tests {
832 use super::{
833 StatusCode, StatusCodeInfoType, StatusCodeLimit, StatusCodeSeverity,
834 StatusCodeValidationError, StatusCodeValueType, SubStatusCode,
835 };
836
837 #[test]
838 fn test_from_sub_code() {
839 assert_eq!("Good", StatusCode::Good.to_string());
840 assert_eq!(
841 "BadBrowseDirectionInvalid",
842 StatusCode::BadBrowseDirectionInvalid.to_string()
843 );
844 assert_eq!(
845 "UncertainDependentValueChanged",
846 StatusCode::UncertainDependentValueChanged.to_string()
847 );
848 }
849
850 #[test]
851 fn test_modify() {
852 let code = StatusCode::from(0);
853 assert_eq!(code, StatusCode::Good);
854 let code = code.set_severity(StatusCodeSeverity::Uncertain);
855 assert_eq!(code.severity(), StatusCodeSeverity::Uncertain);
856 let code = code.set_severity(StatusCodeSeverity::Bad);
857 assert_eq!(code.severity(), StatusCodeSeverity::Bad);
858
859 code.validate().unwrap();
860
861 assert!(!code.structure_changed());
862 let code = code.set_structure_changed(true);
863 code.validate().unwrap();
864 assert!(code.structure_changed());
865 let code = code.set_structure_changed(false);
866 assert!(!code.structure_changed());
867 let code = code.set_structure_changed(true);
868
869 assert!(!code.semantics_changed());
870 let code = code.set_semantics_changed(true);
871 code.validate().unwrap();
872 assert!(code.semantics_changed());
873 let code = code.set_semantics_changed(false);
874 assert!(!code.semantics_changed());
875 let code = code.set_semantics_changed(true);
876
877 assert_eq!(code.sub_code(), SubStatusCode::Bad);
878 let code = code.set_sub_code(SubStatusCode::BadAggregateConfigurationRejected);
879 assert_eq!(
880 code.sub_code(),
881 SubStatusCode::BadAggregateConfigurationRejected
882 );
883 let code = code.set_sub_code(SubStatusCode::UncertainNotAllNodesAvailable);
884 assert_eq!(
885 code.sub_code(),
886 SubStatusCode::UncertainNotAllNodesAvailable
887 );
888
889 assert_eq!(code.info_type(), StatusCodeInfoType::NotUsed);
890 let code = code.set_info_type(StatusCodeInfoType::DataValue);
891 assert_eq!(code.info_type(), StatusCodeInfoType::DataValue);
892 code.validate().unwrap();
893 let code = code.set_info_type(StatusCodeInfoType::NotUsed);
894 assert_eq!(code.info_type(), StatusCodeInfoType::NotUsed);
895
896 assert_eq!(code.limit(), StatusCodeLimit::None);
897 let code = code.set_limit(StatusCodeLimit::High);
898 assert_eq!(code.limit(), StatusCodeLimit::High);
899 let code = code.set_limit(StatusCodeLimit::Constant);
900 assert_eq!(code.limit(), StatusCodeLimit::Constant);
901
902 assert!(matches!(
903 code.validate(),
904 Err(StatusCodeValidationError::InvalidInfoBits)
905 ));
906 let code = code.set_info_type(StatusCodeInfoType::DataValue);
907 code.validate().unwrap();
908
909 assert!(!code.overflow());
910 let code = code.set_overflow(true);
911 code.validate().unwrap();
912 assert!(code.overflow());
913 let code = code.set_overflow(false);
914 assert!(!code.overflow());
915 let code = code.set_overflow(true);
916
917 assert!(!code.multi_value());
918 let code = code.set_multi_value(true);
919 code.validate().unwrap();
920 assert!(code.multi_value());
921 let code = code.set_multi_value(false);
922 assert!(!code.multi_value());
923 let code = code.set_multi_value(true);
924
925 assert!(!code.extra_data());
926 let code = code.set_extra_data(true);
927 code.validate().unwrap();
928 assert!(code.extra_data());
929 let code = code.set_extra_data(false);
930 assert!(!code.extra_data());
931 let code = code.set_extra_data(true);
932
933 assert!(!code.partial());
934 let code = code.set_partial(true);
935 code.validate().unwrap();
936 assert!(code.partial());
937 let code = code.set_partial(false);
938 assert!(!code.partial());
939 let code = code.set_partial(true);
940
941 assert_eq!(code.value_type(), StatusCodeValueType::Raw);
942 let code = code.set_value_type(StatusCodeValueType::Calculated);
943 assert_eq!(code.value_type(), StatusCodeValueType::Calculated);
944 let code = code.set_value_type(StatusCodeValueType::Interpolated);
945 assert_eq!(code.value_type(), StatusCodeValueType::Interpolated);
946
947 assert_eq!(StatusCodeSeverity::Uncertain, code.severity());
948 assert!(code.structure_changed());
949 assert!(code.semantics_changed());
950 assert_eq!(code.info_type(), StatusCodeInfoType::DataValue);
951 assert_eq!(
952 code.sub_code(),
953 SubStatusCode::UncertainNotAllNodesAvailable
954 );
955 assert!(code.overflow());
956 assert!(code.multi_value());
957 assert!(code.extra_data());
958 assert!(code.partial());
959 assert_eq!(code.value_type(), StatusCodeValueType::Interpolated);
960
961 code.validate().unwrap();
962 }
963}