dmx_rdm/
dmx_driver.rs

1use crate::consts::{
2    DMX_MAX_PACKAGE_SIZE, DMX_NULL_START, PREAMBLE_BYTE, RDM_DISCOVERY_RESPONSE_SIZE,
3    RDM_MAX_PACKAGE_SIZE, SC_RDM, SEPARATOR_BYTE,
4};
5use crate::dmx_receiver::DmxFrame;
6use crate::dmx_uart_driver::{
7    DmxRecvUartDriver, DmxRespUartDriver, DmxUartDriver, DmxUartDriverError,
8};
9use crate::rdm_data::{deserialize_discovery_response, RdmData, RdmDeserializationError};
10use crate::unique_identifier::UniqueIdentifier;
11use crate::utils::{calculate_checksum, encode_disc_unique};
12
13#[derive(Debug, Copy, Clone, Eq, PartialEq)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub enum DmxError<E> {
16    /// There were fewer bytes written to the uart then there should have been.
17    UartOverflow,
18    /// The request timed time out.
19    /// **Important:** If you implement a driver make sure this error gets raised instead
20    /// of a driver specific error.
21    TimeoutError,
22    /// Raised when an RDM package could not be deserialized.
23    DeserializationError(RdmDeserializationError),
24    /// An error raised by the uart driver.
25    DriverError(E),
26}
27
28impl<E: core::fmt::Display> core::fmt::Display for DmxError<E> {
29    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
30        match self {
31            DmxError::UartOverflow => write!(f, "uart overflowed"),
32            DmxError::TimeoutError => write!(f, "request timed out"),
33            DmxError::DeserializationError(error) => error.fmt(f),
34            DmxError::DriverError(error) => error.fmt(f),
35        }
36    }
37}
38
39impl<E> From<E> for DmxError<E> {
40    fn from(value: E) -> Self {
41        Self::DriverError(value)
42    }
43}
44
45#[cfg(feature = "std")]
46impl<E: core::fmt::Display + core::fmt::Debug> std::error::Error for DmxError<E> {}
47
48#[derive(Debug, Copy, Clone, Eq, PartialEq)]
49pub enum DiscoveryOption {
50    /// No device responded to the discovery request.
51    /// There aren't any devices in the specified unique id range.
52    NoDevice,
53    /// The response to the discovery request couldn't be deserialized.
54    /// There are multiple devices in the specified unique id range.
55    Collision,
56    /// The discovery response was successfully deserialized.
57    /// There is only one device in the specified unique id range.
58    Found(UniqueIdentifier),
59}
60
61impl<E> From<DmxUartDriverError<E>> for DmxError<E> {
62    fn from(value: DmxUartDriverError<E>) -> Self {
63        match value {
64            DmxUartDriverError::TimeoutError => Self::TimeoutError,
65            DmxUartDriverError::DriverError(driver_error) => Self::DriverError(driver_error),
66        }
67    }
68}
69
70/// Trait that ensures that the same Error is used in the [DmxControllerDriver] as well as the [RdmControllerDriver].
71pub trait ControllerDriverErrorDef {
72    /// The driver specific error.
73    type DriverError;
74}
75
76/// Trait for controlling DMX fixtures.
77pub trait DmxControllerDriver: ControllerDriverErrorDef {
78    /// Send a DMX512 package. It shouldn't be bigger than 512 bytes.
79    fn send_dmx_package(&mut self, package: &[u8]) -> Result<(), DmxError<Self::DriverError>>;
80}
81
82/// Trait for sending and receiving RDM packages from a controller point of view.
83pub trait RdmControllerDriver: ControllerDriverErrorDef {
84    /// Sends an RDM package.
85    fn send_rdm(&mut self, package: RdmData) -> Result<(), DmxError<Self::DriverError>>;
86    /// Receives an RDM package.
87    fn receive_rdm(&mut self) -> Result<RdmData, DmxError<Self::DriverError>>;
88    /// Receives an RDM discovery response.
89    /// Returns the received device id.
90    fn receive_rdm_discovery_response(
91        &mut self,
92    ) -> Result<DiscoveryOption, DmxError<Self::DriverError>>;
93    /// Send a dmx discovery response. If this functionality is already been solved
94    /// by the device add hand, provide an empty function.
95    fn send_rdm_discovery_response(
96        &mut self,
97        uid: UniqueIdentifier,
98    ) -> Result<(), DmxError<Self::DriverError>>;
99}
100
101/// Trait for implementing packages with custom start codes.
102pub trait CustomStartCodeControllerDriver: ControllerDriverErrorDef {
103    /// Sends a package with a custom start code.
104    fn send_custom_package(
105        &mut self,
106        start_code: u8,
107        package: &[u8],
108    ) -> Result<(), DmxError<Self::DriverError>>;
109}
110
111impl<D: DmxUartDriver> ControllerDriverErrorDef for D {
112    type DriverError = D::DriverError;
113}
114
115impl<D: DmxRespUartDriver> CustomStartCodeControllerDriver for D {
116    fn send_custom_package(
117        &mut self,
118        start_code: u8,
119        package: &[u8],
120    ) -> Result<(), DmxError<Self::DriverError>> {
121        let mut frame_buffer: heapless::Vec<_, DMX_MAX_PACKAGE_SIZE> = heapless::Vec::new();
122        frame_buffer.push(start_code).unwrap();
123        frame_buffer
124            .extend_from_slice(package)
125            .or(Err(DmxError::UartOverflow))?;
126
127        if self.write_frames(&frame_buffer)? != package.len() {
128            return Err(DmxError::UartOverflow);
129        }
130
131        Ok(())
132    }
133}
134
135impl<D: DmxRespUartDriver> DmxControllerDriver for D {
136    fn send_dmx_package(&mut self, package: &[u8]) -> Result<(), DmxError<Self::DriverError>> {
137        self.send_custom_package(DMX_NULL_START, package)
138    }
139}
140
141const READ_TIMEOUT_US: u32 = 2800;
142impl<D: DmxRespUartDriver + DmxRecvUartDriver> RdmControllerDriver for D {
143    fn send_rdm(&mut self, rdm_package: RdmData) -> Result<(), DmxError<Self::DriverError>> {
144        let serialized_package = rdm_package.serialize();
145        let written_bytes = self.write_frames(&serialized_package)?;
146
147        if serialized_package.len() != written_bytes {
148            return Err(DmxError::UartOverflow);
149        }
150
151        Ok(())
152    }
153
154    fn receive_rdm(&mut self) -> Result<RdmData, DmxError<Self::DriverError>> {
155        // Very imprecise value for testing
156        let mut receive_buffer = [0u8; RDM_MAX_PACKAGE_SIZE];
157        let mut bytes_read = self.read_frames(&mut receive_buffer[0..3], READ_TIMEOUT_US)?;
158
159        // plus two checksum bytes
160        let message_length = receive_buffer[2] as usize + 2;
161        if message_length < 3 {
162            return Err(DmxError::DeserializationError(
163                RdmDeserializationError::WrongMessageLength(message_length),
164            ));
165        }
166        if message_length > RDM_MAX_PACKAGE_SIZE {
167            return Err(DmxError::DeserializationError(
168                RdmDeserializationError::WrongMessageLength(message_length),
169            ));
170        }
171
172        bytes_read +=
173            self.read_frames_no_break(&mut receive_buffer[3..message_length], READ_TIMEOUT_US)?;
174        let response = RdmData::deserialize(&receive_buffer[..bytes_read])
175            .map_err(DmxError::DeserializationError)?;
176
177        Ok(response)
178    }
179
180    fn receive_rdm_discovery_response(
181        &mut self,
182    ) -> Result<DiscoveryOption, DmxError<Self::DriverError>> {
183        let mut receive_buffer = [0u8; 32]; // the actual package is 24 bytes
184        let bytes_read = match self.read_frames_no_break(&mut receive_buffer, READ_TIMEOUT_US) {
185            Err(DmxUartDriverError::TimeoutError) => return Ok(DiscoveryOption::NoDevice),
186            result => result,
187        }?;
188
189        if bytes_read < RDM_DISCOVERY_RESPONSE_SIZE {
190            return Ok(DiscoveryOption::Collision);
191        }
192
193        Ok(
194            deserialize_discovery_response(&receive_buffer[..bytes_read])
195                .map_or(DiscoveryOption::Collision, DiscoveryOption::Found),
196        )
197    }
198
199    fn send_rdm_discovery_response(
200        &mut self,
201        uid: UniqueIdentifier,
202    ) -> Result<(), DmxError<Self::DriverError>> {
203        let mut frame_buffer = [PREAMBLE_BYTE; 24];
204        frame_buffer[7] = SEPARATOR_BYTE;
205
206        let uid_buffer = uid.to_bytes();
207        encode_disc_unique(&uid_buffer, &mut frame_buffer[8..20]);
208
209        let checksum = calculate_checksum(&frame_buffer[8..20]);
210        encode_disc_unique(&checksum.to_be_bytes(), &mut frame_buffer[20..24]);
211
212        if self.write_frames_no_break(&frame_buffer)? != frame_buffer.len() {
213            return Err(DmxError::UartOverflow);
214        }
215
216        Ok(())
217    }
218}
219
220pub trait DmxReceiver: ControllerDriverErrorDef {
221    /// Receive a DMX512 package.
222    fn receive_package(&mut self) -> Result<DmxFrame, DmxError<Self::DriverError>>;
223}
224
225impl<D: DmxRecvUartDriver> DmxReceiver for D {
226    fn receive_package(&mut self) -> Result<DmxFrame, DmxError<D::DriverError>> {
227        const READ_TIMEOUT_US: u32 = 1800;
228
229        let mut buffer = [0u8; DMX_MAX_PACKAGE_SIZE];
230        let mut bytes_read = self.read_frames(&mut buffer[0..3], READ_TIMEOUT_US)?;
231        if bytes_read < 2 {
232            return Err(DmxError::DeserializationError(
233                RdmDeserializationError::WrongMessageLength(bytes_read),
234            ));
235        }
236
237        // workaround for rdm packages to have better receive times
238        let start_code = buffer[0];
239        let message_size = if start_code == SC_RDM && bytes_read == 3 {
240            // message size plus two checksum bytes
241            buffer[2] as usize + 2
242        } else {
243            DMX_MAX_PACKAGE_SIZE
244        };
245
246        bytes_read += self.read_frames_no_break(&mut buffer[3..message_size], READ_TIMEOUT_US)?;
247        Ok(DmxFrame::from_slice(&buffer[..bytes_read]).unwrap())
248    }
249}