zencan_common/
node_id.rs

1//! Types for representing node IDs
2//!
3
4/// An enum representing the node ID of a CANopen node. The node ID must be between 1 and 127 for
5/// configured devices, with the special value of 255 used to represent an unconfigured device.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub enum NodeId {
9    /// A special node ID indicating the node is not configured (255)
10    Unconfigured,
11    /// A valid node ID for a configured node
12    Configured(ConfiguredNodeId),
13}
14
15/// A newtype on u8 to enforce valid node ID (1-127)
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub struct ConfiguredNodeId(u8);
19impl ConfiguredNodeId {
20    /// Try to create a new ConfiguredId
21    ///
22    /// It will fail if value is invalid (i.e. <1 or >127)
23    pub const fn new(value: u8) -> Result<Self, InvalidNodeIdError> {
24        if (value > 0 && value < 128) || value == 255 {
25            Ok(ConfiguredNodeId(value))
26        } else {
27            Err(InvalidNodeIdError)
28        }
29    }
30
31    /// Get the raw node ID as a u8
32    pub fn raw(&self) -> u8 {
33        self.0
34    }
35}
36
37impl core::fmt::Display for ConfiguredNodeId {
38    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
39        write!(f, "{}", self.0)
40    }
41}
42
43impl From<ConfiguredNodeId> for u8 {
44    fn from(value: ConfiguredNodeId) -> Self {
45        value.raw()
46    }
47}
48
49impl NodeId {
50    /// Try to create a new NodeId from a u8
51    ///
52    /// Will fail if the value is not a valid node ID
53    pub const fn new(value: u8) -> Result<Self, InvalidNodeIdError> {
54        if value == 255 {
55            Ok(NodeId::Unconfigured)
56        } else {
57            match ConfiguredNodeId::new(value) {
58                Ok(id) => Ok(NodeId::Configured(id)),
59                Err(e) => Err(e),
60            }
61        }
62    }
63
64    /// Get the raw node ID as a u8
65    pub fn raw(&self) -> u8 {
66        match self {
67            NodeId::Unconfigured => 255,
68            NodeId::Configured(node_id_num) => node_id_num.0,
69        }
70    }
71
72    /// Attempt to get the node ID as a ConfiguredNodeId
73    ///
74    /// Returns none if the value is NodeId::Unconfigured
75    pub fn as_configured(&self) -> Option<ConfiguredNodeId> {
76        match self {
77            NodeId::Unconfigured => None,
78            NodeId::Configured(configured_node_id) => Some(*configured_node_id),
79        }
80    }
81
82    /// Return true if the NodeId contains a valid configured ID
83    pub fn is_configured(&self) -> bool {
84        match self {
85            Self::Configured(_) => true,
86            Self::Unconfigured => false,
87        }
88    }
89    /// Return true if the node ID is NodeId::Unconfigured
90    pub fn is_unconfigured(&self) -> bool {
91        match self {
92            Self::Configured(_) => false,
93            Self::Unconfigured => true,
94        }
95    }
96}
97
98/// Error for converting u8 to a NodeId
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub struct InvalidNodeIdError;
101
102impl core::fmt::Display for InvalidNodeIdError {
103    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104        write!(f, "Invalid node ID")
105    }
106}
107impl core::error::Error for InvalidNodeIdError {}
108
109impl TryFrom<u8> for NodeId {
110    type Error = InvalidNodeIdError;
111
112    fn try_from(value: u8) -> Result<Self, Self::Error> {
113        if value == 255 {
114            Ok(NodeId::Unconfigured)
115        } else {
116            Ok(NodeId::Configured(ConfiguredNodeId(value)))
117        }
118    }
119}
120
121impl From<NodeId> for u8 {
122    fn from(value: NodeId) -> Self {
123        value.raw()
124    }
125}