#lighting #protocols #dmx #control #rdm

no-std dmx512-rdm-protocol

DMX512 and Remote Device Management (RDM) protocol written in Rust

19 releases (7 breaking)

0.8.0 Oct 16, 2024
0.6.0 Oct 4, 2024

#102 in Hardware support

MIT license

400KB
10K SLoC

dmx512-rdm-protocol

DMX512 and Remote Device Management (RDM) protocol written in Rust

Crates.io Docs Docs

About the project

DMX512 is a unidirectional packet based communication protocol commonly used to control lighting and effects.

Remote Device Management (RDM) is a backward-compatible extension of DMX512, enabling bi-directional communication with compatible devices for the purpose of discovery, identification, reporting, and configuration.

Included

  • Data-types and functionality for encoding and decoding DMX512 and RDM packets.
  • no_std implementations by disabling alloc feature flag

Not included

  • Driver implementations: DMX512 / RDM packets are transmitted over an RS485 bus but interface devices like the Enttec DMX USB PRO exist to communicate with devices via USB. These interface devices usually require extra packet framing ontop of the standard DMX512 / RDM packets, which is out of scope of this project.

Implemented specifications / supported parameters

  • ANSI E1.11 (2008): Asynchronous Serial Digital Data Transmission Standard for Controlling Lighting Equipment and Accessories [Implemented]
  • ANSI E1.20 (2010): RDM Remote Device Management Over DMX512 Networks [Implemented]
  • ANSI E1.37-1 (2012): Additional Message Sets for ANSI E1.20 (RDM) – Part 1, Dimmer Message Sets [Implemented]
  • ANSI E1.37-2 (2015): Additional Message Sets for ANSI E1.20 (RDM) – Part 2, IPv4 & DNS Configuration Messages [Implemented]
  • ANSI E1.37-7 (2019): Additional Message Sets for ANSI E1.20 (RDM) – Gateway & Splitter Configuration Messages [Implemented]
  • ANSI E1.33 (RDMnet): Message Transport and Management for ANSI E1.20 (RDM) compatible and similar devices over IP Networks [Supported]

(back to top)

Installation

cargo add dmx512-rdm-protocol

or add to Cargo.toml dependencies, crates.io for latest version.

(back to top)

Feature flags

The default-features for this project are heap allocation implementations and rdm features included, however if you just want to use the basic DMX512 data-types and functionality and it be no_std compatible, you can set default-features = false in the Cargo.toml dependency.

Otherwise the following flags can be toggled to find subset of the functionality.

  • Add rdm flag to conditionally compile rdm features. The rdm features have no_std compatible implementations.
  • Add alloc flag for heap allocation implementation, i.e not no_std compatible.

(back to top)

Usage

DmxUniverse

use dmx512_rdm_protocol::dmx::DmxUniverse;

// Create a 512 channel universe
let dmx_universe = DmxUniverse::default();
// or create a smaller universe

// If you use the heap allocation implementations, you can create smaller universes
#[cfg(feature = "alloc")]
let dmx_universe = DmxUniverse::new(4).unwrap();

// or decode a dmx packet
let mut dmx_universe = DmxUniverse::decode(&[0, 255, 255, 0, 0]).unwrap();

assert_eq!(&dmx_universe.as_slice()[..4], &[255, 255, 0, 0]);

dmx_universe.set_channel_value(0, 64).unwrap();
dmx_universe.set_channel_values(1, &[128, 192, 255]).unwrap();

assert_eq!(dmx_universe.get_channel_value(0).unwrap(), 64);
assert_eq!(dmx_universe.get_channel_values(1..=2).unwrap(), &[128, 192]);
assert_eq!(&dmx_universe.as_slice()[..4], &[64, 128, 192, 255]);
assert_eq!(&dmx_universe.encode()[..5], &[0, 64, 128, 192, 255]);

RdmRequest

let encoded = RdmRequest::new(
    DeviceUID::new(0x0102, 0x03040506),
    DeviceUID::new(0x0605, 0x04030201),
    0x00,
    0x01,
    SubDeviceId::RootDevice,
    RequestParameter::GetIdentifyDevice,
)
.encode();

let expected = &[
    0xcc, // Start Code
    0x01, // Sub Start Code
    0x18, // Message Length
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Destination UID
    0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // Source UID
    0x00, // Transaction Number
    0x01, // Port ID
    0x00, // Message Count
    0x00, 0x00, // Sub-Device ID = Root Device
    0x20, // Command Class = GetCommand
    0x10, 0x00, // Parameter ID = Identify Device
    0x00, // PDL
    0x01, 0x40, // Checksum
];

assert_eq!(encoded, expected);

RdmResponse

let decoded = RdmResponse::decode(&[
    0xcc, // Start Code
    0x01, // Sub Start Code
    0x19, // Message Length
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Destination UID
    0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // Source UID
    0x00, // Transaction Number
    0x00, // Response Type = Ack
    0x00, // Message Count
    0x00, 0x00, // Sub-Device ID = Root Device
    0x21, // Command Class = GetCommandResponse
    0x10, 0x00, // Parameter ID = Identify Device
    0x01, // PDL
    0x01, // Identifying = true
    0x01, 0x43, // Checksum
]);

let expected = Ok(RdmResponse::RdmFrame(RdmFrameResponse {
    destination_uid: DeviceUID::new(0x0102, 0x03040506),
    source_uid: DeviceUID::new(0x0605, 0x04030201),
    transaction_number: 0x00,
    response_type: ResponseType::Ack,
    message_count: 0x00,
    sub_device_id: SubDeviceId::RootDevice,
    command_class: CommandClass::GetCommandResponse,
    parameter_id: ParameterId::IdentifyDevice,
    parameter_data: ResponseData::ParameterData(Some(
        ResponseParameterData::GetIdentifyDevice(true),
    )),
}));

assert_eq!(decoded, expected);

See tests for more examples.

(back to top)

Contributing

This project is open to contributions, create a new issue and let's discuss.

(back to top)

License

Distributed under the MIT License. See LICENSE.txt for more information.

(back to top)

Acknowledgments

  • The ANSI E1.11 (2008), ANSI E1.20 (2010), ANSI E1.37-1 (2012), ANSI E1.37-2 (2015), ANSI E1.37-7 (2019) and ANSI E1.33 (RDMnet) specifications used to create this library is copyright and published by ESTA

(back to top)

Dependencies

~505KB
~10K SLoC