3 unstable releases

Uses old Rust 2015

0.2.1 Mar 6, 2017
0.2.0 Mar 6, 2017
0.1.0 Mar 6, 2017

#21 in #lighting

Download history 12/week @ 2024-03-11 51/week @ 2024-03-18 26/week @ 2024-03-25 55/week @ 2024-04-01 25/week @ 2024-04-08 44/week @ 2024-04-15 32/week @ 2024-04-22 22/week @ 2024-05-06 17/week @ 2024-05-13 14/week @ 2024-05-20 13/week @ 2024-05-27 32/week @ 2024-06-03 58/week @ 2024-06-10 9/week @ 2024-06-17 18/week @ 2024-06-24

117 downloads per month

MIT license

10KB
64 lines

DMX512 support

The dmx crate supports DMX512 transmission in Rust through a trait, although transmission via UART on Linux is currently the only implementation available.

See the documentation for details.


lib.rs:

DMX512

The "Digital Multiplex" (DMX) protocol is used to control stage lighting and effects in large and small setups. It is electrically based on [RS485] (https://en.wikipedia.org/wiki/RS-485) and can (almost) easily be implemented on microcontrollers as well as soft real-time capable operating systems.

The protocol

The protocol itself assumes a single-master/multiple-slave system. The master periodically sends updates for up to 512 channels. Each one of these updates is called a DMX packet, which consists of a start code and any number of channels, in-order starting from channel 1. Packets can contain less than 512 channels, but must always start at 1 and progress in order.

Channels are byte values ranging from 0 to 255. For most channels these are intensity values, with 0 being "off" and 255 "full brightness". However other functions may be connected to a channel, such as selecting a blink sequence or setting a servo position.

Technical details

DMX is transmitted using serial protocol at the unusual bitrate of 250,000 baud, with no parity and two stop bits.

To begin a transmission, a sender must first pull the line low to send a so called break, followed by pulling it high to send a mark. The duration of this break is fairly long, as is the mark, both being far longer than the time it usually takes to submit a single byte.

After the break/mark-after-break sequence, regular transmission begins at 250,000 baud by sending a single-byte start code. This start code is almost always 0xFF, unless special functions are used, which are vendor-specific.

Right after the start code, any number of channels may be transmitted.

Refresh rate

The refresh rate depends on the number of channels transmitted. For the full 512 channels, the maximum achievable standard-compliant refresh rate is about 44 frames per second. If less than 512 channels are sent inside a packet, higher refresh rate are possible.

It should be noted that there is a minimum time between breaks (and therefore DMX packets) of 1204 microseconds, theoretically capping the refresh rate at about 830 updates per second.

DMX is usually meant to be sent continuously, with at least one update per second. A lot of devices will switch off if intervals become too large.

More information

The [DMX512-A standard] (http://tsp.esta.org/tsp/documents/docs/E1-11_2008R2013.pdf) contains the detailed specification.

Implementations

Currently, only an implementation using Linux serial devices is available. Connecting a UART to an RS485 transceiver is enough to get this working. The implementation is not 100% optimal for DMX: As most Linux kernels are not real-time capable, perfectly stable frame rates are not always achievable. However, the DMX protocol is fairly tolerant of loose timing.

The UARTs must support non-standard baudrates and reasonably fast baud-rate switching. Sending a break is done by switch to a slow baud-rate, sending a single 0x00 byte, then waiting a bit and switching back to 250,000 baud.

Example

The interface is fairly simple to use:

   use dmx::{self, DmxTransmitter};
   use std::{thread, time};

   let mut dmx_port = dmx::open_serial("/dev/ttyS1").unwrap();

   // a typical 4-channel device, expecting RGBV values. this will set a
   // fairly bright yellow.
   let data = &[0xe4, 0xe4, 0x00, 0xca];

   loop {
       dmx_port.send_dmx_packet(data).unwrap();

       // repeat about every 51 ms. for more accurate frame timings,
       // consider using the ticktock crate.
       thread::sleep(time::Duration::new(0, 50_000_000));
   }

Dependencies

~195KB