#protocols #lighting #dmx #control #rdm

dmx512-rdm-protocol

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

6 releases

0.3.0 Aug 16, 2024
0.2.2 Aug 16, 2024
0.1.1 Aug 13, 2024

#131 in Hardware support

Download history 454/week @ 2024-08-12 18/week @ 2024-08-19

472 downloads per month

MIT license

155KB
4K 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.

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

  • ANSI E1.11 (2008): Asynchronous Serial Digital Data Transmission Standard for Controlling Lighting Equipment and Accessories
  • ANSI E1.20 (2010): RDM Remote Device Management Over DMX512 Networks

(back to top)

Installation

cargo add dmx512-rdm-protocol

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

If you just want to use the basic DMX512 data-types and functionality, RDM has been conditionally compiled and included by default, but can be disabled by using the default-features = false dependency declaration.

(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
let dmx_universe = DmxUniverse::new(4).unwrap();
// or decode a DMX packet
let mut dmx_universe = DmxUniverse::decode(&[0, 0, 0, 0, 0]).unwrap();

assert_eq!(dmx_universe.as_slice(), &[0, 0, 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(), &[64, 128, 192, 255]);
assert_eq!(dmx_universe.encode(), &[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) and ANSI E1.20 (2010) specifications used to create this library is copyright and published by ESTA

(back to top)

No runtime deps

Features