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
484impl Default for StatusCodeLimit {
485 fn default() -> Self {
486 Self::None
487 }
488}
489
490value_enum_impl!(
491 StatusCodeSeverity,
493 Good = 0b00,
495 Uncertain = 0b01,
497 Bad = 0b10,
499);
500
501impl Default for StatusCodeSeverity {
502 fn default() -> Self {
503 Self::Good
504 }
505}
506
507value_enum_impl!(
508 StatusCodeValueType,
510 Raw = 0b00,
512 Calculated = 0b01,
514 Interpolated = 0b10,
516 Undefined = 0b11
518);
519
520value_enum_impl!(
521 StatusCodeInfoType,
523 NotUsed = 0,
525 DataValue = 1,
527);
528
529macro_rules! sub_code_impl {
534 ($($code:ident,$val:literal,$doc:literal)*) => {
535 value_enum_impl!(
536 SubStatusCode,
538 $(#[doc = $doc] $code = $val),*
539 );
540 sub_code_impl!(_code_consts $($doc $code = $val),*);
541 };
542
543 (_code_consts $($comment:literal $code:ident = $val:literal),*) => {
544 #[allow(non_upper_case_globals)]
545 impl StatusCode {
546 $(#[doc = $comment] pub const $code: StatusCode = StatusCode($val);)*
547 }
548 };
549}
550
551sub_code_impl! {
552 Good,0x00000000,"The operation succeeded."
553 Uncertain,0x40000000,"The operation was uncertain."
554 Bad,0x80000000,"The operation failed."
555 BadUnexpectedError,0x80010000,"An unexpected error occurred."
556 BadInternalError,0x80020000,"An internal error occurred as a result of a programming or configuration error."
557 BadOutOfMemory,0x80030000,"Not enough memory to complete the operation."
558 BadResourceUnavailable,0x80040000,"An operating system resource is not available."
559 BadCommunicationError,0x80050000,"A low level communication error occurred."
560 BadEncodingError,0x80060000,"Encoding halted because of invalid data in the objects being serialized."
561 BadDecodingError,0x80070000,"Decoding halted because of invalid data in the stream."
562 BadEncodingLimitsExceeded,0x80080000,"The message encoding/decoding limits imposed by the stack have been exceeded."
563 BadRequestTooLarge,0x80B80000,"The request message size exceeds limits set by the server."
564 BadResponseTooLarge,0x80B90000,"The response message size exceeds limits set by the client or server."
565 BadUnknownResponse,0x80090000,"An unrecognized response was received from the server."
566 BadTimeout,0x800A0000,"The operation timed out."
567 BadServiceUnsupported,0x800B0000,"The server does not support the requested service."
568 BadShutdown,0x800C0000,"The operation was cancelled because the application is shutting down."
569 BadServerNotConnected,0x800D0000,"The operation could not complete because the client is not connected to the server."
570 BadServerHalted,0x800E0000,"The server has stopped and cannot process any requests."
571 BadNothingToDo,0x800F0000,"No processing could be done because there was nothing to do."
572 BadTooManyOperations,0x80100000,"The request could not be processed because it specified too many operations."
573 BadTooManyMonitoredItems,0x80DB0000,"The request could not be processed because there are too many monitored items in the subscription."
574 BadDataTypeIdUnknown,0x80110000,"The extension object cannot be (de)serialized because the data type id is not recognized."
575 BadCertificateInvalid,0x80120000,"The certificate provided as a parameter is not valid."
576 BadSecurityChecksFailed,0x80130000,"An error occurred verifying security."
577 BadCertificatePolicyCheckFailed,0x81140000,"The certificate does not meet the requirements of the security policy."
578 BadCertificateTimeInvalid,0x80140000,"The certificate has expired or is not yet valid."
579 BadCertificateIssuerTimeInvalid,0x80150000,"An issuer certificate has expired or is not yet valid."
580 BadCertificateHostNameInvalid,0x80160000,"The HostName used to connect to a server does not match a HostName in the certificate."
581 BadCertificateUriInvalid,0x80170000,"The URI specified in the ApplicationDescription does not match the URI in the certificate."
582 BadCertificateUseNotAllowed,0x80180000,"The certificate may not be used for the requested operation."
583 BadCertificateIssuerUseNotAllowed,0x80190000,"The issuer certificate may not be used for the requested operation."
584 BadCertificateUntrusted,0x801A0000,"The certificate is not trusted."
585 BadCertificateRevocationUnknown,0x801B0000,"It was not possible to determine if the certificate has been revoked."
586 BadCertificateIssuerRevocationUnknown,0x801C0000,"It was not possible to determine if the issuer certificate has been revoked."
587 BadCertificateRevoked,0x801D0000,"The certificate has been revoked."
588 BadCertificateIssuerRevoked,0x801E0000,"The issuer certificate has been revoked."
589 BadCertificateChainIncomplete,0x810D0000,"The certificate chain is incomplete."
590 BadUserAccessDenied,0x801F0000,"User does not have permission to perform the requested operation."
591 BadIdentityTokenInvalid,0x80200000,"The user identity token is not valid."
592 BadIdentityTokenRejected,0x80210000,"The user identity token is valid but the server has rejected it."
593 BadSecureChannelIdInvalid,0x80220000,"The specified secure channel is no longer valid."
594 BadInvalidTimestamp,0x80230000,"The timestamp is outside the range allowed by the server."
595 BadNonceInvalid,0x80240000,"The nonce does appear to be not a random value or it is not the correct length."
596 BadSessionIdInvalid,0x80250000,"The session id is not valid."
597 BadSessionClosed,0x80260000,"The session was closed by the client."
598 BadSessionNotActivated,0x80270000,"The session cannot be used because ActivateSession has not been called."
599 BadSubscriptionIdInvalid,0x80280000,"The subscription id is not valid."
600 BadRequestHeaderInvalid,0x802A0000,"The header for the request is missing or invalid."
601 BadTimestampsToReturnInvalid,0x802B0000,"The timestamps to return parameter is invalid."
602 BadRequestCancelledByClient,0x802C0000,"The request was cancelled by the client."
603 BadTooManyArguments,0x80E50000,"Too many arguments were provided."
604 BadLicenseExpired,0x810E0000,"The server requires a license to operate in general or to perform a service or operation, but existing license is expired."
605 BadLicenseLimitsExceeded,0x810F0000,"The server has limits on number of allowed operations / objects, based on installed licenses, and these limits where exceeded."
606 BadLicenseNotAvailable,0x81100000,"The server does not have a license which is required to operate in general or to perform a service or operation."
607 BadServerTooBusy,0x80EE0000,"The Server does not have the resources to process the request at this time."
608 GoodPasswordChangeRequired,0x00EF0000,"The log-on for the user succeeded but the user is required to change the password."
609 GoodSubscriptionTransferred,0x002D0000,"The subscription was transferred to another session."
610 GoodCompletesAsynchronously,0x002E0000,"The processing will complete asynchronously."
611 GoodOverload,0x002F0000,"Sampling has slowed down due to resource limitations."
612 GoodClamped,0x00300000,"The value written was accepted but was clamped."
613 BadNoCommunication,0x80310000,"Communication with the data source is defined, but not established, and there is no last known value available."
614 BadWaitingForInitialData,0x80320000,"Waiting for the server to obtain values from the underlying data source."
615 BadNodeIdInvalid,0x80330000,"The syntax the node id is not valid or refers to a node that is not valid for the operation."
616 BadNodeIdUnknown,0x80340000,"The node id refers to a node that does not exist in the server address space."
617 BadAttributeIdInvalid,0x80350000,"The attribute is not supported for the specified Node."
618 BadIndexRangeInvalid,0x80360000,"The syntax of the index range parameter is invalid."
619 BadIndexRangeNoData,0x80370000,"No data exists within the range of indexes specified."
620 BadIndexRangeDataMismatch,0x80EA0000,"The written data does not match the IndexRange specified."
621 BadDataEncodingInvalid,0x80380000,"The data encoding is invalid."
622 BadDataEncodingUnsupported,0x80390000,"The server does not support the requested data encoding for the node."
623 BadNotReadable,0x803A0000,"The access level does not allow reading or subscribing to the Node."
624 BadNotWritable,0x803B0000,"The access level does not allow writing to the Node."
625 BadOutOfRange,0x803C0000,"The value was out of range."
626 BadNotSupported,0x803D0000,"The requested operation is not supported."
627 BadNotFound,0x803E0000,"A requested item was not found or a search operation ended without success."
628 BadObjectDeleted,0x803F0000,"The object cannot be used because it has been deleted."
629 BadNotImplemented,0x80400000,"Requested operation is not implemented."
630 BadMonitoringModeInvalid,0x80410000,"The monitoring mode is invalid."
631 BadMonitoredItemIdInvalid,0x80420000,"The monitoring item id does not refer to a valid monitored item."
632 BadMonitoredItemFilterInvalid,0x80430000,"The monitored item filter parameter is not valid."
633 BadMonitoredItemFilterUnsupported,0x80440000,"The server does not support the requested monitored item filter."
634 BadFilterNotAllowed,0x80450000,"A monitoring filter cannot be used in combination with the attribute specified."
635 BadStructureMissing,0x80460000,"A mandatory structured parameter was missing or null."
636 BadEventFilterInvalid,0x80470000,"The event filter is not valid."
637 BadContentFilterInvalid,0x80480000,"The content filter is not valid."
638 BadFilterOperatorInvalid,0x80C10000,"An unrecognized operator was provided in a filter."
639 BadFilterOperatorUnsupported,0x80C20000,"A valid operator was provided, but the server does not provide support for this filter operator."
640 BadFilterOperandCountMismatch,0x80C30000,"The number of operands provided for the filter operator was less then expected for the operand provided."
641 BadFilterOperandInvalid,0x80490000,"The operand used in a content filter is not valid."
642 BadFilterElementInvalid,0x80C40000,"The referenced element is not a valid element in the content filter."
643 BadFilterLiteralInvalid,0x80C50000,"The referenced literal is not a valid value."
644 BadContinuationPointInvalid,0x804A0000,"The continuation point provide is longer valid."
645 BadNoContinuationPoints,0x804B0000,"The operation could not be processed because all continuation points have been allocated."
646 BadReferenceTypeIdInvalid,0x804C0000,"The reference type id does not refer to a valid reference type node."
647 BadBrowseDirectionInvalid,0x804D0000,"The browse direction is not valid."
648 BadNodeNotInView,0x804E0000,"The node is not part of the view."
649 BadNumericOverflow,0x81120000,"The number was not accepted because of a numeric overflow."
650 BadLocaleNotSupported,0x80ED0000,"The locale in the requested write operation is not supported."
651 BadNoValue,0x80F00000,"The variable has no default value and no initial value."
652 BadServerUriInvalid,0x804F0000,"The ServerUri is not a valid URI."
653 BadServerNameMissing,0x80500000,"No ServerName was specified."
654 BadDiscoveryUrlMissing,0x80510000,"No DiscoveryUrl was specified."
655 BadSempahoreFileMissing,0x80520000,"The semaphore file specified by the client is not valid."
656 BadRequestTypeInvalid,0x80530000,"The security token request type is not valid."
657 BadSecurityModeRejected,0x80540000,"The security mode does not meet the requirements set by the server."
658 BadSecurityPolicyRejected,0x80550000,"The security policy does not meet the requirements set by the server."
659 BadTooManySessions,0x80560000,"The server has reached its maximum number of sessions."
660 BadUserSignatureInvalid,0x80570000,"The user token signature is missing or invalid."
661 BadApplicationSignatureInvalid,0x80580000,"The signature generated with the client certificate is missing or invalid."
662 BadNoValidCertificates,0x80590000,"The client did not provide at least one software certificate that is valid and meets the profile requirements for the server."
663 BadIdentityChangeNotSupported,0x80C60000,"The server does not support changing the user identity assigned to the session."
664 BadRequestCancelledByRequest,0x805A0000,"The request was cancelled by the client with the Cancel service."
665 BadParentNodeIdInvalid,0x805B0000,"The parent node id does not to refer to a valid node."
666 BadReferenceNotAllowed,0x805C0000,"The reference could not be created because it violates constraints imposed by the data model."
667 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."
668 BadNodeIdExists,0x805E0000,"The requested node id is already used by another node."
669 BadNodeClassInvalid,0x805F0000,"The node class is not valid."
670 BadBrowseNameInvalid,0x80600000,"The browse name is invalid."
671 BadBrowseNameDuplicated,0x80610000,"The browse name is not unique among nodes that share the same relationship with the parent."
672 BadNodeAttributesInvalid,0x80620000,"The node attributes are not valid for the node class."
673 BadTypeDefinitionInvalid,0x80630000,"The type definition node id does not reference an appropriate type node."
674 BadSourceNodeIdInvalid,0x80640000,"The source node id does not reference a valid node."
675 BadTargetNodeIdInvalid,0x80650000,"The target node id does not reference a valid node."
676 BadDuplicateReferenceNotAllowed,0x80660000,"The reference type between the nodes is already defined."
677 BadInvalidSelfReference,0x80670000,"The server does not allow this type of self reference on this node."
678 BadReferenceLocalOnly,0x80680000,"The reference type is not valid for a reference to a remote server."
679 BadNoDeleteRights,0x80690000,"The server will not allow the node to be deleted."
680 UncertainReferenceNotDeleted,0x40BC0000,"The server was not able to delete all target references."
681 BadServerIndexInvalid,0x806A0000,"The server index is not valid."
682 BadViewIdUnknown,0x806B0000,"The view id does not refer to a valid view node."
683 BadViewTimestampInvalid,0x80C90000,"The view timestamp is not available or not supported."
684 BadViewParameterMismatch,0x80CA0000,"The view parameters are not consistent with each other."
685 BadViewVersionInvalid,0x80CB0000,"The view version is not available or not supported."
686 UncertainNotAllNodesAvailable,0x40C00000,"The list of references may not be complete because the underlying system is not available."
687 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."
688 BadNotTypeDefinition,0x80C80000,"The provided Nodeid was not a type definition nodeid."
689 UncertainReferenceOutOfServer,0x406C0000,"One of the references to follow in the relative path references to a node in the address space in another server."
690 BadTooManyMatches,0x806D0000,"The requested operation has too many matches to return."
691 BadQueryTooComplex,0x806E0000,"The requested operation requires too many resources in the server."
692 BadNoMatch,0x806F0000,"The requested operation has no match to return."
693 BadMaxAgeInvalid,0x80700000,"The max age parameter is invalid."
694 BadSecurityModeInsufficient,0x80E60000,"The operation is not permitted over the current secure channel."
695 BadHistoryOperationInvalid,0x80710000,"The history details parameter is not valid."
696 BadHistoryOperationUnsupported,0x80720000,"The server does not support the requested operation."
697 BadInvalidTimestampArgument,0x80BD0000,"The defined timestamp to return was invalid."
698 BadWriteNotSupported,0x80730000,"The server does not support writing the combination of value, status and timestamps provided."
699 BadTypeMismatch,0x80740000,"The value supplied for the attribute is not of the same type as the attribute's value."
700 BadMethodInvalid,0x80750000,"The method id does not refer to a method for the specified object."
701 BadArgumentsMissing,0x80760000,"The client did not specify all of the input arguments for the method."
702 BadNotExecutable,0x81110000,"The executable attribute does not allow the execution of the method."
703 BadTooManySubscriptions,0x80770000,"The server has reached its maximum number of subscriptions."
704 BadTooManyPublishRequests,0x80780000,"The server has reached the maximum number of queued publish requests."
705 BadNoSubscription,0x80790000,"There is no subscription available for this session."
706 BadSequenceNumberUnknown,0x807A0000,"The sequence number is unknown to the server."
707 GoodRetransmissionQueueNotSupported,0x00DF0000,"The Server does not support retransmission queue and acknowledgement of sequence numbers is not available."
708 BadMessageNotAvailable,0x807B0000,"The requested notification message is no longer available."
709 BadInsufficientClientProfile,0x807C0000,"The client of the current session does not support one or more Profiles that are necessary for the subscription."
710 BadStateNotActive,0x80BF0000,"The sub-state machine is not currently active."
711 BadAlreadyExists,0x81150000,"An equivalent rule already exists."
712 BadTcpServerTooBusy,0x807D0000,"The server cannot process the request because it is too busy."
713 BadTcpMessageTypeInvalid,0x807E0000,"The type of the message specified in the header invalid."
714 BadTcpSecureChannelUnknown,0x807F0000,"The SecureChannelId and/or TokenId are not currently in use."
715 BadTcpMessageTooLarge,0x80800000,"The size of the message chunk specified in the header is too large."
716 BadTcpNotEnoughResources,0x80810000,"There are not enough resources to process the request."
717 BadTcpInternalError,0x80820000,"An internal error occurred."
718 BadTcpEndpointUrlInvalid,0x80830000,"The server does not recognize the QueryString specified."
719 BadRequestInterrupted,0x80840000,"The request could not be sent because of a network interruption."
720 BadRequestTimeout,0x80850000,"Timeout occurred while processing the request."
721 BadSecureChannelClosed,0x80860000,"The secure channel has been closed."
722 BadSecureChannelTokenUnknown,0x80870000,"The token has expired or is not recognized."
723 BadSequenceNumberInvalid,0x80880000,"The sequence number is not valid."
724 BadProtocolVersionUnsupported,0x80BE0000,"The applications do not have compatible protocol versions."
725 BadConfigurationError,0x80890000,"There is a problem with the configuration that affects the usefulness of the value."
726 BadNotConnected,0x808A0000,"The variable should receive its value from another variable, but has never been configured to do so."
727 BadDeviceFailure,0x808B0000,"There has been a failure in the device/data source that generates the value that has affected the value."
728 BadSensorFailure,0x808C0000,"There has been a failure in the sensor from which the value is derived by the device/data source."
729 BadOutOfService,0x808D0000,"The source of the data is not operational."
730 BadDeadbandFilterInvalid,0x808E0000,"The deadband filter is not valid."
731 UncertainNoCommunicationLastUsableValue,0x408F0000,"Communication to the data source has failed. The variable value is the last value that had a good quality."
732 UncertainLastUsableValue,0x40900000,"Whatever was updating this value has stopped doing so."
733 UncertainSubstituteValue,0x40910000,"The value is an operational value that was manually overwritten."
734 UncertainInitialValue,0x40920000,"The value is an initial value for a variable that normally receives its value from another variable."
735 UncertainSensorNotAccurate,0x40930000,"The value is at one of the sensor limits."
736 UncertainEngineeringUnitsExceeded,0x40940000,"The value is outside of the range of values defined for this parameter."
737 UncertainSubNormal,0x40950000,"The data value is derived from multiple sources and has less than the required number of Good sources."
738 GoodLocalOverride,0x00960000,"The value has been overridden."
739 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."
740 BadRefreshInProgress,0x80970000,"This Condition refresh failed, a Condition refresh operation is already in progress."
741 BadConditionAlreadyDisabled,0x80980000,"This condition has already been disabled."
742 BadConditionAlreadyEnabled,0x80CC0000,"This condition has already been enabled."
743 BadConditionDisabled,0x80990000,"Property not available, this condition is disabled."
744 BadEventIdUnknown,0x809A0000,"The specified event id is not recognized."
745 BadEventNotAcknowledgeable,0x80BB0000,"The event cannot be acknowledged."
746 BadDialogNotActive,0x80CD0000,"The dialog condition is not active."
747 BadDialogResponseInvalid,0x80CE0000,"The response is not valid for the dialog."
748 BadConditionBranchAlreadyAcked,0x80CF0000,"The condition branch has already been acknowledged."
749 BadConditionBranchAlreadyConfirmed,0x80D00000,"The condition branch has already been confirmed."
750 BadConditionAlreadyShelved,0x80D10000,"The condition has already been shelved."
751 BadConditionNotShelved,0x80D20000,"The condition is not currently shelved."
752 BadShelvingTimeOutOfRange,0x80D30000,"The shelving time not within an acceptable range."
753 BadNoData,0x809B0000,"No data exists for the requested time range or event filter."
754 BadBoundNotFound,0x80D70000,"No data found to provide upper or lower bound value."
755 BadBoundNotSupported,0x80D80000,"The server cannot retrieve a bound for the variable."
756 BadDataLost,0x809D0000,"Data is missing due to collection started/stopped/lost."
757 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."
758 BadEntryExists,0x809F0000,"The data or event was not successfully inserted because a matching entry exists."
759 BadNoEntryExists,0x80A00000,"The data or event was not successfully updated because no matching entry exists."
760 BadTimestampNotSupported,0x80A10000,"The Client requested history using a TimestampsToReturn the Server does not support."
761 GoodEntryInserted,0x00A20000,"The data or event was successfully inserted into the historical database."
762 GoodEntryReplaced,0x00A30000,"The data or event field was successfully replaced in the historical database."
763 UncertainDataSubNormal,0x40A40000,"The aggregate value is derived from multiple values and has less than the required number of Good values."
764 GoodNoData,0x00A50000,"No data exists for the requested time range or event filter."
765 GoodMoreData,0x00A60000,"More data is available in the time range beyond the number of values requested."
766 BadAggregateListMismatch,0x80D40000,"The requested number of Aggregates does not match the requested number of NodeIds."
767 BadAggregateNotSupported,0x80D50000,"The requested Aggregate is not support by the server."
768 BadAggregateInvalidInputs,0x80D60000,"The aggregate value could not be derived due to invalid data inputs."
769 BadAggregateConfigurationRejected,0x80DA0000,"The aggregate configuration is not valid for specified node."
770 GoodDataIgnored,0x00D90000,"The request specifies fields which are not valid for the EventType or cannot be saved by the historian."
771 BadRequestNotAllowed,0x80E40000,"The request was rejected by the server because it did not meet the criteria set by the server."
772 BadRequestNotComplete,0x81130000,"The request has not been processed by the server yet."
773 BadTransactionPending,0x80E80000,"The operation is not allowed because a transaction is in progress."
774 BadTicketRequired,0x811F0000,"The device identity needs a ticket before it can be accepted."
775 BadTicketInvalid,0x81200000,"The device identity needs a ticket before it can be accepted."
776 BadLocked,0x80E90000,"The requested operation is not allowed, because the Node is locked by a different application."
777 BadRequiresLock,0x80EC0000,"The requested operation is not allowed, because the Node is not locked by the application."
778 GoodEdited,0x00DC0000,"The value does not come from the real source and has been edited by the server."
779 GoodPostActionFailed,0x00DD0000,"There was an error in execution of these post-actions."
780 UncertainDominantValueChanged,0x40DE0000,"The related EngineeringUnit has been changed but the Variable Value is still provided based on the previous unit."
781 GoodDependentValueChanged,0x00E00000,"A dependent value has been changed but the change has not been applied to the device."
782 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."
783 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."
784 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."
785 GoodEdited_DependentValueChanged,0x01160000,"It is delivered with a dominant Variable value when a dependent Variable has changed but the change has not been applied."
786 GoodEdited_DominantValueChanged,0x01170000,"It is delivered with a dependent Variable value when a dominant Variable has changed but the change has not been applied."
787 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."
788 BadEdited_OutOfRange,0x81190000,"It is delivered with a Variable value when Variable has changed but the value is not legal."
789 BadInitialValue_OutOfRange,0x811A0000,"It is delivered with a Variable value when a source Variable has changed but the value is not legal."
790 BadOutOfRange_DominantValueChanged,0x811B0000,"It is delivered with a dependent Variable value when a dominant Variable has changed and the value is not legal."
791 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."
792 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."
793 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."
794 GoodCommunicationEvent,0x00A70000,"The communication layer has raised an event."
795 GoodShutdownEvent,0x00A80000,"The system is shutting down."
796 GoodCallAgain,0x00A90000,"The operation is not finished and needs to be called again."
797 GoodNonCriticalTimeout,0x00AA0000,"A non-critical timeout occurred."
798 BadInvalidArgument,0x80AB0000,"One or more arguments are invalid."
799 BadConnectionRejected,0x80AC0000,"Could not establish a network connection to remote server."
800 BadDisconnect,0x80AD0000,"The server has disconnected from the client."
801 BadConnectionClosed,0x80AE0000,"The network connection has been closed."
802 BadInvalidState,0x80AF0000,"The operation cannot be completed because the object is closed, uninitialized or in some other invalid state."
803 BadEndOfStream,0x80B00000,"Cannot move beyond end of the stream."
804 BadNoDataAvailable,0x80B10000,"No data is currently available for reading from a non-blocking stream."
805 BadWaitingForResponse,0x80B20000,"The asynchronous operation is waiting for a response."
806 BadOperationAbandoned,0x80B30000,"The asynchronous operation was abandoned by the caller."
807 BadExpectedStreamToBlock,0x80B40000,"The stream did not return all data requested (possibly because it is a non-blocking stream)."
808 BadWouldBlock,0x80B50000,"Non blocking behaviour is required and the operation would block."
809 BadSyntaxError,0x80B60000,"A value had an invalid syntax."
810 BadMaxConnectionsReached,0x80B70000,"The operation could not be finished because all available connections are in use."
811 UncertainTransducerInManual,0x42080000,"The value may not be accurate because the transducer is in manual mode."
812 UncertainSimulatedValue,0x42090000,"The value is simulated."
813 UncertainSensorCalibration,0x420A0000,"The value may not be accurate due to a sensor calibration fault."
814 UncertainConfigurationError,0x420F0000,"The value may not be accurate due to a configuration issue."
815 GoodCascadeInitializationAcknowledged,0x04010000,"The value source supports cascade handshaking and the value has been Initialized based on an initialization request from a cascade secondary."
816 GoodCascadeInitializationRequest,0x04020000,"The value source supports cascade handshaking and is requesting initialization of a cascade primary."
817 GoodCascadeNotInvited,0x04030000,"The value source supports cascade handshaking, however, the source’s current state does not allow for cascade."
818 GoodCascadeNotSelected,0x04040000,"The value source supports cascade handshaking, however, the source has not selected the corresponding cascade primary for use."
819 GoodFaultStateActive,0x04070000,"There is a fault state condition active in the value source."
820 GoodInitiateFaultState,0x04080000,"A fault state condition is being requested of the destination."
821 GoodCascade,0x04090000,"The value is accurate, and the signal source supports cascade handshaking."
822 BadDataSetIdInvalid,0x80E70000,"The DataSet specified for the DataSetWriter creation is invalid."
823
824 Invalid,0xFFFFFFFF,"Invalid status code"
825}
826#[cfg(test)]
829mod tests {
830 use super::{
831 StatusCode, StatusCodeInfoType, StatusCodeLimit, StatusCodeSeverity,
832 StatusCodeValidationError, StatusCodeValueType, SubStatusCode,
833 };
834
835 #[test]
836 fn test_from_sub_code() {
837 assert_eq!("Good", StatusCode::Good.to_string());
838 assert_eq!(
839 "BadBrowseDirectionInvalid",
840 StatusCode::BadBrowseDirectionInvalid.to_string()
841 );
842 assert_eq!(
843 "UncertainDependentValueChanged",
844 StatusCode::UncertainDependentValueChanged.to_string()
845 );
846 }
847
848 #[test]
849 fn test_modify() {
850 let code = StatusCode::from(0);
851 assert_eq!(code, StatusCode::Good);
852 let code = code.set_severity(StatusCodeSeverity::Uncertain);
853 assert_eq!(code.severity(), StatusCodeSeverity::Uncertain);
854 let code = code.set_severity(StatusCodeSeverity::Bad);
855 assert_eq!(code.severity(), StatusCodeSeverity::Bad);
856
857 code.validate().unwrap();
858
859 assert!(!code.structure_changed());
860 let code = code.set_structure_changed(true);
861 code.validate().unwrap();
862 assert!(code.structure_changed());
863 let code = code.set_structure_changed(false);
864 assert!(!code.structure_changed());
865 let code = code.set_structure_changed(true);
866
867 assert!(!code.semantics_changed());
868 let code = code.set_semantics_changed(true);
869 code.validate().unwrap();
870 assert!(code.semantics_changed());
871 let code = code.set_semantics_changed(false);
872 assert!(!code.semantics_changed());
873 let code = code.set_semantics_changed(true);
874
875 assert_eq!(code.sub_code(), SubStatusCode::Bad);
876 let code = code.set_sub_code(SubStatusCode::BadAggregateConfigurationRejected);
877 assert_eq!(
878 code.sub_code(),
879 SubStatusCode::BadAggregateConfigurationRejected
880 );
881 let code = code.set_sub_code(SubStatusCode::UncertainNotAllNodesAvailable);
882 assert_eq!(
883 code.sub_code(),
884 SubStatusCode::UncertainNotAllNodesAvailable
885 );
886
887 assert_eq!(code.info_type(), StatusCodeInfoType::NotUsed);
888 let code = code.set_info_type(StatusCodeInfoType::DataValue);
889 assert_eq!(code.info_type(), StatusCodeInfoType::DataValue);
890 code.validate().unwrap();
891 let code = code.set_info_type(StatusCodeInfoType::NotUsed);
892 assert_eq!(code.info_type(), StatusCodeInfoType::NotUsed);
893
894 assert_eq!(code.limit(), StatusCodeLimit::None);
895 let code = code.set_limit(StatusCodeLimit::High);
896 assert_eq!(code.limit(), StatusCodeLimit::High);
897 let code = code.set_limit(StatusCodeLimit::Constant);
898 assert_eq!(code.limit(), StatusCodeLimit::Constant);
899
900 assert!(matches!(
901 code.validate(),
902 Err(StatusCodeValidationError::InvalidInfoBits)
903 ));
904 let code = code.set_info_type(StatusCodeInfoType::DataValue);
905 code.validate().unwrap();
906
907 assert!(!code.overflow());
908 let code = code.set_overflow(true);
909 code.validate().unwrap();
910 assert!(code.overflow());
911 let code = code.set_overflow(false);
912 assert!(!code.overflow());
913 let code = code.set_overflow(true);
914
915 assert!(!code.multi_value());
916 let code = code.set_multi_value(true);
917 code.validate().unwrap();
918 assert!(code.multi_value());
919 let code = code.set_multi_value(false);
920 assert!(!code.multi_value());
921 let code = code.set_multi_value(true);
922
923 assert!(!code.extra_data());
924 let code = code.set_extra_data(true);
925 code.validate().unwrap();
926 assert!(code.extra_data());
927 let code = code.set_extra_data(false);
928 assert!(!code.extra_data());
929 let code = code.set_extra_data(true);
930
931 assert!(!code.partial());
932 let code = code.set_partial(true);
933 code.validate().unwrap();
934 assert!(code.partial());
935 let code = code.set_partial(false);
936 assert!(!code.partial());
937 let code = code.set_partial(true);
938
939 assert_eq!(code.value_type(), StatusCodeValueType::Raw);
940 let code = code.set_value_type(StatusCodeValueType::Calculated);
941 assert_eq!(code.value_type(), StatusCodeValueType::Calculated);
942 let code = code.set_value_type(StatusCodeValueType::Interpolated);
943 assert_eq!(code.value_type(), StatusCodeValueType::Interpolated);
944
945 assert_eq!(StatusCodeSeverity::Uncertain, code.severity());
946 assert!(code.structure_changed());
947 assert!(code.semantics_changed());
948 assert_eq!(code.info_type(), StatusCodeInfoType::DataValue);
949 assert_eq!(
950 code.sub_code(),
951 SubStatusCode::UncertainNotAllNodesAvailable
952 );
953 assert!(code.overflow());
954 assert!(code.multi_value());
955 assert!(code.extra_data());
956 assert!(code.partial());
957 assert_eq!(code.value_type(), StatusCodeValueType::Interpolated);
958
959 code.validate().unwrap();
960 }
961}