dmx_rdm/
lib.rs

1//! Rust library for communicating DMX512 (ANSI E1.11) and DMX-RDM (ANSI E1.20) over a RS485 bus by
2//! using interchangeable drivers. This library features no-std as well as no-alloc support
3//! (no heap allocation) to target embedded as well as os platforms.
4//!
5//! Please refer to the [official specifications](https://tsp.esta.org/) published by the ESTA.
6//!
7//! <div class="warning">This library is wip, it has not yet received extensive testing and the api
8//! might not be final.</div>
9//!
10//! # Usage
11//! These examples show the basic usage using the dmx-rdm-ftdi driver.
12//! These examples work together.
13//!
14//! ## Controller
15//!
16//! ```rust
17//! use dmx_rdm::dmx_controller::{DmxController, DmxControllerConfig};
18//! use dmx_rdm::unique_identifier::{PackageAddress, UniqueIdentifier};
19//! use dmx_rdm::utils::run_full_discovery;
20//! use dmx_rdm_ftdi::{FtdiDriver, FtdiDriverConfig};
21//!
22//! let dmx_driver = FtdiDriver::new(FtdiDriverConfig::default()).unwrap();
23//! let mut dmx_controller = DmxController::new(dmx_driver, &DmxControllerConfig::default());
24//!
25//! let mut devices_found = vec![];
26//!
27//! // Unmute all dmx responders.
28//! dmx_controller
29//!     .rdm_disc_un_mute(PackageAddress::Broadcast)
30//!     .unwrap();
31//!
32//! let mut uid_array = [UniqueIdentifier::new(1, 1).unwrap(); 512];
33//! loop {
34//!     // Search for devices.
35//!     let amount_devices_found = run_full_discovery(&mut dmx_controller, &mut uid_array).unwrap();
36//!
37//!     // Add found devices to vector.
38//!     devices_found.extend_from_slice(&uid_array[..amount_devices_found]);
39//!
40//!     // Have all devices been found and muted?
41//!     if amount_devices_found != uid_array.len() {
42//!         break;
43//!     }
44//! }
45//!
46//! for device in devices_found {
47//!     match dmx_controller.rdm_set_identify(PackageAddress::Device(device), true) {
48//!         Ok(_) => println!("Activated identify for device_uid {device}"),
49//!         Err(error) => {
50//!             println!("Activating identify for device_uid {device} failed with {error}")
51//!         },
52//!     }
53//! }
54//! ```
55//!
56//! ## Responder
57//!
58//! ```rust
59//! use dmx_rdm::command_class::RequestCommandClass;
60//! use dmx_rdm::dmx_receiver::{DmxResponderHandler, RdmResponder};
61//! use dmx_rdm::rdm_data::RdmRequestData;
62//! use dmx_rdm::rdm_responder::{DmxReceiverContext, RdmResponderConfig, RdmResult};
63//! use dmx_rdm::types::{DataPack, NackReason};
64//! use dmx_rdm::unique_identifier::UniqueIdentifier;
65//! use dmx_rdm_ftdi::{FtdiDriver, FtdiDriverConfig};
66//!
67//! struct RdmHandler {
68//!     identify: bool,
69//! }
70//!
71//! const PID_IDENTIFY_DEVICE: u16 = 0x1000;
72//!
73//! impl RdmHandler {
74//!     fn handle_get_identify(&self) -> RdmResult {
75//!         RdmResult::Acknowledged(DataPack::from_slice(&[self.identify as u8]).unwrap())
76//!     }
77//!
78//!     fn handle_set_identify(&mut self, parameter_data: &[u8]) -> Result<RdmResult, std::fmt::Error> {
79//!         // Check if the parameter data has the correct size
80//!         if parameter_data.len() != 1 {
81//!             return Ok(RdmResult::NotAcknowledged(
82//!                 NackReason::DataOutOfRange as u16,
83//!             ));
84//!         }
85//!
86//!         // Convert identify flag to bool and set that in the state.
87//!         self.identify = parameter_data[0] != 0;
88//!
89//!         println!("Current identify is {}", self.identify);
90//!
91//!         // Acknowledge request with an empty response.
92//!         Ok(RdmResult::Acknowledged(DataPack::new()))
93//!     }
94//! }
95//!
96//! impl DmxResponderHandler for RdmHandler {
97//!     type Error = std::fmt::Error;
98//!
99//!     fn handle_rdm(
100//!         &mut self,
101//!         request: &RdmRequestData,
102//!         _: &mut DmxReceiverContext,
103//!     ) -> Result<RdmResult, Self::Error> {
104//!         match request.parameter_id {
105//!             PID_IDENTIFY_DEVICE => match request.command_class {
106//!                 RequestCommandClass::GetCommand => Ok(self.handle_get_identify()),
107//!                 RequestCommandClass::SetCommand => {
108//!                     self.handle_set_identify(&request.parameter_data)
109//!                 },
110//!                 _ => Ok(RdmResult::NotAcknowledged(
111//!                     NackReason::UnsupportedCommandClass as u16,
112//!                 )),
113//!             },
114//!             _ => Ok(RdmResult::NotAcknowledged(NackReason::UnknownPid as u16)),
115//!         }
116//!     }
117//! }
118//!
119//!
120//! let dmx_driver = FtdiDriver::new(FtdiDriverConfig::default()).unwrap();
121//!
122//! // Create rdm_responder with space for 32 queued messages.
123//! let mut dmx_responder = RdmResponder::<_, 32>::new(
124//!     dmx_driver,
125//!     RdmResponderConfig {
126//!         uid: UniqueIdentifier::new(0x7FF0, 1).unwrap(),
127//!         // Won't add PID_IDENTIFY_DEVICE since this is a required pid.
128//!         supported_pids: &[],
129//!         rdm_receiver_metadata: Default::default(),
130//!     },
131//! );
132//!
133//! let mut rdm_handler = RdmHandler { identify: false };
134//!
135//! loop {
136//!     // poll for new packages using our handler
137//!     match dmx_responder.poll(&mut rdm_handler) {
138//!         Ok(_) => (),
139//!         Err(error) => println!("'{error}' during polling"),
140//!     }
141//! }
142//! ```
143//!
144
145#![cfg_attr(not(feature = "std"), no_std)]
146#![cfg_attr(docsrs, feature(doc_cfg))]
147
148pub mod command_class;
149pub mod consts;
150/// Module for building dmx-rdm controllers.
151pub mod dmx_controller;
152/// Module for implementing more sophisticated dmx-rdm devices like Enttec DMX Pro, as well as
153/// mockups, where a simple uart implementation won't suffice.
154pub mod dmx_driver;
155/// Module for building dmx-rdm receivers.
156pub mod dmx_receiver;
157/// Module for simplifying the implementation of new drivers/hardware that behave like direct uart devices.
158pub mod dmx_uart_driver;
159mod layouts;
160mod pids;
161pub mod rdm_data;
162pub mod rdm_packages;
163/// Parser for handling rdm requests without an underlying driver.
164/// Mainly for highly interrupt driven applications.
165pub mod rdm_responder;
166pub mod rdm_types;
167pub mod types;
168pub mod unique_identifier;
169pub mod utils;