mabi_opcua/types/
status_code.rs1use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
28#[repr(transparent)]
29pub struct StatusCode(u32);
30
31impl StatusCode {
32 pub const GOOD: Self = Self(0x00000000);
38 pub const GOOD_LOCAL_OVERRIDE: Self = Self(0x00960000);
40 pub const GOOD_CLAMPED: Self = Self(0x00300000);
42 pub const GOOD_NO_DATA: Self = Self(0x00A50000);
44 pub const GOOD_MORE_DATA: Self = Self(0x00A60000);
46 pub const GOOD_SUBSCRIPTION_TRANSFERRED: Self = Self(0x002D0000);
48 pub const GOOD_REFRESH_IN_PROGRESS: Self = Self(0x006A0000);
50 pub const GOOD_REFRESH_FINISHED: Self = Self(0x006B0000);
52
53 pub const UNCERTAIN: Self = Self(0x40000000);
59 pub const UNCERTAIN_LAST_USABLE_VALUE: Self = Self(0x408F0000);
61 pub const UNCERTAIN_SENSOR_NOT_ACCURATE: Self = Self(0x40930000);
63 pub const UNCERTAIN_SUB_NORMAL: Self = Self(0x40A40000);
65 pub const UNCERTAIN_INITIAL_VALUE: Self = Self(0x40920000);
67
68 pub const BAD_UNEXPECTED_ERROR: Self = Self(0x80010000);
74 pub const BAD_INTERNAL_ERROR: Self = Self(0x80020000);
76 pub const BAD_OUT_OF_MEMORY: Self = Self(0x80030000);
78 pub const BAD_INVALID_ARGUMENT: Self = Self(0x80AB0000);
80 pub const BAD_RESOURCE_UNAVAILABLE: Self = Self(0x80040000);
82 pub const BAD_COMMUNICATION_ERROR: Self = Self(0x80050000);
84 pub const BAD_ENCODING_ERROR: Self = Self(0x80060000);
86 pub const BAD_DECODING_ERROR: Self = Self(0x80070000);
88 pub const BAD_TIMEOUT: Self = Self(0x800A0000);
90 pub const BAD_SERVICE_UNSUPPORTED: Self = Self(0x800B0000);
92 pub const BAD_SHUTDOWN: Self = Self(0x800C0000);
94 pub const BAD_SERVER_NOT_CONNECTED: Self = Self(0x800D0000);
96 pub const BAD_SERVER_HALTED: Self = Self(0x800E0000);
98 pub const BAD_NOTHING_TO_DO: Self = Self(0x800F0000);
100 pub const BAD_TOO_MANY_OPERATIONS: Self = Self(0x80100000);
102 pub const BAD_DATA_TYPE_MISMATCH: Self = Self(0x80490000);
104 pub const BAD_NODE_ID_UNKNOWN: Self = Self(0x80340000);
106 pub const BAD_NODE_ID_INVALID: Self = Self(0x80330000);
108 pub const BAD_ATTRIBUTE_ID_INVALID: Self = Self(0x80350000);
110 pub const BAD_INDEX_RANGE_INVALID: Self = Self(0x80360000);
112 pub const BAD_INDEX_RANGE_NO_DATA: Self = Self(0x80370000);
114 pub const BAD_DATA_ENCODING_INVALID: Self = Self(0x80380000);
116 pub const BAD_DATA_ENCODING_UNSUPPORTED: Self = Self(0x80390000);
118 pub const BAD_NOT_READABLE: Self = Self(0x803A0000);
120 pub const BAD_NOT_WRITABLE: Self = Self(0x803B0000);
122 pub const BAD_OUT_OF_RANGE: Self = Self(0x803C0000);
124 pub const BAD_NOT_SUPPORTED: Self = Self(0x803D0000);
126 pub const BAD_NOT_FOUND: Self = Self(0x803E0000);
128 pub const BAD_OBJECT_DELETED: Self = Self(0x803F0000);
130 pub const BAD_NOT_IMPLEMENTED: Self = Self(0x80400000);
132 pub const BAD_MONITORING_MODE_INVALID: Self = Self(0x80410000);
134 pub const BAD_MONITORED_ITEM_ID_INVALID: Self = Self(0x80420000);
136 pub const BAD_MONITORED_ITEM_FILTER_INVALID: Self = Self(0x80430000);
138 pub const BAD_MONITORED_ITEM_FILTER_UNSUPPORTED: Self = Self(0x80440000);
140 pub const BAD_FILTER_NOT_ALLOWED: Self = Self(0x80450000);
142 pub const BAD_STRUCTURE_MISSING: Self = Self(0x80460000);
144 pub const BAD_EVENT_FILTER_INVALID: Self = Self(0x80470000);
146 pub const BAD_CONTENT_FILTER_INVALID: Self = Self(0x80480000);
148 pub const BAD_SUBSCRIPTION_ID_INVALID: Self = Self(0x80280000);
150 pub const BAD_SEQUENCE_NUMBER_UNKNOWN: Self = Self(0x80290000);
152 pub const BAD_MESSAGE_NOT_AVAILABLE: Self = Self(0x802A0000);
154 pub const BAD_INSUFFICIENT_CLIENT_PROFILE: Self = Self(0x802B0000);
156 pub const BAD_SESSION_ID_INVALID: Self = Self(0x80250000);
158 pub const BAD_SESSION_CLOSED: Self = Self(0x80260000);
160 pub const BAD_SESSION_NOT_ACTIVATED: Self = Self(0x80270000);
162 pub const BAD_SECURE_CHANNEL_ID_INVALID: Self = Self(0x80220000);
164 pub const BAD_SECURE_CHANNEL_CLOSED: Self = Self(0x80860000);
166 pub const BAD_REQUEST_TIMEOUT: Self = Self(0x80A10000);
168 pub const BAD_SECURITY_CHECKS_FAILED: Self = Self(0x80130000);
170 pub const BAD_USER_ACCESS_DENIED: Self = Self(0x801F0000);
172 pub const BAD_IDENTITY_TOKEN_INVALID: Self = Self(0x80200000);
174 pub const BAD_IDENTITY_TOKEN_REJECTED: Self = Self(0x80210000);
176 pub const BAD_NO_MATCH: Self = Self(0x806F0000);
178 pub const BAD_BROWSE_DIRECTION_INVALID: Self = Self(0x804D0000);
180 pub const BAD_NODE_NOT_BROWSABLE: Self = Self(0x804E0000);
182 pub const BAD_REFERENCE_TYPE_ID_INVALID: Self = Self(0x804C0000);
184 pub const BAD_CONTINUATION_POINT_INVALID: Self = Self(0x804F0000);
186 pub const BAD_NO_CONTINUATION_POINTS: Self = Self(0x80500000);
188 pub const BAD_TOO_MANY_SUBSCRIPTIONS: Self = Self(0x80770000);
190 pub const BAD_TOO_MANY_MONITORED_ITEMS: Self = Self(0x80780000);
192 pub const BAD_WRITE_NOT_SUPPORTED: Self = Self(0x80730000);
194 pub const BAD_HISTORY_OPERATION_INVALID: Self = Self(0x80710000);
196 pub const BAD_HISTORY_OPERATION_UNSUPPORTED: Self = Self(0x80720000);
198
199 pub const fn from_raw(value: u32) -> Self {
205 Self(value)
206 }
207
208 pub const fn raw(&self) -> u32 {
210 self.0
211 }
212
213 pub const fn is_good(&self) -> bool {
215 self.severity() == 0
216 }
217
218 pub const fn is_uncertain(&self) -> bool {
220 self.severity() == 1
221 }
222
223 pub const fn is_bad(&self) -> bool {
225 self.severity() >= 2
226 }
227
228 pub const fn severity(&self) -> u8 {
230 ((self.0 >> 30) & 0x03) as u8
231 }
232
233 pub const fn sub_code(&self) -> u16 {
235 ((self.0 >> 16) & 0x3FFF) as u16
236 }
237
238 pub const fn info_bits(&self) -> u16 {
240 (self.0 & 0xFFFF) as u16
241 }
242
243 pub fn description(&self) -> &'static str {
245 match *self {
246 Self::GOOD => "Good",
247 Self::GOOD_LOCAL_OVERRIDE => "Good (local override)",
248 Self::GOOD_CLAMPED => "Good (clamped)",
249 Self::GOOD_NO_DATA => "Good (no data)",
250 Self::GOOD_MORE_DATA => "Good (more data available)",
251 Self::UNCERTAIN => "Uncertain",
252 Self::UNCERTAIN_LAST_USABLE_VALUE => "Uncertain (last usable value)",
253 Self::UNCERTAIN_SENSOR_NOT_ACCURATE => "Uncertain (sensor not accurate)",
254 Self::UNCERTAIN_INITIAL_VALUE => "Uncertain (initial value)",
255 Self::BAD_UNEXPECTED_ERROR => "Bad (unexpected error)",
256 Self::BAD_INTERNAL_ERROR => "Bad (internal error)",
257 Self::BAD_OUT_OF_MEMORY => "Bad (out of memory)",
258 Self::BAD_INVALID_ARGUMENT => "Bad (invalid argument)",
259 Self::BAD_TIMEOUT => "Bad (timeout)",
260 Self::BAD_NODE_ID_UNKNOWN => "Bad (node ID unknown)",
261 Self::BAD_NODE_ID_INVALID => "Bad (node ID invalid)",
262 Self::BAD_ATTRIBUTE_ID_INVALID => "Bad (attribute ID invalid)",
263 Self::BAD_NOT_READABLE => "Bad (not readable)",
264 Self::BAD_NOT_WRITABLE => "Bad (not writable)",
265 Self::BAD_NOT_FOUND => "Bad (not found)",
266 Self::BAD_NOT_SUPPORTED => "Bad (not supported)",
267 Self::BAD_NOT_IMPLEMENTED => "Bad (not implemented)",
268 Self::BAD_SUBSCRIPTION_ID_INVALID => "Bad (subscription ID invalid)",
269 Self::BAD_SESSION_ID_INVALID => "Bad (session ID invalid)",
270 Self::BAD_SESSION_CLOSED => "Bad (session closed)",
271 Self::BAD_TOO_MANY_SUBSCRIPTIONS => "Bad (too many subscriptions)",
272 Self::BAD_TOO_MANY_MONITORED_ITEMS => "Bad (too many monitored items)",
273 _ => "Unknown status code",
274 }
275 }
276}
277
278impl Default for StatusCode {
279 fn default() -> Self {
280 Self::GOOD
281 }
282}
283
284impl fmt::Display for StatusCode {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 write!(f, "{} (0x{:08X})", self.description(), self.0)
287 }
288}
289
290impl From<u32> for StatusCode {
291 fn from(value: u32) -> Self {
292 Self(value)
293 }
294}
295
296impl From<StatusCode> for u32 {
297 fn from(status: StatusCode) -> Self {
298 status.0
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305
306 #[test]
307 fn test_good_status() {
308 assert!(StatusCode::GOOD.is_good());
309 assert!(!StatusCode::GOOD.is_uncertain());
310 assert!(!StatusCode::GOOD.is_bad());
311 assert_eq!(StatusCode::GOOD.severity(), 0);
312 }
313
314 #[test]
315 fn test_uncertain_status() {
316 assert!(!StatusCode::UNCERTAIN.is_good());
317 assert!(StatusCode::UNCERTAIN.is_uncertain());
318 assert!(!StatusCode::UNCERTAIN.is_bad());
319 assert_eq!(StatusCode::UNCERTAIN.severity(), 1);
320 }
321
322 #[test]
323 fn test_bad_status() {
324 assert!(!StatusCode::BAD_UNEXPECTED_ERROR.is_good());
325 assert!(!StatusCode::BAD_UNEXPECTED_ERROR.is_uncertain());
326 assert!(StatusCode::BAD_UNEXPECTED_ERROR.is_bad());
327 assert_eq!(StatusCode::BAD_UNEXPECTED_ERROR.severity(), 2);
328 }
329
330 #[test]
331 fn test_status_code_display() {
332 let status = StatusCode::GOOD;
333 assert!(status.to_string().contains("Good"));
334
335 let status = StatusCode::BAD_NODE_ID_UNKNOWN;
336 assert!(status.to_string().contains("node ID unknown"));
337 }
338}