For those who need to do custom interfacing with the Programmer software, the built in UDP server- is a good choice in some cases. While the UDP server lies at a lower level than the HTTP server, it does have the advantage of being quite a bit faster. I’ve found it useful particularly when I needed to create a custom drag and drop interface for a client who wanted building staff, untrained in any sort of computerized lighting system, to be able to program custom shows on a regular basis.
The downside, as you already know if you are familiar with UDP, is that unlike TCP (which HTTP uses) is connectionless and there is no guarantee that the data is being received. While TCP connections return an error if the data is not properly received, according to the UDP protocol, the data is sent out and there is no built-in checks that anyone is even listening for it.
A good metaphor for a TCP connection is a phone call… you dial a number and you either have the conversation you expected to have or you gett an error (“This number has been disconnected”, “Sorry, wrong number”, etc) where as a UDP connection is more like a radio station. You broadcast your message, but even if no one is tuned into your station, there is no way to know inherently whether your message is received (although you could, say, ask for someone who is listening to call in and let you know they hear you.
Without further adeiu, here are instructions for the method I implemented… you can obviously adapt it to suite your situation, but this should be able to give you a foundation:
First, we need to set up a generic UDP server device in your show file, so
- Open the device manager by clicking .
- Add a new device by clicking .
- Select “Terminals and Miscellaneous > UDP Generic” and click ADD.
- In the configuration window, select the network adapter you’d like to bind to and an available port.
- Once you’ve chosen all the desired settings, click OK
You should now have a UDP device ready to go. Now we have to create an e:script macro, which we will name UDP. I’ll give you the code to copy and paste first, and explain afterward. If you need an intro/refresher on e:script, you can read this tutorial:
// udp script comment
int sendport = 9001;
inBob = BobAllocate(1500);
outBob = BobAllocate(1500);
// Handles an incoming UDP packet
function OnUdp(int nDriverHandle)
// Clear the UDP input block
// Copy UDP backet into a Binary Object Block
nLen = ReceiveFrom(nDriverHandle, inBob, sIpAddress, nPort);
// Exit if the packet is empty
if (nLen <= 0)
// Parse out the 2 byte command and the parameter
command = BobGetString(inBob, 0, 3);
param = BobGetString(inBob, 2, 255-3);
// Send an acknowladgement for a CHECK RESPONSE message
msg = "ACK";
// Turn blind mode on or off
// Play specified cuelist
// Send a UDP message to sIpAddress on sendport, message is msg
function sendMessage(int nHandle)
BobSetString(outBob, 0,255, msg);
SendTo(nHandle, outBob, strlen(msg), sIpAddress, sendport);
This script takes advantage of e:scripts ability to run the script in the background. The first thing you’ll notices is the “RegisterEvent” command, which tells the programmer to call a function called “OnUDP” every time a UDP packet is received. After that there is a list of variables that are created for later use. You’ll need to change the “sendport” variable to match the port number that your client is listening on.
After the variables are created, thee is a “Suspend” Command which works in conjunction with the “RegisterEvent” command. The “RegisterEvent” tells the software where to send information when a particular event happens, while the “Suspend” command tells the software that you have finished setting up all the variables and such that you need and that control can return back to normal until the registered event can take place.
Most programs use a size of 1500 bytes for the payload of a UDP packet, and this is what I used in my case. A BOB (binary object block) was created to hold the data from the packet after it is received. A BOB is simply a chunk of memory that is set aside for use in your script. Each time a UDP packet is received, the BOB named inBob is cleared using the “BobSetRange” command to ensure that no data from the previous packet remains to taint this packet. After the BOB is cleared, the “ReceiveFrom” command is called, which reads the most recent UDP packet and places the data into “inBob”. It also sets the “sIpAddress” and “nPort” variables, corresponding to the IP addressA unique network address that consists of four numbers separated by periods such as 192.168.123.1 (which happens to be the default address for all e:cue equipment). and Port of the sender. It also returns the length of the packet, which is useful information to know.
After checking to ensure that the packet is not empty, the packet gets broken into components: the “command”, which is a consists of a 2 byte ASCII code and the “parameter” (param). The command specifies the action being requested, and the parameter contains any information needed to execute that action (such as a cue number or cuelist number). This is done using the “BobGetString” command.
After the packet is split up into the command and parameter, you simply use an “if” statement for each command you’re defining to see if that command has been sent, and then perform the specified action within the “if” statement’s code block. I left a few examples in the code. Parameters are always passed as ASCII, but the value of a number passed can be retrieved using the “val” statement, an example of which can be seen in the “BL” command which turns blind mode on or off. The client will send either “BL1” or “BL0”, it reads BL as the command and then either 0 or 1 as the parameter. The parameter is converted to an integer and then used in the “SetSwitchState” e:script command, which sets the state of blind mode. The PL command uses the same logic, but is used to play the cuelist specified in the parameter.
The last peice of the puzzle deals with the weakness that I talked about earlier. Since UDP doesn’t guarantee that there is anyone out there listening, I created a “heartbeat” system, in which the client can periodically send out a request for a response. In this case, the request comes in the form of a “CS” (check server”) command. When it is received it sends back a UDP packet containing the string “ACK” (acknowledge). This allows the client to ensure that the server is there to process its requests. This is a simple solution that still doesn’t guarantee any given packet was being received, but it provided enough security on the installation I designed this system for, which was running on a contained network with very little traffic. For higher reliability you could certainly design an algorithm that, for example, responds to every command with a check-sum that verifies that exactly the right command was received.
In order to start listening to for UDP packets the script must be started. You can do this manually while you are testing, but should be automated with an “On Initialization” trigger so that it starts as soon as the show file is loaded.
The script I’ve put on here is a pared down version of what was created for a specific situation. You may certainly use it as a base for your needs, but you should most certainly adapt it to suit the particular requirement you are using it for. Over a small local network this works great, but I would definitely recommend adding more error checking for larger networks or use over the internet.