dmx_rdm/
dmx_receiver.rs

1use crate::consts::SC_RDM;
2use crate::dmx_driver::{DmxError, DmxReceiver, RdmControllerDriver};
3use crate::rdm_data::{RdmData, RdmDeserializationError, RdmRequestData, RdmResponseData};
4use crate::rdm_responder::{
5    DmxReceiverContext, RdmAnswer, RdmResponderConfig, RdmResponderHandlerFunc,
6    RdmResponderPackageHandler, RdmResult,
7};
8use crate::rdm_types::StatusMessage;
9use crate::types::NackReason;
10
11/// A vector that contains one DmxFrame. The first byte is the start code. 0x00 is the dmx start code.
12pub type DmxFrame = heapless::Vec<u8, 513>;
13
14pub enum ResponseOption {
15    NoResponse,
16    Response(DmxFrame),
17    ResponseNoBreak(DmxFrame),
18}
19
20#[derive(Debug)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub struct HandlePackageError;
23
24impl core::fmt::Display for HandlePackageError {
25    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
26        write!(f, "Couldn't handle package.")
27    }
28}
29
30#[cfg(feature = "std")]
31impl std::error::Error for HandlePackageError {}
32
33#[derive(Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35/// Errors that can happen during polling. These errors should not cause panics.
36pub enum PollingError<DriverError, HandlerError> {
37    /// There were fewer bytes written to the uart then there should have been.
38    UartOverflow,
39    /// The request timed time out.
40    /// **Important:** If you implement a driver make sure this error gets raised instead
41    /// of a driver specific error.
42    TimeoutError,
43    /// The start code is unknown.
44    UnknownStartCode,
45    /// The package size is insufficient.
46    WrongPackageSize,
47    /// The received package doesn't match the request.
48    NotMatching,
49    /// A driver specific error occurred.
50    DriverError(DriverError),
51    /// A handler specific error occurred.
52    HandlerError(HandlerError),
53    /// Raised when an RDM package could not be deserialized.
54    DeserializationError(RdmDeserializationError),
55}
56
57impl<DriverError, HandlerError> From<DmxError<DriverError>>
58    for PollingError<DriverError, HandlerError>
59{
60    fn from(value: DmxError<DriverError>) -> Self {
61        match value {
62            DmxError::UartOverflow => Self::UartOverflow,
63            DmxError::TimeoutError => Self::TimeoutError,
64            DmxError::DeserializationError(deserialization_error) => {
65                Self::DeserializationError(deserialization_error)
66            },
67            DmxError::DriverError(driver_error) => Self::DriverError(driver_error),
68        }
69    }
70}
71
72impl<DriverError: core::fmt::Display, HandlerError: core::fmt::Display> core::fmt::Display
73    for PollingError<DriverError, HandlerError>
74{
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        let error_message = match self {
77            PollingError::UartOverflow => "Uart overflow.",
78            PollingError::TimeoutError => "Timeout error.",
79            PollingError::DeserializationError(_) => "Deserialization error.",
80            PollingError::NotMatching => "Received response and not request.",
81            PollingError::UnknownStartCode => "The start code is unknown.",
82            PollingError::WrongPackageSize => "The package size is insufficient.",
83            PollingError::DriverError(error) => {
84                return core::fmt::Display::fmt(error, f);
85            },
86            PollingError::HandlerError(error) => {
87                return core::fmt::Display::fmt(error, f);
88            },
89        };
90
91        write!(f, "{}", error_message)
92    }
93}
94
95#[cfg(feature = "std")]
96impl<
97        DriverError: core::fmt::Display + core::fmt::Debug,
98        HandlerError: core::fmt::Display + core::fmt::Debug,
99    > std::error::Error for PollingError<DriverError, HandlerError>
100{
101}
102
103/// A handler for dmx and custom rdm packages.
104pub trait DmxResponderHandler {
105    type Error;
106
107    /// Handle rdm requests that aren't handled by the [RdmResponder] itself.
108    fn handle_rdm(
109        &mut self,
110        _request: &RdmRequestData,
111        _context: &mut DmxReceiverContext,
112    ) -> Result<RdmResult, Self::Error> {
113        Ok(RdmResult::NotAcknowledged(
114            NackReason::UnsupportedCommandClass as u16,
115        ))
116    }
117
118    /// Handle all received frames that have a different start code than `0xCC` (the rdm start code).
119    /// The first byte is the start code. If start code is `0x00` it's a DMX Package.
120    fn handle_dmx(
121        &mut self,
122        _dmx_frame: DmxFrame,
123        _context: &mut DmxReceiverContext,
124    ) -> Result<(), Self::Error> {
125        Ok(())
126    }
127}
128
129/// The structure to build an RDM Receiver.
130/// MQ_SIZE specifies the size of the message queue and the status vector. MQ_SIZE cannot be greater
131/// than 255.
132pub struct RdmResponder<D: DmxReceiver + RdmControllerDriver, const MQ_SIZE: usize> {
133    driver: D,
134    rdm_receiver_handler: RdmResponderPackageHandler<MQ_SIZE>,
135}
136
137impl<D: DmxReceiver + RdmControllerDriver, const MQ_SIZE: usize> RdmResponder<D, MQ_SIZE> {
138    /// Creates a new [RdmResponder].
139    pub fn new(driver: D, config: RdmResponderConfig) -> Self {
140        Self {
141            driver,
142            rdm_receiver_handler: RdmResponderPackageHandler::new(config),
143        }
144    }
145
146    /// Call this function as often as you can or on a serial interrupt. It will
147    /// receive a package and handle it.
148    ///
149    /// Returns false if no package was received.
150    pub fn poll<HandlerError>(
151        &mut self,
152        handler: &mut dyn DmxResponderHandler<Error = HandlerError>,
153    ) -> Result<bool, PollingError<D::DriverError, HandlerError>> {
154        let package = match self.driver.receive_package() {
155            Err(DmxError::TimeoutError) => return Ok(false),
156            result => result?,
157        };
158
159        if package.is_empty() {
160            return Err(PollingError::WrongPackageSize);
161        }
162
163        let start_code = package[0];
164        match start_code {
165            SC_RDM => {
166                self.handle_rdm(package, handler)?;
167            },
168            _ => {
169                handler
170                    .handle_dmx(package, &mut self.rdm_receiver_handler.get_context())
171                    .map_err(|error| PollingError::HandlerError(error))?;
172            },
173        }
174
175        Ok(true)
176    }
177
178    fn handle_rdm<HandlerError>(
179        &mut self,
180        package: DmxFrame,
181        handler: &mut dyn DmxResponderHandler<Error = HandlerError>,
182    ) -> Result<(), PollingError<D::DriverError, HandlerError>> {
183        struct DmxRdmHandlerWrapper<'a, HandlerError> {
184            dmx: &'a mut dyn DmxResponderHandler<Error = HandlerError>,
185        }
186
187        impl<HandlerError> RdmResponderHandlerFunc for DmxRdmHandlerWrapper<'_, HandlerError> {
188            type Error = HandlerError;
189            fn handle_rdm(
190                &mut self,
191                request: &RdmRequestData,
192                context: &mut DmxReceiverContext,
193            ) -> Result<RdmResult, Self::Error> {
194                self.dmx.handle_rdm(request, context)
195            }
196        }
197
198        let rdm_data =
199            RdmData::deserialize(&package).map_err(PollingError::DeserializationError)?;
200
201        let request = match rdm_data {
202            RdmData::Request(request) => request,
203            _ => return Err(PollingError::NotMatching),
204        };
205
206        let response = self
207            .rdm_receiver_handler
208            .handle_rdm_request(request, &mut DmxRdmHandlerWrapper { dmx: handler })
209            .map_err(PollingError::HandlerError)?;
210
211        match response {
212            RdmAnswer::Response(response_data) => {
213                self.driver
214                    .send_rdm(RdmData::Response(response_data))
215                    .map_err(|error| match error {
216                        DmxError::UartOverflow => PollingError::UartOverflow,
217                        DmxError::TimeoutError => PollingError::TimeoutError,
218                        DmxError::DeserializationError(deserialization_error) => {
219                            PollingError::DeserializationError(deserialization_error)
220                        },
221                        DmxError::DriverError(driver_error) => {
222                            PollingError::DriverError(driver_error)
223                        },
224                    })?;
225            },
226            RdmAnswer::DiscoveryResponse(uid) => {
227                self.driver.send_rdm_discovery_response(uid)?;
228            },
229            RdmAnswer::NoResponse => {},
230        }
231
232        Ok(())
233    }
234
235    /// Get the message queue that contains the results of [RdmResult::AcknowledgedTimer] packages.
236    pub fn get_message_queue(&self) -> &heapless::Deque<RdmResponseData, MQ_SIZE> {
237        self.rdm_receiver_handler.get_message_queue()
238    }
239
240    /// Get the message queue to add the results of [RdmResult::AcknowledgedTimer] packages to.
241    pub fn get_message_queue_mut(&mut self) -> &mut heapless::Deque<RdmResponseData, MQ_SIZE> {
242        self.rdm_receiver_handler.get_message_queue_mut()
243    }
244
245    /// Get the amount of queued messages.
246    pub fn get_message_count(&self) -> u8 {
247        self.rdm_receiver_handler.get_message_count()
248    }
249
250    /// Get the status queue that contains the current status messages.
251    pub fn get_status_vec(&self) -> &heapless::Vec<StatusMessage, MQ_SIZE> {
252        self.rdm_receiver_handler.get_status_vec()
253    }
254
255    /// Get the status queue to add or remove status messages.
256    pub fn get_status_vec_mut(&mut self) -> &mut heapless::Vec<StatusMessage, MQ_SIZE> {
257        self.rdm_receiver_handler.get_status_vec_mut()
258    }
259}