Skip to main content

opcua_types/
data_value.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2022 Adam Lock
4
5//! Contains the implementation of `DataValue`.
6
7use std::io::{Read, Write};
8
9use crate::{
10    byte_string::ByteString, date_time::*, encoding::*, guid::Guid, localized_text::LocalizedText,
11    node_id::NodeId, qualified_name::QualifiedName, service_types::TimestampsToReturn,
12    status_codes::StatusCode, string::UAString, variant::Variant,
13};
14
15bitflags! {
16    struct DataValueFlags: u8 {
17        /// False if the Value is Null.
18        const HAS_VALUE = 0x1;
19        /// False if the StatusCode is Good.
20        const HAS_STATUS = 0x2;
21        /// False if the Source Timestamp is DateTime.MinValue.
22        const HAS_SOURCE_TIMESTAMP = 0x4;
23        /// False if the Server Timestamp is DateTime.MinValue.
24        const HAS_SERVER_TIMESTAMP = 0x8;
25        /// False if the Source Picoseconds is 0.
26        const HAS_SOURCE_PICOSECONDS = 0x10;
27        /// False if the Server Picoseconds is 0.
28        const HAS_SERVER_PICOSECONDS = 0x20;
29    }
30}
31
32/// A data value is a value of a variable in the OPC UA server and contains information about its
33/// value, status and change timestamps.
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35pub struct DataValue {
36    /// The value. BaseDataType
37    /// Not present if the Value bit in the EncodingMask is False.
38    pub value: Option<Variant>,
39    /// The status associated with the value.
40    /// Not present if the StatusCode bit in the EncodingMask is False
41    pub status: Option<StatusCode>,
42    /// The source timestamp associated with the value.
43    /// Not present if the SourceTimestamp bit in the EncodingMask is False.
44    pub source_timestamp: Option<DateTime>,
45    /// The number of 10 picosecond intervals for the SourceTimestamp.
46    /// Not present if the SourcePicoSeconds bit in the EncodingMask is False.
47    /// If the source timestamp is missing the picoseconds are ignored.
48    pub source_picoseconds: Option<i16>,
49    /// The Server timestamp associated with the value.
50    /// Not present if the ServerTimestamp bit in the EncodingMask is False.
51    pub server_timestamp: Option<DateTime>,
52    /// The number of 10 picosecond intervals for the ServerTimestamp.
53    /// Not present if the ServerPicoSeconds bit in the EncodingMask is False.
54    /// If the Server timestamp is missing the picoseconds are ignored.
55    pub server_picoseconds: Option<i16>,
56}
57
58impl BinaryEncoder<DataValue> for DataValue {
59    fn byte_len(&self) -> usize {
60        let mut size = 1;
61        let encoding_mask = self.encoding_mask();
62        if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
63            size += self.value.as_ref().unwrap().byte_len();
64        }
65        if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
66            size += self.status.as_ref().unwrap().byte_len();
67        }
68        if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
69            size += self.source_timestamp.as_ref().unwrap().byte_len();
70            if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
71                size += self.source_picoseconds.as_ref().unwrap().byte_len();
72            }
73        }
74        if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
75            size += self.server_timestamp.as_ref().unwrap().byte_len();
76            if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
77                size += self.server_picoseconds.as_ref().unwrap().byte_len();
78            }
79        }
80        size
81    }
82
83    fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
84        let mut size = 0;
85
86        let encoding_mask = self.encoding_mask();
87        size += encoding_mask.bits.encode(stream)?;
88
89        if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
90            size += self.value.as_ref().unwrap().encode(stream)?;
91        }
92        if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
93            size += self.status.as_ref().unwrap().bits().encode(stream)?;
94        }
95        if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
96            size += self.source_timestamp.as_ref().unwrap().encode(stream)?;
97            if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
98                size += self.source_picoseconds.as_ref().unwrap().encode(stream)?;
99            }
100        }
101        if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
102            size += self.server_timestamp.as_ref().unwrap().encode(stream)?;
103            if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
104                size += self.server_picoseconds.as_ref().unwrap().encode(stream)?;
105            }
106        }
107        Ok(size)
108    }
109
110    fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
111        let encoding_mask =
112            DataValueFlags::from_bits_truncate(u8::decode(stream, decoding_options)?);
113
114        // Value
115        let value = if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
116            Some(Variant::decode(stream, decoding_options)?)
117        } else {
118            None
119        };
120        // Status
121        let status = if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
122            let status = StatusCode::from_bits_truncate(u32::decode(stream, decoding_options)?);
123            Some(status)
124        } else {
125            None
126        };
127        // Source timestamp
128        let source_timestamp = if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
129            // The source timestamp should never be adjusted, not even when ignoring clock skew
130            let decoding_options = DecodingOptions {
131                client_offset: chrono::Duration::zero(),
132                ..*decoding_options
133            };
134            Some(DateTime::decode(stream, &decoding_options)?)
135        } else {
136            None
137        };
138        let source_picoseconds = if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
139            Some(i16::decode(stream, decoding_options)?)
140        } else {
141            None
142        };
143        // Server timestamp
144        let server_timestamp = if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
145            Some(DateTime::decode(stream, decoding_options)?)
146        } else {
147            None
148        };
149        let server_picoseconds = if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
150            Some(i16::decode(stream, decoding_options)?)
151        } else {
152            None
153        };
154        // Pico second values are discarded if associated timestamp is not supplied
155        Ok(DataValue {
156            value,
157            status,
158            source_picoseconds: if source_timestamp.is_some() {
159                source_picoseconds
160            } else {
161                None
162            },
163            source_timestamp,
164            server_picoseconds: if server_timestamp.is_some() {
165                server_picoseconds
166            } else {
167                None
168            },
169            server_timestamp,
170        })
171    }
172}
173
174// It would be nice if everything from here to the ... below could be condensed into a single
175// trait impl somehow because it's more or less duplicating all the code in Variant.
176
177impl From<bool> for DataValue {
178    fn from(v: bool) -> Self {
179        Self::from(Variant::from(v))
180    }
181}
182
183impl From<u8> for DataValue {
184    fn from(v: u8) -> Self {
185        Self::from(Variant::from(v))
186    }
187}
188
189impl From<i8> for DataValue {
190    fn from(v: i8) -> Self {
191        Self::from(Variant::from(v))
192    }
193}
194
195impl From<i16> for DataValue {
196    fn from(v: i16) -> Self {
197        Self::from(Variant::from(v))
198    }
199}
200
201impl From<u16> for DataValue {
202    fn from(v: u16) -> Self {
203        Self::from(Variant::from(v))
204    }
205}
206
207impl From<i32> for DataValue {
208    fn from(v: i32) -> Self {
209        Self::from(Variant::from(v))
210    }
211}
212
213impl From<u32> for DataValue {
214    fn from(v: u32) -> Self {
215        Self::from(Variant::from(v))
216    }
217}
218
219impl From<i64> for DataValue {
220    fn from(v: i64) -> Self {
221        Self::from(Variant::from(v))
222    }
223}
224
225impl From<u64> for DataValue {
226    fn from(v: u64) -> Self {
227        Self::from(Variant::from(v))
228    }
229}
230
231impl From<f32> for DataValue {
232    fn from(v: f32) -> Self {
233        Self::from(Variant::from(v))
234    }
235}
236
237impl From<f64> for DataValue {
238    fn from(v: f64) -> Self {
239        Self::from(Variant::from(v))
240    }
241}
242
243impl<'a> From<&'a str> for DataValue {
244    fn from(v: &'a str) -> Self {
245        Self::from(Variant::from(v))
246    }
247}
248
249impl From<String> for DataValue {
250    fn from(v: String) -> Self {
251        Self::from(Variant::from(v))
252    }
253}
254
255impl From<UAString> for DataValue {
256    fn from(v: UAString) -> Self {
257        Self::from(Variant::from(v))
258    }
259}
260
261impl From<DateTime> for DataValue {
262    fn from(v: DateTime) -> Self {
263        Self::from(Variant::from(v))
264    }
265}
266
267impl From<Guid> for DataValue {
268    fn from(v: Guid) -> Self {
269        Self::from(Variant::from(v))
270    }
271}
272
273impl From<StatusCode> for DataValue {
274    fn from(v: StatusCode) -> Self {
275        Self::from(Variant::from(v))
276    }
277}
278
279impl From<ByteString> for DataValue {
280    fn from(v: ByteString) -> Self {
281        Self::from(Variant::from(v))
282    }
283}
284
285impl From<QualifiedName> for DataValue {
286    fn from(v: QualifiedName) -> Self {
287        Self::from(Variant::from(v))
288    }
289}
290
291impl From<LocalizedText> for DataValue {
292    fn from(v: LocalizedText) -> Self {
293        Self::from(Variant::from(v))
294    }
295}
296
297impl From<NodeId> for DataValue {
298    fn from(v: NodeId) -> Self {
299        Self::from(Variant::from(v))
300    }
301}
302//... (see above)
303
304impl From<Variant> for DataValue {
305    fn from(v: Variant) -> Self {
306        DataValue::value_only(v)
307    }
308}
309
310impl From<(Variant, StatusCode)> for DataValue {
311    fn from(v: (Variant, StatusCode)) -> Self {
312        DataValue {
313            value: Some(v.0),
314            status: Some(v.1),
315            source_timestamp: None,
316            source_picoseconds: None,
317            server_timestamp: None,
318            server_picoseconds: None,
319        }
320    }
321}
322
323/*
324impl<'a> From<(Variant, &'a DateTime)> for DataValue {
325    fn from(v: (Variant, &'a DateTime)) -> Self {
326        DataValue {
327            value: Some(v.0),
328            status: Some(StatusCode::Good),
329            source_timestamp: Some(v.1.clone()),
330            source_picoseconds: Some(0),
331            server_timestamp: Some(v.1.clone()),
332            server_picoseconds: Some(0),
333        }
334    }
335}
336
337impl<'a> From<(Variant, &'a DateTime, &'a DateTime)> for DataValue {
338    fn from(v: (Variant, &'a DateTime, &'a DateTime)) -> Self {
339        // First date is source time, second is server time
340        DataValue {
341            value: Some(v.0),
342            status: Some(StatusCode::Good),
343            source_timestamp: Some(v.1.clone()),
344            source_picoseconds: Some(0),
345            server_timestamp: Some(v.2.clone()),
346            server_picoseconds: Some(0),
347        }
348    }
349}
350*/
351
352impl Default for DataValue {
353    fn default() -> Self {
354        Self::null()
355    }
356}
357
358impl DataValue {
359    /// Creates a `DataValue` from the supplied value with nothing else.
360    pub fn value_only<V>(value: V) -> DataValue
361    where
362        V: Into<Variant>,
363    {
364        DataValue {
365            value: Some(value.into()),
366            status: None,
367            source_timestamp: None,
368            source_picoseconds: None,
369            server_timestamp: None,
370            server_picoseconds: None,
371        }
372    }
373
374    /// Creates a `DataValue` from the supplied value AND a timestamp for now. If you are passing a value to the Attribute::Write service
375    /// on a server from a server, you may consider this from the specification:
376    ///
377    /// _If the SourceTimestamp or the ServerTimestamp is specified, the Server shall use these values.
378    /// The Server returns a Bad_WriteNotSupported error if it does not support writing of timestamps_
379    ///
380    /// In which case, use the `value_only()` constructor, or make explicit which fields you pass.
381    pub fn new_now<V>(value: V) -> DataValue
382    where
383        V: Into<Variant>,
384    {
385        let now = DateTime::now();
386        DataValue {
387            value: Some(value.into()),
388            status: Some(StatusCode::Good),
389            source_timestamp: Some(now),
390            source_picoseconds: Some(0),
391            server_timestamp: Some(now),
392            server_picoseconds: Some(0),
393        }
394    }
395
396    /// Creates an empty DataValue
397    pub fn null() -> DataValue {
398        DataValue {
399            value: None,
400            status: None,
401            source_timestamp: None,
402            source_picoseconds: None,
403            server_timestamp: None,
404            server_picoseconds: None,
405        }
406    }
407
408    /// Sets the value of the data value, updating the timestamps at the same point
409    pub fn set_value<V>(
410        &mut self,
411        value: V,
412        source_timestamp: &DateTime,
413        server_timestamp: &DateTime,
414    ) where
415        V: Into<Variant>,
416    {
417        self.value = Some(value.into());
418        self.source_timestamp = Some(*source_timestamp);
419        self.source_picoseconds = Some(0);
420        self.server_timestamp = Some(*server_timestamp);
421        self.server_picoseconds = Some(0);
422    }
423
424    /// Sets the timestamps of the data value based on supplied timestamps to return
425    pub fn set_timestamps(
426        &mut self,
427        timestamps_to_return: TimestampsToReturn,
428        source_timestamp: DateTime,
429        server_timestamp: DateTime,
430    ) {
431        match timestamps_to_return {
432            TimestampsToReturn::Source => {
433                self.source_timestamp = Some(source_timestamp);
434                self.source_picoseconds = Some(0);
435                self.server_timestamp = None;
436                self.server_picoseconds = None;
437            }
438            TimestampsToReturn::Server => {
439                self.source_timestamp = None;
440                self.source_picoseconds = None;
441                self.server_timestamp = Some(server_timestamp);
442                self.server_picoseconds = Some(0);
443            }
444            TimestampsToReturn::Both => {
445                self.source_timestamp = Some(source_timestamp);
446                self.source_picoseconds = Some(0);
447                self.server_timestamp = Some(server_timestamp);
448                self.server_picoseconds = Some(0);
449            }
450            TimestampsToReturn::Neither => {
451                self.source_timestamp = None;
452                self.source_picoseconds = None;
453                self.server_timestamp = None;
454                self.server_picoseconds = None;
455            }
456            _ => {}
457        }
458    }
459
460    /// Returns the status code or Good if there is no code on the value
461    pub fn status(&self) -> StatusCode {
462        self.status.map_or(StatusCode::Good, |s| s)
463    }
464
465    /// Test if the value held by this data value is known to be good
466    /// Anything other than Good is assumed to be invalid.
467    pub fn is_valid(&self) -> bool {
468        self.status().status().is_good()
469    }
470
471    fn encoding_mask(&self) -> DataValueFlags {
472        let mut encoding_mask = DataValueFlags::empty();
473        if self.value.is_some() {
474            encoding_mask |= DataValueFlags::HAS_VALUE;
475        }
476        if self.status.is_some() {
477            encoding_mask |= DataValueFlags::HAS_STATUS;
478        }
479        if self.source_timestamp.is_some() {
480            encoding_mask |= DataValueFlags::HAS_SOURCE_TIMESTAMP;
481            if self.source_picoseconds.is_some() {
482                encoding_mask |= DataValueFlags::HAS_SOURCE_PICOSECONDS;
483            }
484        }
485        if self.server_timestamp.is_some() {
486            encoding_mask |= DataValueFlags::HAS_SERVER_TIMESTAMP;
487            if self.server_picoseconds.is_some() {
488                encoding_mask |= DataValueFlags::HAS_SERVER_PICOSECONDS;
489            }
490        }
491        encoding_mask
492    }
493}