January 1

Using OpenDMX in Linux

Enttec makes a handy little USB to DMX converter called OpenDMX. (DMX is the standard theatrical lighting control protocol – a serial protocol where up to 512 lights are daisy chained together). Several people have made Linux kernel drivers for this device – for example: the DMX4Linux project and Erwin Rol – however, at the time I got one of these dongles, they either didn’t work with the 2.6.x kernels or required compiling a kernel module (irritating when apt-get keep installing new ones requiring a module recompile…). So, I set about using another approach – using just the stock Linux serial drivers.

The OpenDMX device actually uses a standard FTDI USB to Serial IC that is well supported by Linux. The main tricky bit is persuading Linux to use the unusual baud rate used by DMX (250Kbits/sec). Handily recent linux kernels (the earliest I’ve tried is 2.6.17) allow you to set the data rate of a serial port to the required value.

The second tricky bit is that DMX requires that the lighting data is sent out continuously. The OpenDMX has no data buffer of it’s own so it relies on the PC software to keep spitting out all of the DMX data. I knocked together a crude daemon that memory maps a file that stores the lighting levels and keeps spitting the values out to the OpenDMX device.

Here it is the code – admittedly lacking error checking, or configuration parameters – but, you get the idea:

 * $Id: dmx_server.cpp,v 1.2 2008/10/04 17:05:22 anthony Exp $

using namespace std;

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <iostream>
#include <sys/mman.h>

#include <termios.h>
#include <linux/serial.h>
#include <termio.h>

#define DMXDEVICE "/dev/ttyUSB0"

int main(int argc, char* argv[])
	int mcr=0;
	struct termios newtio;
	struct serial_struct advsettings;
	unsigned char *buffer;

	int res;
	int fd;
	int statefd;
	cout << "Opening state file..." << endl;
	cout << "mmap'ing state file..." << endl;
	buffer = static_cast<unsigned char *>(mmap(0, 513, PROT_READ, MAP_SHARED, statefd, 0));

	cout << "Opening output device... " << endl;
	// Open write-only, not controlling TTY
        if (fd < 0) {

	// Now setup serial port as required:
	// First setup custom baud rate
        printf("Before: Baudbase: %i Divisor: %i \n",advsettings.baud_base,advsettings.custom_divisor);

	advsettings.flags = (advsettings.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
	advsettings.custom_divisor = advsettings.baud_base / 250000;

	printf("After: Baudbase: %i Divisor: %i \n",advsettings.baud_base,advsettings.custom_divisor);


	// First zero all fields in struct:
	bzero(&newtio, sizeof(newtio));

	// 8bit, 2stopbits, ignore modem signals
	newtio.c_cflag = CS8 | CSTOPB | CLOCAL | B38400;


	// Set RTS High:
	ioctl(fd, TIOCMGET, &mcr);
        mcr &= ~TIOCM_RTS;
        ioctl(fd, TIOCMSET, &mcr);

	cout << "Running." << endl;
	while(1) {
		// Wait for TX buffer to empty:

		// 88us break

		res = write(fd, buffer, 513);

		if (res < 0){



	munmap(buffer, 513);

	return 0;

Copyright 2020. All rights reserved.

Posted January 1, 2009 by anthony in category "Open-source software


  1. By Steph Reed on

    Thanks loads for this! After problems with both the Erwinrol and DMX4Linux drivers I actually came up with the same idea.. it’s great someone’s already done it!

  2. By Peter on

    Dear Anthony,
    can I use your Code as open-source in my DMX project? I am planning to extend it a little more, add a socket for network control.

  3. By ajgreen (Post author) on

    Sure Peter, you are welcome to use the code on this page in your open-source project. If you release it on the web, let me know and I’ll put up a link.


Leave a Reply

Your email address will not be published. Required fields are marked *