dmx_rdm/
rdm_packages.rs

1use crate::consts::RDM_STATUS_MESSAGE_SIZE;
2use crate::pids;
3use crate::rdm_types::{
4    DeserializationError, DmxStartAddress, StatusMessage, StatusMessages, SupportedParameters,
5};
6use crate::types::DataPack;
7
8pub fn deserialize_identify(buffer: &[u8]) -> Result<bool, DeserializationError> {
9    if buffer.len() != 1 {
10        return Err(DeserializationError);
11    }
12
13    Ok(buffer[0] != 0)
14}
15
16pub fn deserialize_software_version_label(
17    buffer: &[u8],
18) -> Result<heapless::String<32>, DeserializationError> {
19    heapless::String::from_utf8(
20        heapless::Vec::<_, 32>::from_slice(buffer).or(Err(DeserializationError))?,
21    )
22    .or(Err(DeserializationError))
23}
24
25pub fn deserialize_status_messages(buffer: &[u8]) -> Result<StatusMessages, DeserializationError> {
26    if buffer.len() % RDM_STATUS_MESSAGE_SIZE != 0 {
27        return Err(DeserializationError);
28    }
29
30    let mut status_messages = heapless::Vec::new();
31    for package_bytes in buffer.chunks(RDM_STATUS_MESSAGE_SIZE) {
32        status_messages
33            .push(StatusMessage::deserialize(package_bytes)?)
34            .map_err(|_| DeserializationError)?;
35    }
36
37    Ok(status_messages)
38}
39
40pub fn deserialize_supported_parameters(
41    buffer: &[u8],
42) -> Result<SupportedParameters, DeserializationError> {
43    if buffer.len() % 2 != 0 {
44        return Err(DeserializationError);
45    }
46
47    let mut supported_parameters = heapless::Vec::new();
48    for package_bytes in buffer.chunks(2) {
49        supported_parameters
50            .push(u16::from_be_bytes(package_bytes.try_into().unwrap()))
51            .map_err(|_| DeserializationError)?;
52    }
53
54    Ok(supported_parameters)
55}
56
57#[derive(Debug)]
58pub struct RdmResponseInfo {
59    pub parameter_id: u16,
60    pub message_count: u8,
61    pub data: DataPack,
62}
63
64#[derive(Debug)]
65pub enum RdmResponsePackage {
66    IdentifyDevice(bool),
67    SoftwareVersionLabel(heapless::String<32>),
68    DmxStartAddress(DmxStartAddress),
69    StatusMessages(StatusMessages),
70    SupportedParameters(SupportedParameters),
71    Custom(RdmResponseInfo),
72}
73
74impl RdmResponsePackage {
75    pub fn from_response_info(
76        response_info: RdmResponseInfo,
77    ) -> Result<Self, DeserializationError> {
78        Ok(match response_info.parameter_id {
79            pids::IDENTIFY_DEVICE => {
80                RdmResponsePackage::IdentifyDevice(deserialize_identify(&response_info.data)?)
81            },
82            pids::SOFTWARE_VERSION_LABEL => RdmResponsePackage::SoftwareVersionLabel(
83                deserialize_software_version_label(&response_info.data)?,
84            ),
85            pids::DMX_START_ADDRESS => RdmResponsePackage::DmxStartAddress(
86                DmxStartAddress::deserialize(&response_info.data)?,
87            ),
88            pids::STATUS_MESSAGES => RdmResponsePackage::StatusMessages(
89                deserialize_status_messages(&response_info.data)?,
90            ),
91            pids::SUPPORTED_PARAMETERS => RdmResponsePackage::SupportedParameters(
92                deserialize_supported_parameters(&response_info.data)?,
93            ),
94            _ => Self::Custom(response_info),
95        })
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use crate::rdm_packages::deserialize_identify;
102
103    #[test]
104    fn test_deserialize_identify_success() {
105        assert_eq!(deserialize_identify(&[0]).unwrap(), false);
106        assert_eq!(deserialize_identify(&[1]).unwrap(), true);
107
108        // should this work 🤣
109        assert_eq!(deserialize_identify(&[3]).unwrap(), true);
110    }
111
112    #[test]
113    fn test_deserialize_identify_failure() {
114        deserialize_identify(&[2, 1]).unwrap_err();
115        deserialize_identify(&[0, 0]).unwrap_err();
116    }
117}