TuX as LLG logo
Software
DMX4Linux
Driver Suite for Linux
csv2iif.pl suite
convert PayPal transactions to IIF, OFX, QIF
Hardware
DMX30 Interface
128Ch SPP
DMX43 Interface
2out 2in EPP
LED Hardware
for Linux and Windows
EPROM Sampler
for 8 bits of sound
Misc
CatWeasel
Linux drivers for MK3/4 PCI
pg_trompe
PostgreSQL replication
trycatch
C exception/signal handling lib
Patches
to various software
Tools
and small scripts
Docs
misc documents
Links
to lighting stuff
DMX4Linux 2.6 - A DMX device driver package for Linux
Home Installation Documentation Interfaces Coding

Coding

Accessing the DMX4Linux drivers is like accessing files (or most other drivers in the unix world). If you know how to work with files, programming for DMX4Linux should be easy. We have written some example programs that show how to do simple things.

  1. Writing to Universes
  2. Blocking Read
  3. Nonblocking Read
  4. Nonblocking Read with select
  5. DMXlib - supporting routines


The Filesystem interface

The Filesystem interface can be divided in two major parts. The first one goes thru the special file /dev/dmx,/dev/dmxin, Currently all can be accessed in the same way.
/dev/dmx is for writing to the output universes and for readback from the output universe. /dev/dmxin is used for reading from the input universes, where a write to it is without any effect. Normaly they block when doing a read, but opening them with the flag O_NONBLOCK the read will return imediately.

Writing to Universes


/* This example shows a simple write to the dmx-outputs. */

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#include <dmx/dmx.h>

int main(int argc, const char **argv)
{
  int fd = open (DMXdev(&argc, argv), O_WRONLY);
  if (fd!=-1)
    {
      dmx_t buffer[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

      lseek (fd, 0, SEEK_SET);  /* set to the first channel */
      write (fd, buffer, sizeof(buffer)); /* write the 10 channels */
      /* now it points to the 11th channel */
      close (fd);
    }
  return 0;
}

The write in the example above does not block. It returns just after the data has been arrived in the driver. If you do a second write direcly after the first one that looks exactly the same it will write to channels 11 to 20 and the filepointer will point to channel 21 (the file pointer will have the value 20 which is the 21th channel).

Blocking Read

Writing to the universes for setting channel values is the most popular case :-) but sometimes you want to read from an input universe or even from an output universe. A blocking variant of that is shown in the example below.


/* This example shows a simple blocking read. */

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#include <dmx/dmx.h>

int main (int argc, const char **argv)
{
  const char *dmxname = DMXINdev(&argc, argv);
  int fd = open (dmxname, O_RDONLY);
  if (fd!=-1)
    {
      int i, n;
      dmx_t buffer[10];

      lseek (fd, 0, SEEK_SET);  /* set to the first channel */
      n=read (fd, buffer, sizeof(buffer)); /* read up to 10 channels */

      if (n>0)
        for (i=0; i<n; i++)
          printf ("channel %d has value %d\n", i+1, buffer[i]);
      else
        printf ("Error %d while reading %s\n", n, dmxname);
      close (fd);
    }
  return 0;
}

The read in the example blocks and returns after a write to one of the channels 1 to 10 has been made. It returns the number of channels that actualy has been read. The only case where you will get less channels than requested currently is if you try to read past the last universe.

Nonblocking Read

If you don't want to know when values have changed but want to get the current state of the input or output for example to set some sliders or to capture the current state you have to do a non-blocking read. Therefore it is nessesary to add the flag O_NONBLOCK to the open systemcall. The example below captures 200 channels and displays them in a tabular like form.


/* This example shows a non-blocking read from the dmx-output. */

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <dmx/dmx.h>

int main (int argc, const char **argv)
{
  const char *dmxname = DMXdev(&argc, argv);
  int fd = open (dmxname, O_RDONLY | O_NONBLOCK);
  if (fd!=-1)
    {
      int  i=0;

      lseek (fd, 0, SEEK_SET);  /* set to the first channel */

      while (i<200)
        {
          int j;
          dmx_t buffer[20];
          int n=read (fd, buffer, sizeof(buffer));
          if (n<=0)
            {
              printf ("error %d while reading %s\n", n, dmxname);
              close (fd);
	      return 1;
            }

          printf ("%d..%d:", i, i+n);
          for (j=0; j<n; j++)
            printf (" %03d", buffer[i+j]);
          printf ("\n");

          i += n;
        }
      close (fd);
    }
  else
    printf ("Error while opening %s\n", dmxname);
  return 0;
}

Nonblocking Read with select

There may be times you want to read more than one files. May be you would like to read from a socket and write that data to a dmx-output or so. Then you have to use threads or use the select function. Below is an example how to use the select. The example reads from an input, does a patch and writes them back to the output. It swaps each even channel with the next odd channel.


/* this example shows a a non-blocking read trigered by a select. */

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>

#include <dmx/dmx.h>

int dmxin=-1,
    dmxout=-1;

void exit_daemon (int sig)
{
  exit(0);
}

void close_files(void)
{
  if (dmxin)
    close(dmxin);
  if (dmxout)
    close(dmxout);
}

int main(int argc, const char **argv)
{
  dmx_t dmxbuffer[512];

  dmxout = open (DMXdev(&argc, argv), O_WRONLY);
  dmxin  = open (DMXINdev(&argc, argv), O_RDONLY | O_NONBLOCK);

  if (dmxout==-1 || dmxin==-1)
    exit(0);

  signal (SIGKILL, exit_daemon);
  atexit (close_files);

  while (1)
    {
      int n;
      fd_set readset;

      FD_ZERO(&readset);
      FD_SET(dmxin, &readset);
      FD_SET(0, &readset);

      n = select (dmxin+1, &readset, NULL, NULL, NULL);
      if (n>0)
        {
          if (FD_ISSET(dmxin, &readset))
            {
              int i;

              lseek (dmxin, 0, SEEK_SET);
              n=read (dmxin, dmxbuffer, sizeof(dmxbuffer));
              for (i=0; i<512; i+=2)
                {
                  int c = dmxbuffer[i];
                  dmxbuffer[i] = dmxbuffer[i+1];
                  dmxbuffer[i+1] = c;
                }
              lseek (dmxout, 0, SEEK_SET);
              write (dmxout, dmxbuffer, sizeof(dmxbuffer));
            }

          /* exit after the user presses return */
          if (FD_ISSET(0, &readset))
          {
            exit(0);
          }
        }
    }
}



The DMXlib

Some common used functionality for DMX/Lighting applications is collected in the DMXlib. You have already seen the function call DMXdev() in the examples above that retrieves the DMX device filename from the command line, environment or the default places.
The documentation for DMXlib is autogenerated with Doxygen. To use DMXlib include the header file dmx/dmx.h and link your application with -ldmx.


Search:
https://llg.cubic.org/dmx4linux © 2001-2024 by Dirk Jagdmann and Michael Stickel