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