dmx512_rdm_protocol/rdm/
mod.rs

1//! Data types and functionality for encoding and decoding RDM packets
2
3pub mod error;
4pub mod parameter;
5pub mod request;
6pub mod response;
7
8use error::RdmError;
9pub use macaddr;
10
11pub const RDM_START_CODE_BYTE: u8 = 0xcc;
12pub const RDM_SUB_START_CODE_BYTE: u8 = 0x01;
13
14pub const DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE: u8 = 0xfe;
15pub const DISCOVERY_UNIQUE_BRANCH_PREAMBLE_SEPARATOR_BYTE: u8 = 0xaa;
16
17pub const MAX_RDM_FRAME_LENGTH: usize = 257;
18pub const MAX_RDM_PARAMETER_DATA_LENGTH: usize = 231;
19
20#[cfg(not(feature = "alloc"))]
21use heapless::Vec;
22
23#[cfg(feature = "alloc")]
24pub type EncodedFrame = Vec<u8>;
25#[cfg(not(feature = "alloc"))]
26pub type EncodedFrame = Vec<u8, MAX_RDM_FRAME_LENGTH>;
27
28#[cfg(feature = "alloc")]
29pub type EncodedParameterData = Vec<u8>;
30#[cfg(not(feature = "alloc"))]
31pub type EncodedParameterData = Vec<u8, MAX_RDM_PARAMETER_DATA_LENGTH>;
32
33#[derive(Copy, Clone, Debug, PartialEq)]
34pub enum CommandClass {
35    DiscoveryCommand = 0x10,
36    DiscoveryCommandResponse = 0x11,
37    GetCommand = 0x20,
38    GetCommandResponse = 0x21,
39    SetCommand = 0x30,
40    SetCommandResponse = 0x31,
41}
42
43impl TryFrom<u8> for CommandClass {
44    type Error = RdmError;
45
46    fn try_from(value: u8) -> Result<Self, Self::Error> {
47        match value {
48            0x10 => Ok(Self::DiscoveryCommand),
49            0x11 => Ok(Self::DiscoveryCommandResponse),
50            0x20 => Ok(Self::GetCommand),
51            0x21 => Ok(Self::GetCommandResponse),
52            0x30 => Ok(Self::SetCommand),
53            0x31 => Ok(Self::SetCommandResponse),
54            _ => Err(RdmError::InvalidCommandClass(value)),
55        }
56    }
57}
58
59#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
60pub struct DeviceUID {
61    pub manufacturer_id: u16,
62    pub device_id: u32,
63}
64
65impl DeviceUID {
66    pub const ALL_MANUFACTURERS_ID: u16 = 0xffff;
67    pub const ALL_DEVICES_ID: u32 = 0xffffffff;
68
69    pub const fn new(manufacturer_id: u16, device_id: u32) -> Self {
70        Self {
71            manufacturer_id,
72            device_id,
73        }
74    }
75
76    pub const fn new_dynamic(mut manufacturer_id: u16, device_id: u32) -> Self {
77        manufacturer_id |= 0x8000;
78
79        Self {
80            manufacturer_id,
81            device_id,
82        }
83    }
84
85    pub const fn broadcast_to_devices_with_manufacturer_id(manufacturer_id: u16) -> Self {
86        Self {
87            manufacturer_id,
88            device_id: Self::ALL_DEVICES_ID,
89        }
90    }
91
92    pub const fn broadcast_to_devices_with_manufacturer_id_dynamic(
93        mut manufacturer_id: u16,
94        device_id: u32,
95    ) -> Self {
96        manufacturer_id |= 0x8000;
97
98        Self {
99            manufacturer_id,
100            device_id,
101        }
102    }
103
104    pub const fn broadcast_to_all_devices() -> Self {
105        Self {
106            manufacturer_id: Self::ALL_MANUFACTURERS_ID,
107            device_id: Self::ALL_DEVICES_ID,
108        }
109    }
110
111    pub fn is_dynamic(&self) -> bool {
112        self.manufacturer_id & 0x8000 != 0
113    }
114}
115
116impl From<[u8; 6]> for DeviceUID {
117    fn from(bytes: [u8; 6]) -> Self {
118        let manufacturer_id = u16::from_be_bytes([bytes[0], bytes[1]]);
119        let device_id = u32::from_be_bytes([bytes[2], bytes[3], bytes[4], bytes[5]]);
120
121        DeviceUID {
122            manufacturer_id,
123            device_id,
124        }
125    }
126}
127
128impl From<DeviceUID> for [u8; 6] {
129    fn from(uid: DeviceUID) -> Self {
130        let manufacturer_id_bytes = uid.manufacturer_id.to_be_bytes();
131        let device_id_bytes = uid.device_id.to_be_bytes();
132
133        [
134            manufacturer_id_bytes[0],
135            manufacturer_id_bytes[1],
136            device_id_bytes[0],
137            device_id_bytes[1],
138            device_id_bytes[2],
139            device_id_bytes[3],
140        ]
141    }
142}
143
144pub fn bsd_16_crc(packet: &[u8]) -> u16 {
145    packet
146        .iter()
147        .fold(0_u16, |sum, byte| (sum.overflowing_add(*byte as u16).0))
148}
149
150#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
151pub enum SubDeviceId {
152    RootDevice,
153    Id(u16),
154    AllDevices,
155}
156
157impl From<u16> for SubDeviceId {
158    fn from(value: u16) -> SubDeviceId {
159        match value {
160            0x0000 => SubDeviceId::RootDevice,
161            0xffff => SubDeviceId::AllDevices,
162            _ => SubDeviceId::Id(value),
163        }
164    }
165}
166
167impl From<SubDeviceId> for u16 {
168    fn from(sub_device: SubDeviceId) -> u16 {
169        match sub_device {
170            SubDeviceId::RootDevice => 0x0000,
171            SubDeviceId::AllDevices => 0xffff,
172            SubDeviceId::Id(id) => id,
173        }
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180
181    #[test]
182    fn should_create_static_device_uid() {
183        let device_uid = DeviceUID::new(0x1234, 0x56789abc);
184
185        assert_eq!(
186            device_uid,
187            DeviceUID {
188                manufacturer_id: 0x1234,
189                device_id: 0x56789abc
190            }
191        );
192        assert!(!device_uid.is_dynamic());
193    }
194
195    #[test]
196    fn should_create_dynamic_device_uid() {
197        let device_uid = DeviceUID::new_dynamic(0x1234, 0x56789abc);
198
199        assert_eq!(
200            device_uid,
201            DeviceUID {
202                manufacturer_id: 0x9234,
203                device_id: 0x56789abc
204            }
205        );
206        assert!(device_uid.is_dynamic());
207    }
208
209    #[test]
210    fn should_array_to_convert_device_uid() {
211        assert_eq!(
212            DeviceUID::from([0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]),
213            DeviceUID::new(0x1234, 0x56789abc)
214        );
215    }
216
217    #[test]
218    fn should_convert_device_uid_to_array() {
219        assert_eq!(
220            <[u8; 6]>::from(DeviceUID::new(0x1234, 0x56789abc)),
221            [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]
222        );
223    }
224}