use core::fmt;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum Error {
BadLength,
Overflow,
ObjectNotFound,
InvalidNodeId,
ReadOnly,
WriteOnly,
TypeMismatch,
DictionaryFull,
UnsupportedTransfer,
UnexpectedCommand,
UnknownState,
PdoTooLong,
MappingFull,
InvalidSyncCounter,
ToggleMismatch,
CrcMismatch,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
Error::BadLength => "frame or buffer length invalid for operation",
Error::Overflow => "value does not fit the target CANopen data type",
Error::ObjectNotFound => "no object at the requested index/subindex",
Error::InvalidNodeId => "node id out of range (must be 1..=127)",
Error::ReadOnly => "object is not writable",
Error::WriteOnly => "object is not readable",
Error::TypeMismatch => "value data type does not match the object",
Error::DictionaryFull => "object dictionary capacity exhausted",
Error::UnsupportedTransfer => "value cannot be carried by this transfer type",
Error::UnexpectedCommand => "unexpected SDO command byte in response",
Error::UnknownState => "unrecognised NMT state in heartbeat frame",
Error::PdoTooLong => "mapped PDO objects exceed eight bytes",
Error::MappingFull => "PDO mapping capacity exhausted",
Error::InvalidSyncCounter => "SYNC counter overflow must be 0 or 2..=240",
Error::ToggleMismatch => "SDO segment toggle bit did not alternate",
Error::CrcMismatch => "block-transfer CRC did not match the data",
};
f.write_str(msg)
}
}
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "std")]
impl std::error::Error for Error {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeId(u8);
impl NodeId {
pub const BROADCAST: NodeId = NodeId(0);
pub fn new(id: u8) -> Result<Self> {
if (1..=127).contains(&id) {
Ok(NodeId(id))
} else {
Err(Error::InvalidNodeId)
}
}
pub const fn raw(self) -> u8 {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn node_id_accepts_valid_range() {
assert_eq!(NodeId::new(1).unwrap().raw(), 1);
assert_eq!(NodeId::new(127).unwrap().raw(), 127);
}
#[test]
fn node_id_rejects_out_of_range() {
assert_eq!(NodeId::new(0), Err(Error::InvalidNodeId));
assert_eq!(NodeId::new(128), Err(Error::InvalidNodeId));
}
#[test]
fn broadcast_is_zero() {
assert_eq!(NodeId::BROADCAST.raw(), 0);
}
}