Skip to main content

zencan_common/
objects.rs

1//! Object Definitions
2//!
3
4/// A container for the address of a subobject
5#[derive(Clone, Copy, Debug, PartialEq)]
6pub struct ObjectId {
7    /// Object index
8    pub index: u16,
9    /// Sub index
10    pub sub: u8,
11}
12
13/// Object Code value
14///
15/// Defines the type of an object or sub object
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
17#[repr(u8)]
18pub enum ObjectCode {
19    /// An empty object
20    ///
21    /// Zencan does not support Null objects
22    Null = 0,
23    /// A large chunk of data
24    ///
25    /// Zencan does not support Domain Object; it only supports domain sub-objects.
26    Domain = 2,
27    /// Unused
28    DefType = 5,
29    /// Unused
30    DefStruct = 6,
31    /// An object which has a single sub object
32    #[default]
33    Var = 7,
34    /// An array of sub-objects all with the same data type
35    Array = 8,
36    /// A collection of sub-objects with varying types
37    Record = 9,
38}
39
40impl TryFrom<u8> for ObjectCode {
41    type Error = ();
42
43    fn try_from(value: u8) -> Result<Self, Self::Error> {
44        match value {
45            0 => Ok(ObjectCode::Null),
46            2 => Ok(ObjectCode::Domain),
47            5 => Ok(ObjectCode::DefType),
48            6 => Ok(ObjectCode::DefStruct),
49            7 => Ok(ObjectCode::Var),
50            8 => Ok(ObjectCode::Array),
51            9 => Ok(ObjectCode::Record),
52            _ => Err(()),
53        }
54    }
55}
56
57/// Access type enum
58#[derive(Copy, Clone, Debug, Default, PartialEq)]
59pub enum AccessType {
60    /// Read-only
61    #[default]
62    Ro,
63    /// Write-only
64    Wo,
65    /// Read-write
66    Rw,
67    /// Read-only, and also will never be changed, even internally by the device
68    Const,
69}
70
71impl AccessType {
72    /// Returns true if an object with this access type can be read
73    pub fn is_readable(&self) -> bool {
74        matches!(self, AccessType::Ro | AccessType::Rw | AccessType::Const)
75    }
76
77    /// Returns true if an object with this access type can be written
78    pub fn is_writable(&self) -> bool {
79        matches!(self, AccessType::Rw | AccessType::Wo)
80    }
81}
82
83/// Possible PDO mapping values for an object
84#[derive(Copy, Clone, Debug, Default, PartialEq)]
85#[cfg_attr(
86    feature = "std",
87    derive(serde::Deserialize),
88    serde(rename_all = "lowercase")
89)]
90pub enum PdoMappable {
91    /// Object cannot be mapped to PDOs
92    #[default]
93    None,
94    /// Object can be mapped to RPDOs only
95    Rpdo,
96    /// Object can be mapped to TPDOs only
97    Tpdo,
98    /// Object can be mapped to both RPDOs and TPDOs
99    Both,
100}
101
102impl PdoMappable {
103    /// Can be mapped to a TPDO
104    pub fn supports_tpdo(&self) -> bool {
105        matches!(self, PdoMappable::Tpdo | PdoMappable::Both)
106    }
107
108    /// Can be mapped to an RPDO
109    pub fn supports_rpdo(&self) -> bool {
110        matches!(self, PdoMappable::Rpdo | PdoMappable::Both)
111    }
112}
113
114/// Indicate the type of data stored in an object
115#[derive(Copy, Clone, Debug, Default, PartialEq)]
116#[repr(u16)]
117pub enum DataType {
118    /// A true false value, encoded as a single byte, with 0 for false and 1 for true
119    Boolean = 1,
120    #[default]
121    /// A signed 8-bit integer
122    Int8 = 2,
123    /// A signed 16-bit integer
124    Int16 = 3,
125    /// A signed 32-bit integer
126    Int32 = 4,
127    /// An unsigned 8-bit integer
128    UInt8 = 5,
129    /// An unsigned 16-bit integer
130    UInt16 = 6,
131    /// An unsigned 32-bit integer
132    UInt32 = 7,
133    /// A 32-bit floating point value
134    Real32 = 0x8,
135    /// An ASCII/utf-8 string
136    VisibleString = 0x9,
137    /// A byte string
138    OctetString = 0xa,
139    /// A unicode string
140    UnicodeString = 0xb,
141    /// Currently Unimplemented
142    TimeOfDay = 0xc,
143    /// Currently Unimplemented
144    TimeDifference = 0xd,
145    /// An arbitrary byte access type for e.g. data streams, or large chunks of
146    /// data. Size is typically not known at build time.
147    Domain = 0xf,
148    /// A signed 24-bit integer
149    Int24 = 0x10,
150    /// A 64-bit floating point value
151    Real64 = 0x11,
152    /// A signed 64-bit integer
153    Int64 = 0x15,
154    /// An unsigned 24-bit integer
155    UInt24 = 0x16,
156    /// An unsigned 64-bit integer
157    UInt64 = 0x1b,
158    /// A contained for an unrecognized data type value
159    Other(u16),
160}
161
162impl From<u16> for DataType {
163    fn from(value: u16) -> Self {
164        use DataType::*;
165        match value {
166            1 => Boolean,
167            2 => Int8,
168            3 => Int16,
169            4 => Int32,
170            5 => UInt8,
171            6 => UInt16,
172            7 => UInt32,
173            8 => Real32,
174            9 => VisibleString,
175            0xa => OctetString,
176            0xb => UnicodeString,
177            0xf => Domain,
178            0x10 => Int24,
179            0x11 => Real64,
180            0x15 => Int64,
181            0x16 => UInt24,
182            0x1b => UInt64,
183            _ => Other(value),
184        }
185    }
186}
187
188impl DataType {
189    /// Returns true if data type is one of the string types
190    pub fn is_str(&self) -> bool {
191        matches!(
192            self,
193            Self::VisibleString | Self::OctetString | Self::UnicodeString
194        )
195    }
196}
197
198/// Information about a sub object
199#[derive(Clone, Copy, Debug, Default, PartialEq)]
200pub struct SubInfo {
201    /// The size (or max size) of this sub object, in bytes
202    pub size: usize,
203    /// The data type of this sub object
204    pub data_type: DataType,
205    /// Indicates what accesses (i.e. read/write) are allowed on this sub object
206    pub access_type: AccessType,
207    /// Indicates whether this sub may be mapped to PDOs
208    pub pdo_mapping: PdoMappable,
209    /// Indicates whether this sub should be persisted when data is saved
210    pub persist: bool,
211}
212
213impl SubInfo {
214    /// A shorthand value for sub0 on record and array objects
215    pub const MAX_SUB_NUMBER: SubInfo = SubInfo {
216        size: 1,
217        data_type: DataType::UInt8,
218        access_type: AccessType::Const,
219        pdo_mapping: PdoMappable::None,
220        persist: false,
221    };
222
223    /// Convenience function for creating a new sub-info by type
224    pub const fn new_u32() -> Self {
225        Self {
226            size: 4,
227            data_type: DataType::UInt32,
228            access_type: AccessType::Ro,
229            pdo_mapping: PdoMappable::None,
230            persist: false,
231        }
232    }
233
234    /// Convenience function for creating a new sub-info by type
235    pub const fn new_u24() -> Self {
236        Self {
237            size: 3,
238            data_type: DataType::UInt24,
239            access_type: AccessType::Ro,
240            pdo_mapping: PdoMappable::None,
241            persist: false,
242        }
243    }
244
245    /// Convenience function for creating a new sub-info by type
246    pub const fn new_u16() -> Self {
247        Self {
248            size: 2,
249            data_type: DataType::UInt16,
250            access_type: AccessType::Ro,
251            pdo_mapping: PdoMappable::None,
252            persist: false,
253        }
254    }
255
256    /// Convenience function for creating a new sub-info by type
257    pub const fn new_u8() -> Self {
258        Self {
259            size: 1,
260            data_type: DataType::UInt8,
261            access_type: AccessType::Ro,
262            pdo_mapping: PdoMappable::None,
263            persist: false,
264        }
265    }
266
267    /// Convenience function for creating a new sub-info by type
268    pub const fn new_i32() -> Self {
269        Self {
270            size: 4,
271            data_type: DataType::Int32,
272            access_type: AccessType::Ro,
273            pdo_mapping: PdoMappable::None,
274            persist: false,
275        }
276    }
277
278    /// Convenience function for creating a new sub-info by type
279    pub const fn new_i24() -> Self {
280        Self {
281            size: 3,
282            data_type: DataType::Int24,
283            access_type: AccessType::Ro,
284            pdo_mapping: PdoMappable::None,
285            persist: false,
286        }
287    }
288
289    /// Convenience function for creating a new sub-info by type
290    pub const fn new_i16() -> Self {
291        Self {
292            size: 2,
293            data_type: DataType::Int16,
294            access_type: AccessType::Ro,
295            pdo_mapping: PdoMappable::None,
296            persist: false,
297        }
298    }
299
300    /// Convenience function for creating a new sub-info by type
301    pub const fn new_i8() -> Self {
302        Self {
303            size: 1,
304            data_type: DataType::Int8,
305            access_type: AccessType::Ro,
306            pdo_mapping: PdoMappable::None,
307            persist: false,
308        }
309    }
310
311    /// Convenience function for creating a new sub-info by type
312    pub const fn new_f32() -> Self {
313        Self {
314            size: 4,
315            data_type: DataType::Real32,
316            access_type: AccessType::Ro,
317            pdo_mapping: PdoMappable::None,
318            persist: false,
319        }
320    }
321
322    /// Convenience function for creating a new sub-info by type
323    pub const fn new_visibile_str(size: usize) -> Self {
324        Self {
325            size,
326            data_type: DataType::VisibleString,
327            access_type: AccessType::Ro,
328            pdo_mapping: PdoMappable::None,
329            persist: false,
330        }
331    }
332
333    /// Convenience function to set the access_type to read-only
334    pub const fn ro_access(mut self) -> Self {
335        self.access_type = AccessType::Ro;
336        self
337    }
338
339    /// Convenience function to set the access_type to read-write
340    pub const fn rw_access(mut self) -> Self {
341        self.access_type = AccessType::Rw;
342        self
343    }
344
345    /// Convenience function to set the access_type to const
346    pub const fn const_access(mut self) -> Self {
347        self.access_type = AccessType::Const;
348        self
349    }
350
351    /// Convenience function to set the access_type to write-only
352    pub const fn wo_access(mut self) -> Self {
353        self.access_type = AccessType::Wo;
354        self
355    }
356
357    /// Convenience function to set the persist value
358    pub const fn persist(mut self, value: bool) -> Self {
359        self.persist = value;
360        self
361    }
362}