This is the JNIOR Knowledge-base.  Here you will find a collection of articles that will help you learn or trouble shoot the JNIOR.

If you find there is information we should add then please get in touch with us.

Name Version Release Date Size MD5
JANOS - UPD v2.3 Feb 03 2023 954.6 KB a1b9bcde0a4768bfdcfbc11704c06634
Series 4 All-In-One Update Project v2.3 Feb 03 2023 1.8 MB 9308e8af6b59c480a3a75ff43158ab40
Core JANOS Update Project v2.3 Feb 03 2023 1.1 MB 46faa801012faeae4f4b1310e18706c8
JANOS Release Notes v2.3 Jan 25 2023 447.5 KB eee5c466e41038127aa4a37f5c67a294

Models

JNIOR, a Network I/O Resource utilizing the JAVA™ platform, is a cost effective automation controller that communicates over a network using TCP/IP via an Ethernet Port or via its serial port. The JNIOR is a general-purpose automation controller and I/O device that is easily configurable for controlling and monitoring your equipment or process via the built-in web pages, by enabling the built-in software applications, interaction with an application running on another computer, or by adding your own applications.

Currently there are 4 different Models of the Series 4 JNIOR, each very similar to one another with a few differences.

JNIOR Model Catalog Number I/O Serial/DMX Ports
410  JNR-100-004B 8 inputs 8 outputs 1 AUX Port, 1 COM Port
(COM Port RS-485/RS-232 compatible)
412  JNR-200-004B 4 inputs 12 outputs 1 AUX Port, 1 COM Port
(COM Port RS-232 compatible)
414  JNR-300-004B 12 inputs 4 outputs 1 AUX Port, 1 COM Port
(COM Port RS-232 compatible)
412DMX  JNR-200-004D 4 inputs 12 outputs 1 DMX 5-pin Output Port (allows DMX control)
1 COM Port (COM Port RS-232 compatible)
Each JNIOR Model links to their web page, where more detailed information can be found for them (like their data sheets)

Powering Your JNIOR

The JNIOR uses a 2-piece terminal connector system for all power and I/O wiring connections allowing for easy installation and/or removal of the JNIOR.  Additional installation information and drawings are provided on our website.

The JNIOR can be powered with 12 to 24 volts AC or DC. An optional, wall transformer (AC power converter) for North American outlets is available from INTEG that can be used for converting 120/240 VAC to 12 VDC @ 1 amp. International models are also available as Euro and UK plugs.

The Power Connector is located along the upper left edge of the JNIOR. Note that this is a 4-pin connector. If numbered from one (1) through four (4) from left to right power is always connected to positions 2 and 3 (middle two connectors). The polarity is irrelevant although it is recommended that the positive (+) lead be connected to position 2.

The left two positions (1 & 2) are internally connected together, as are the right two positions (3 & 4). This is to facilitate the interconnection of the supplied power to other devices and circuits such as input or output devices. If you power the I/O circuits with your JNIOR power supply, please make sure the power supply is sized appropriately.

WARNING: Do not connect the transformer leads both to Positions 1 & 2 or both to positions 3 & 4. This will short the transformer and possibly damage it and/or the JNIOR. Always use a fused/protected power source.

When a proper power source is connected and turned on the leftmost LED adjacent to the power connector will glow BLUE continuously. The LED to the right may glow ORANGE for several seconds. This orange STATUS LED remains on through most of the JNIOR boot sequence. Later it will flash whenever an external connection is made to the JNIOR via the Ethernet port.

Wiring JNIOR I/O

JNIOR Inputs

The JNIOR is equipped with optically isolated digital inputs. Each digital input can accept AC or DC voltage sources in the 0 – 30 V range. An LED associated with each digital input displays the current electrical status of the input (off or on). Isolation of each digital input allows you to connect input signals to different voltage sources without the addition of isolation devices. The input voltage must be greater than 2 VDC for the input to register as “on” and then less than 1 VDC to register as “off”. A typical connection would be as follows:

JNIOR Outputs

The JNIOR is equipped with Relay Outputs with most of them being a Form A SPST relay (1 Normally Open Contact) and two of them being a Form C SPST relay (1 Normally Open Contact and 1 Normally Closed Contact – jumper selectable as to which one is available on the JNIOR terminals by removing the lid and changing the jumper setting. Normally Open is the default.) Each relay output is independent and isolated from the other relay output. Each relay contact rating is 1A @ 24VDC and the voltage source must be in the range of 5 – 30V AC or DC. A typical connection would be configured as follows:

Setting the JNIOR’s IP

Starting with JANOS 2.0, the JNIOR is shipped with DHCP enabled for dynamic setting of the JNIOR IP address by a network server. More information is here on finding your JNIOR’s IP address.

If DHCP does not work on your network, then there are two ways to configure your JNIOR IP settings:

  • By using the JNIOR Support Tool (Beacon tab) provided on our website at the following link: https://www.integpg.com/jnior-support-tool/. You can use JNIOR Support Tool to configure the JNIOR’s IP by right clicking the JNIOR, and selecting Configure -> IP Configuration. A dialog will appear to edit the JNIOR’s IP after that.

 

 

  • Via the RS232 Serial Port and a command line window available via the JNIOR Support Tool: http://www.integpg.com/support/jnior/. You can use this command line to set the IP by doing the ipconfig -a IP -m MASK command, replacing ‘IP’ with the IP you want for the JNIOR, and ‘MASK’ with the subnet you want for the JNIOR. For example, on a private network the IP address may be something like 192.168.1.10. A common mask would be 255.255.255.0. The command would then look as follows:

 

ipconfig -a 192.168.1.10 -m 255.255.255.0

JNIOR Web Pages

The JNIOR Series 4 contains the JNIOR web page which is a web page used for a variety of functions including monitoring and manually controlling the I/O, changing various configuration items, opening a Telnet/Console session and several other functions. The JNIOR web page works with Microsoft Internet Explorer, Google Chrome, Fire Fox and other browsers.

PLEASE NOTE: The dynamic web page requires a ‘modern web browser’ which is defined as Internet Explorer 10 or greater, Google Chrome or Firefox.

You can launch the JNIOR web page from the Beacon tab in the JNIOR Support Tool by right-clicking on your JNIOR and going to Tools – Open web page or by manually entering the JNIOR IP address in your browser address line. To manually launch the JNIOR web page, open your browser and in the address line of the browser type your JNIOR IP address or serial number, for example: http://10.0.0.146 or jr616010235

After the JNIOR web page is loaded, the user is asked to login with a valid username and password. You can use the default username (jnior) and default password (jnior).

The JNIOR web page will be launched in your browser as shown below.

DMX requires RS485 communication at 500K baud.  The JNIOR 412 DMX handles this inherently.  The JNIOR 410 has the ability to handle RS485.  An additional application must be loaded to get the DMX data to be streamed out the AUX port.  You can read about using the JNIOR 410 and a 412 DMX Alternative.  The downside of this is that there is additional overhead on the JNIOR and that the AUX port is not properly isolated.  In most cases the lack of isolation is not an issue but it could be given certain circumstances.

At the time of writing this article, in 2022, we have found it hard to acquire the components needed to build the 412DMX unit due to supply chain issues and chip shortages.

While using the 410 as a DMX alternative would work, some people like the IO mix on the 412.  So we decided to look at what it would take to use the 412 as a DMX alternative.  It turns out that an RS232 to RS485 adapter with a NULL modem will do the trick.  Here are links to the components that we tested an commanded DMX fixtures with here in the office.

DTECH RS232 to RS485 / RS422 Serial Communication Data Converter Adapter Mini-Size

DB9 Null Modem Adapter Male to Male

The 410 has 8 inputs and 8 outputs, the 412 and 412DMX have 4 inputs and 12 outputs, and the 414 has 12 inputs and 4 outputs. Each digital input can accept AC or DC voltage sources in the 0 – 30 V range. The input voltage must be greater than 2 VDC for the input to register as “on” and then less than 1 VDC to register as “off”. The JNIOR uses a 2-piece terminal connector system for all power and I/O wiring connections allowing for easy installation and/or removal of the JNIOR. Digital Inputs are Optically Isolated.  

Controlling Digital Inputs

When controlling the JNIOR’s I/O, the JANOS class can be used to get/manipulate their statuses. In the following example the JANOS class is used to invert an input and print the input state mask, manipulate an input counter, and check an input’s usage meter.

package inputcontrolexample;

import com.integpg.system.JANOS;
import java.io.IOException;
import static java.lang.Thread.sleep;

public class InputControlExample {
    
    public static void main(String[] args) throws IOException, InterruptedException {
        
        //Use input conditioning to invert input 1's status
        JANOS.setInputConditioning(0, JANOS.INPUT_COND_INVERT);
        //print out the current mask of inputs that are on.
        System.out.println(String.format("current input states are %d\n", JANOS.getInputStates()));
        sleep(3000);
        //Turn off input 1's inversion
        JANOS.setInputConditioning(0, JANOS.INPUT_COND_NONE);
        sleep(1000);
        //Check and manipulate input 1 counter
        System.out.println(String.format("Current counter value for input 1: %d\n", JANOS.getInputCounter(0)));
        JANOS.incInputCounter(0);
        System.out.println(String.format("Current counter value for input 1 after being incremented: %d\n", JANOS.getInputCounter(0)));
        JANOS.setInputCounter(0, 100);
        System.out.println(String.format("Current counter value for input 1 after being set to 100: %d\n", JANOS.getInputCounter(0)));
        //print out usage meter value for input 1, values may change for different model JNIOR:
        System.out.println(String.format("Current usage meter value for input 1: %d\n", JANOS.getUsageMeter(0)));
        
    }

}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it displays different data about the inputs at the time of the application running.

Getting Inputs from the IO Log

Another way to interact with the I/O on the JNIOR is via the Iolog Monitor. The Iolog Monitor is an object that can be checked for I/O events that have occurred on the JNIOR. There is the IoEvent class and Iolog class. An IoEvent is when an input or output state changed on the JNIOR, and the Iolog is an object that contains all the IoEvents from a certain timestamp. The example below inverts an input, and then shows how the Iolog has recorded that input pulse as an IoEvent.

package inputcontrolexample2;

import com.integpg.system.IoEvent;
import com.integpg.system.Iolog;
import com.integpg.system.JANOS;
import java.io.IOException;
import static java.lang.Thread.sleep;
import java.text.SimpleDateFormat;

public class InputControlExample2 {

    public static void main(String[] args) throws IOException, InterruptedException {
        
        //gets the current time as a long.
        long now = System.currentTimeMillis();
        
        JANOS.setRegistryString("IO/Inputs/din1/Inversion", "enabled");
        sleep(4000);
        JANOS.setRegistryString("IO/Inputs/din1/Inversion", "disabled");
        
        //iolog object for getting I/O events
        //refresh Iolog so getting output events from it are only output evetns
        //from when this application start AKA the outputs we just pulsed. 
        Iolog iolog = new Iolog();
        iolog.refresh(now);
        IoEvent[] events = iolog.getInputEvents();

        //for each output event in the iolog, print the output states at that
        //time and the timestamp it occured.
        if (events.length > 0) {
            //SimpleDateFormat object that formats the timestamps of the IO events
            //into a caladender date and time.
            SimpleDateFormat date = new SimpleDateFormat("MM/dd/yy HH:mm:ss.SSS");
            for (int i = iolog.getInputEvents().length - 1; i >= 0; i--) {
                System.out.println(String.format("States: %d @ %s\n",
                        events[i].states, date.format(events[i].timestamp)));
            }
        } else {
            System.out.println("no input events...\n");
        }
        
    }
    
}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it recorded the input change where input 1 turned on and again when it turned back off.

When creating an application, being able to send emails from it may be something a User wants to do. JNIORs have email blocks in their configuration that can be  configured to send emails.

Setting Up JNIOR Email

To properly setup an email for the JNIOR to use, you’ll want to use the JNIOR’s Web UI and navigate to the Email Account section under Configuration. Here you’ll want to include the Mail Server, From Address, and SMTP Username your JNIOR will use to send the email. These are required in order to send emails from the JNIOR.

Next, in the Network section you’ll want to make sure you have a DNS Address declared. For our examples we use 8.8.8.8, which is Google’s.

Lastly, we’ll want to make sure we give the address we are sending to to the Mail-Profiles section. Only a ToAddress is needed, but additional information can be entered to be used as a default. This is used for the JANOS.sendmail() class.

Series 4 JNIOR’s have a file directory that can be interacted with via a command line connection or from the Web UI. Being able to interact with the file directory and read/write files to it can be a useful tool when creating applications, from recording versioning numbers to writing data to reference later. Below is a small example below that writes and then reads to a file.

Directories and File Interaction

To start a file object is declared with the directory of the temp folder and the name of the file we are creating which is “test.log”. We also create another file object called directory and we are going to use this to display all the files located under the flash directory in the JNIOR by. We get the files in the flash directory by assigning the value ‘/flash’ to it, and then using the .list() function we can return a string array of all the files under that directory. We declare a local string array called files and populate it with the file names we just got. Then we go through and print out the name of each one. After this we declare a BufferedWriter to create a FileWriter. The FileWriter is then used to write a string to the test.log file we just declared. Next a BufferedReader is declared to create a FileReader. The FileReader is used to the read whatever data is on the file as a string, and since we just wrote to it, it will print out what we’ve writer to the file.

package filesystemexample;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileSystemExample {

    public static void main(String[] args) {

        File file = new File("/temp/test.log");
        File directory = new File("/flash");

        String[] files = directory.list();
        
        System.out.println("Listing files in the Flash folder.\n");
        
        for (int i = 0; i < files.length; i++) {
            System.out.println(files[i]);
        }

        System.out.println(String.format("\nPath for sample file is: %s", file.getAbsolutePath()));

        // Write content to the file
        try ( BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) {
            String fileContent = "This is a sample text.";
            bufferedWriter.write(fileContent);
        } catch (IOException e) {
            // Exception handling
        }

        // Read content from the file
        try ( BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
            String line = bufferedReader.readLine();
            while (line != null) {
                System.out.println(line);
                line = bufferedReader.readLine();
            }
        } catch (FileNotFoundException e) {
            // Exception handling
        } catch (IOException e) {
            // Exception handling
        }
    }
}

Filing Example

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it, application runs and prints out the text that was written to the file. You can also see the test.log file is created in the temp folder.

The registry on the JNIOR is what defines how it is configured. Registry keys hold information that persist past reboots, allowing applications to set them and save settings that have been created. This information can be connection settings, device identification, versioning, etc. Below is a quick example that prints out a specific registry key’s information, and then prompts the user to enter a new value for it. 

In this example the registry key being referenced on the JNIOR called AppData/RegistyTest. This registry key doesn’t exist the first time the application is run, and it will print out “Registry not created yet”. It will then prompt the user to enter a value for it, and once that’s done it will exit the application. Running the application a second time will show that the value entered for the registry key will now be what’s displayed for its value.

package registryexample;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import com.integpg.system.JANOS;
import java.io.IOException;

public class RegistryExample {

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String stringRegistry = JANOS.getRegistryString("AppData/RegistryTest", "Registry not created yet.");
        System.out.println(String.format("Current registry value was: %s", stringRegistry));
        System.out.print("Enter new string value for registry: ");
        String registryValue = br.readLine();
        JANOS.setRegistryString("AppData/RegistryTest", registryValue);
        System.out.println("Exiting");
    }

}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it, the registry key report empty the first the application is run, and the second time its run the registry key contains the value enter for it the first time it was run.

Here shows the registry key we created in the Registry Tab of the JNIOR Web UI.

There could be a want for an application that performs different functionality, completing multiple operations at the same time. The JNIOR accomplishes this with threading. A thread is a sequence of instructions within a program that can be executed independently of other code. The JNIOR is able to handle threading via the default JAVA library. Below are two quick examples of threading, with one of them using synchronization. 

Non-Synchronized Threading

In this first example, there is a main method that creates two threads, each supplying it an array of words that will be used to create sentences and print them out. Each new thread calls a function called slowStringBuffer, taking the words in their string array’s they’ve been supplied and adding them to the string buffer in that function. Since the threads run at the same time, they add their words to the string buffer simultaneously. This results in nonsense being printed out for the sentences, showing that synchronization in our next example is useful in avoiding this issue.

package ThreadingExample;

public class ThreadingExample {

    private static final StringBuffer STRING_BUFFER = new StringBuffer();



    public static void main(String[] args) {
        newThread(new String[]{ "The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog" });
        newThread(new String[]{ "I", "scream,", "you", "scream,", "we", "all", "scream", "for", "ice", "cream" });
    }



    private static void newThread(String[] wordArray) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    slowStringBufffer(wordArray);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }).start();
    }



    /**
     * A perfect example of needing to synchronize code is when a shared resource or object is
     * being used. Here we will use a shared StringBuffer object. Without synchronization the
     * words get added to the shared StringBuffer at the same time and are all mixed by the time we
     * print it out. If we simply synchronize this method then the sentences are built one at a
     * time.
     *
     * @param wordArray
     */
    private static void slowStringBuffer(String[] wordArray) throws InterruptedException {
        
        // reset the length
        STRING_BUFFER.setLength(0);

        // add each word to the string buffer.  we will use a small delay to simulate the need 
        // for synchronization
        for (String word : wordArray) {
            if (0 != STRING_BUFFER.length()) STRING_BUFFER.append(" ");
            STRING_BUFFER.append(word);

            Thread.sleep(10);
        }

        // finally we add a period and print out our sentence
        STRING_BUFFER.append(".");
        System.out.println(STRING_BUFFER.toString());
    }

}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it, the threads compete against each other to build their sentences, resulting in nonsense being printed out.

Synchronized Threading

In this second example, the only change that is made is that the slowStringBuffer function is made synchronized. This results in one thread taking control first, making sure it prints out its sentence completely before the next thread can start its sentence. This results in two complete sentences being generated.

package SynchronizedThreadingExample;

public class SynchronizedThreadingExample {

    private static final StringBuffer STRING_BUFFER = new StringBuffer();



    public static void main(String[] args) {
        newThread(new String[]{ "The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog" });
        newThread(new String[]{ "I", "scream,", "you", "scream,", "we", "all", "scream", "for", "ice", "cream" });
    }



    private static void newThread(String[] wordArray) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    slowStringBuffer(wordArray);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }).start();
    }



    /**
     * A perfect example of needing to synchronize code is when a shared resource or object is
     * being used. Here we will use a shared StringBuffer object. Without synchronization the
     * words get added to the shared StringBuffer at the same time and are all mixed by the time we
     * print it out. If we simply synchronize this method then the sentences are built one at a
     * time.
     *
     * @param wordArray
     */
    private static synchronized void slowStringBuffer(String[] wordArray) throws InterruptedException {

        // reset the length
        STRING_BUFFER.setLength(0);

        // add each word to the string buffer.  we will use a small delay to simulate the need 
        // for synchronization
        for (String word : wordArray) {
            if (0 != STRING_BUFFER.length()) STRING_BUFFER.append(" ");
            STRING_BUFFER.append(word);

            Thread.sleep(10);
        }

        // finally we add a period and print out our sentence
        STRING_BUFFER.append(".");
        System.out.println(STRING_BUFFER.toString());
    }

}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. In this example two complete sentences are formed and printed.

JNIORs can connect with other devices via Ethernet connections. Defining a port and IP, the JNIOR can listen or send to a device with those Ethernet settings using the IO and Net classes of the JANOS Runtime library. Receiving data uses a DataInputStream and sending data uses a DataOutputStream. 

TCP

Below is a very short example, that shows a quick reference to the IO class to create a socket to open a DataOutputStream. Once that is open I can send a message to an external device. The socket only requires the IP address and the port number. In this example the IP is 10.0.0.17 and the port is 9222. Once the DataOutputStream is created using the socket, I send a string out it. I use a TCP server I created that listens on that IP and port number to see if it receives the data sent.

package ethernetexample;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class TCPSocketExample {

    //declare output stream and socket objects for an ethernet connection
    public static OutputStream outputStream = null;
    public static Socket socket = null;

    public static void main(String[] args) throws IOException {

        //set IP and port number
        int portOut = 9222;
        String IP = "10.0.0.17";

        try {
            //set socket and then create outputstream with socket
            socket = new Socket(IP, portOut);
            outputStream = new DataOutputStream(socket.getOutputStream());
        } catch (NullPointerException e) {
        }
        
        try {
            //send message out the outputstream
            outputStream.write("This was sent from an ethernet connection.".getBytes());
            outputStream.flush();
        } catch (NullPointerException e) {}
        

    }

}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. After it has successfully run, I check my TCP server and see that the information was successfully received.

UDP

Another example of Ethernet control uses a UDP connection versus a TCP connection. Another example is below, using the Datagram Socket and Packet classes from the Java.net package. This creates a UDP connection from the JNIOR to any UDP server listening and sends it a string. 

package ethernetexample2;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class UDPExample {

    public static DatagramSocket udpsocket;
    public static InetAddress address;
    public static byte[] buf;
    
    public static void main(String[] args) throws UnknownHostException, IOException {
        
    udpsocket = new DatagramSocket();
    address = InetAddress.getByName("10.0.0.17");

       try {
        buf = "This was sent from a UDP connection.".getBytes();
        DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 9222);
        udpsocket.send(packet);
        } catch (NullPointerException e) {
        }
    }
    
}

Just like before, I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. After it has successfully run, I check a UDP server I created  and see that the information was successfully received.

Applications can log information they are generating into a .log file to view. This feature can be crucial to some users, letting them be able to monitor data that constantly needs supervision. Log files can roll over as well, which happens when a log file runs out of space. When this occurs, a new empty file with the same name is created to log more data, while the old file that has no more space gets a .bat extension added to the end of the file name. This allows for data to be retained longer before being overwritten. 

To use logging in a software application on the JNIOR, you will need to use the JANOS class of the JANOS runtime library. With it you can define a log file name and what you want to log to it. If the log file exists at the location you specify, it will add what enter to it. If the log file doesn’t exist, it will create the log file, and then log what you enter to it. Below is a short example of creating/adding to a log file that exists in the temp folder of the JNIOR.

package loggingexample;

import com.integpg.system.JANOS;

public class LoggingExample {

    public static void main(String[] args) {
        
        //log message to log file
        JANOS.logfile("/temp/loggingExample.log", "This will create a log in"
                + " the temp folder of the JNIOR called loggingExample");
        
    }
    
}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see after running it, going to the temp directory of the JNIOR shows the loggingExample.log file.

Series 4 JNIORs have a varying amount of inputs and outputs depending on what model you have. The 410 has 8 inputs and 8 outputs, the 412 and 412DMX have 4 inputs and 12 outputs, and the 414 has 12 inputs and 4 outputs. Each relay contact rating is 1A @ 24VDC and the voltage source must be in the range of 5 – 30V AC or DC. The JNIOR uses a 2-piece terminal connector system for all power and I/O wiring connections allowing for easy installation and/or removal of the JNIOR.

Controlling Relay Outputs

When controlling the JNIOR’s I/O, the JANOS class can be used to get/manipulate their statuses. In the following example the JANOS class is used to pulse outputs, get the output states mask, check the status of an output, and check an outputs usage meter.

package outputcontrolexample;

import com.integpg.system.JANOS;
import java.io.IOException;
import static java.lang.Thread.sleep;

public class OutputControlExample {
    
    public static void main(String[] args) throws IOException, InterruptedException {
        
        //Pulse output 1 for 3 seconds
        JANOS.setOutputPulsed(1, 1, 3000);
        sleep(4000);
        //Pulse output 2 and 3 for 3 seconds
        JANOS.setOutputPulsed(6, 6, 3000);
        //print out the current mask of outputs that are on.
        System.out.println(String.format("current output states are %d\n", JANOS.getOutputStates()));
        sleep(4000);
        //Check if output 1 is on
        System.out.println(String.format("Is output 1 on: %s\n", String.valueOf(JANOS.isOutputSet(0))));
        //print out usage meter value for output 1, values may change for different model JNIOR:
        System.out.println(String.format("Current usage meter value for output 1: %d\n", JANOS.getUsageMeter(8)));
        
    }

}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it displays different data about the outputs at the time of the application running.

Getting Outputs from the IO Log

Another way to interact with the I/O on the JNIOR is via the Iolog Monitor. The Iolog Monitor is an object that can be checked for I/O events that have occurred on the JNIOR. There is the IoEvent class and Iolog class. An IoEvent is when an input or output state changed on the JNIOR, and the Iolog is an object that contains all the IoEvents from a certain timestamp. The example below pulses an output, and then shows how the Iolog has recorded that output pulse as an IoEvent.

package outputcontrolexample2;

import com.integpg.system.IoEvent;
import com.integpg.system.Iolog;
import com.integpg.system.JANOS;
import java.io.IOException;
import static java.lang.Thread.sleep;
import java.text.SimpleDateFormat;

public class OutputControlExample2 {

    public static void main(String[] args) throws IOException, InterruptedException {
        
        //gets the current time as a long.
        long now = System.currentTimeMillis();
        
        JANOS.setOutputPulsed(8, 8, 3000);
        sleep(4000);
        
        //iolog object for getting I/O events
        //refresh Iolog so getting output events from it are only output evetns
        //from when this application start AKA the outputs we just pulsed. 
        Iolog iolog = new Iolog();
        iolog.refresh(now);
        IoEvent[] events = iolog.getOutputEvents();

        //for each output event in the iolog, print the output states at that
        //time and the timestamp it occured.
        if (events.length > 0) {
            //SimpleDateFormat object that formats the timestamps of the IO events
            //into a caladender date and time.
            SimpleDateFormat date = new SimpleDateFormat("MM/dd/yy HH:mm:ss.SSS");
            for (int i = iolog.getOutputEvents().length - 1; i >= 0; i--) {
                System.out.println(String.format("States: %d @ %s\n",
                        events[i].states, date.format(events[i].timestamp)));
            }
        } else {
            System.out.println("no output events...\n");
        }
        
    }
    
}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it recorded the output change where output 8 turned on and again when it turned back off.

While JNIOR 412DMX units may be unavailable, JNIOR 410s can be made to work as a substitute. Note that this does NOT work for JNIOR 412s and 414s, as 410s RS-485 compatibility is the reason why it can be used as a 412DMX substitute.

Cabling

When trying to connect to a 410 with DMX, the cabling will need to be corrected as you need to go from an AUX port to a male/female 5-pin XLR connector. By splicing into an existing DMX cable, you can attach a DB9 adapter with screw terminals to the end of the cable. It should look something like the picture below.

Here is the pin numbering for splicing the adapter on. Note the wire colors vary.

        Signal           XLR      DB-9 Male
--------------------  ---------  -----------
Signal Ground (GND)       1          5
Data (D-)                 2          3
Data (D+)                 3          7
Not Used (NC)            4,5     1,2,4,6,8,9

This cable allows the JNIOR to be a DMX FIXTURE. THE RESULTING DMX CONNECTION IS NOT ISOLATED. We recommend using an isolated power supply for the JNIOR and not sharing that voltage with other circuits. Take great care in making ground connections. Note that the JNIOR relay outputs are naturally isolated.

Aux Port Application

Below is an application you’ll need to update and install on the JNIOR. This is required for the JNIOR to interpret DMX communication on the JNIOR.

Name Version Release Date Size MD5
DmxPort for enabling DMX on 410 Mar 17 2021 3.5 KB 299c66717c03a9c9b702716d9d56d095

Serial Settings

The serial settings of the JNIOR need to be configured so the AUX port output doesn’t disrupt the DMX communications. Below are the settings you need to set for the AUX Port. This is located on the JNIOR\’s Webpage, in the Serial I/O section under the Configuration Tab.

Once the cabling has been created, the DMX Port application is on the JNIOR, and the Serial Settings have been set, DMX communication should be possible on the JNIOR 410.

If you have any questions about this, contact our support to get help with this setup using pure chat or our email: support@integpg.com.

The DMX application does not ship preinstalled. You MUST obtain the application from our website. There is a download on the website that will be opened in the JNIOR Support Tool and published to the JNIOR. This is called an Update Project.

Here are links to latest versions of the JNIOR Support Tool and the Cinema application. NOTE: The DMX link below is for new installations only. If you already have the DMX application on your JNIOR and only need to update to a newer version, visit our DMX page to download our other update project for DMX that isn’t for new installs.

Name Version Release Date Size MD5
JNIOR Support Tool v7.13 Aug 04 2022 10.4 MB fd24b3818ec6ad8e572b6c5131c94d09
DMX Application v3.5 Nov 12 2021 637.3 KB 19fe2244ff60d4e6d9807794abf9f431

After installing both the JNIOR Support Tool and the DMX Update Project, you’ll want to open the Support Tool and click on the Update Tab. Once there, the first thing you’ll want to do is select the Open Project button, and select the DMX Update Project you just downloaded. When you open the DMX Update Project in the Support Tool you will see the following.

DMX Update Project

In the DMX application you can create fixtures, scripts and triggers to control the 512 DMX channels for your external lighting device.

To update JANOS, the JNIOR Series 4 Operating System, you will need to do two things.

  1. Get the UPD file on the JNIOR in the /temp directory.
  2. Execute the jupdate command. To force the update to happen immediately upon entering this command we will type jrupdate -fup /temp/janos_filename.upd

The easierst way to update the unit remotely is using the DCP The DCP is most likely to be available on a remote JNIOR because it uses a single port for all of the features. Without the DCP you might need port 23 for telnet, port 21 for FTP commands and many other ports for FTP data.

If the DCP is available follow the this procedure.

  1. Once the DCP is open, navigate to the Console tab.
  2. Login to the command console.
  3. Drag and drop the JANOS .upd file into the console window. This automatically stores the file in the /temp directory.
  1. Issue the jrupdate command. Like above, t o force the update to happen immediately upon entering this command we will type jrupdate -fup /temp/janos_filename.upd

If the DCP is not available, you can also remotely update using the JrGet utility.

This post goes over an application that reads inputs being activated as a pattern using their state mask. However many times inputs are triggered within a certain amount of milliseconds between them, those inputs state masks are added to the pattern already there. This continues until there is an input not within the set amount of milliseconds. Then it prints the pattern and begins creating a new one.

Make sure to have properly setup the project before using this code, to learn how to setup a custom java application on the JNIOR, a link is here.

After setting up the project, it will require two files. This first one we create is called MultiplexSample, which calls the run function we will create in the second file.

//function runs the application
public class MultiplexSample {

    public static void main(String[] args) {
        
        InputMultiplexer inputMultiplex = new InputMultiplexer();
        inputMultiplex.run();
        
    }
    
}

After that we begin creating the second file called InputMultiplexer. The first thing we include in the project is the import statements. The two imports we use are for IoEvents and the Iolog. We will use these to get the input’s information and process them as patterns.

We then declare the global variables. The first one we declare is the _iolog object. The Iolog keeps track of all IoEvents, including inputs. We will use the IoEvents from the Iolog to grab the information of the inputs when they are activated.

After this is _eventCaptureTime which grabs the start of when the IoEvents are grabbed at the start of each loop through the application.

We then need a long value called _startOfPatternTime. This is the current time of each new input that comes in. We need this because the program loops every 500 seconds, and if 1 input happens right after the loop ends we’ll miss it. The _startOfPatternTime is subtracted from the _eventCaptureTime which helps us check if that input should keep the pattern going.

The _refreshTimestamp value helps us only grab new IoEvents from the Iolog by only grabbing events past its value.

Next is the IoEvent array _ioEvents which contains the inputs we are processing from the Iolog for the current pattern.

We then have the pattern value, which is the pattern we are constantly building from the IoEvents state mask.

Lastly is PATTERN_WINDOW_DURATION which is the value in milliseconds we are looking to see pass between inputs to determine if they are close enough to combine into a new pattern or process as separate ones.

import com.integpg.system.IoEvent;
import com.integpg.system.Iolog;

public class InputMultiplexer implements Runnable {

    //grabs the Iolog to get IoEvents
    private Iolog _iolog = new Iolog();
    //time of the first input to find the start of the input pattern
    private long _startOfPatternTime = 0;
    //time where Iolog is refreshed as to not look at old IoEvents
    private long _refreshTimestamp = _startOfPatternTime;
    //array of IoEvents to evaluate from the Iolog
    private IoEvent[] _ioEvents;
    //value for checking pattern has more IoEvents to process
    private long _eventCaptureTime = 0;
    //input pattern to log
    private int _pattern = 0;
    //duration between inputs required to continue a pattern
    private static final int PATTERN_WINDOW_DURATION = 100;

Next is the run function, which sets the _eventCaptureTime value, calls the other functions we are about to create, and permanently loops the program every 500 seconds. This makes it so the application is constantly checking the Iolog for new IoEvents.

    //function calls other functions to log input pattern in a infinite loop
    @Override
    public void run() {

        while (true) {

            _eventCaptureTime = System.currentTimeMillis();
            getIoEvents();

            lookForIoPattern();

            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {

            }

        }

    }

Next is the lookForIoPattern function. This function starts with a for loop that will go through all recent IoEvents from the Iolog and processes their states to begin creating a new pattern.

Next the IoEvent states and mask values have an & operation done to get which states have turned high. Next the _startOfPatternTime was set if this was the first input in the pattern. After that _startOfPatternTime would be compared with either the current IoEvent’s timestamp or the _eventCaptureTime value to determine if more inputs need to be added to the pattern. _startOfPatternTime is compared to currentIoEvent’s timestamp to check if timestamps of inputs were within PATTERN_WINDOW_DURATION milliseconds of each other, which in this example is 100 milliseconds. If the 500 milliseconds that the program is looping in ends as another input comes in, then its compared to the _eventCaptureTime value to check if another input came in within 100 milliseconds of the last input, even if the loop ended. This would prevent patterns from getting cut of from one another because of the 500 millisecond loop.

//function checks the IoEvents of the Iolog and evaluates an input pattern
    private void lookForIoPattern() {

        //grabs the IoEvents of the Iolog
        for (int index = _ioEvents.length - 1; index >= 0; index--) {

            IoEvent currentIoEvent = _ioEvents[index];

            System.out.println(currentIoEvent.timestamp);

            //This value shows the state total for the IoEvent
            System.out.println("This is the current I/O state: " + currentIoEvent.states);
            //This value shows which input values were activated for the IoEvent
            int statesTurnedHigh = currentIoEvent.states & currentIoEvent.mask;
            System.out.println("This is the value of statesTurnedHigh: " + statesTurnedHigh + "\n");

            //grabs the start of the input pattern if its hasn't been assigned yet and if enough time passes between IoEvents it evaluates the pattern,
            //otherwise the pattern has an or statement performed on it with the current IO event
            if (statesTurnedHigh != 0) {

                if (_startOfPatternTime == 0) {
                    _startOfPatternTime = currentIoEvent.timestamp;
                    System.out.println("Start of pattern found.");
                }
                if (currentIoEvent.timestamp - _startOfPatternTime > PATTERN_WINDOW_DURATION) {
                    evaluatePattern(_pattern);
                    _startOfPatternTime = currentIoEvent.timestamp;
                    _pattern = currentIoEvent.states;

                } else {
                    _pattern = currentIoEvent.states | _pattern;
                }

            }

        }

        //checks if the pattern is done or if the loop needs to grab more IoEvents
        if (_startOfPatternTime != 0) {

            if (_eventCaptureTime - _startOfPatternTime > PATTERN_WINDOW_DURATION) {

                evaluatePattern(_pattern);
                _startOfPatternTime = 0;
                _pattern = 0;

            }
        }
    }

The last two functions are the evaluatePattern function and the getIoEvents function. The evaluatePattern function simply grabs the pattern created from the lookForIoPattern function and prints it. The getIoEvents function is what is called to grab the most recent IoEvents from the IoLog.

 //prints out the Input Pattern
    private void evaluatePattern(int createdPattern) {

        System.out.println("Pattern is " + createdPattern);

    }



    //grabs IoEvents and puts them into a class level array
    private void getIoEvents() {

        _iolog.refresh(_refreshTimestamp);
        _ioEvents = _iolog.getInputEvents();

    }

}

After adding those last functions, you should now have program that grabs all the inputs activating on the JNIOR, and creates a state pattern depending on how close each input’s timestamp is. Below is the code for the full application. Make sure you set the MultiplexSample file as the main function of your project.

//function runs the application
public class MultiplexSample {

    public static void main(String[] args) {
        
        InputMultiplexer inputMultiplex = new InputMultiplexer();
        inputMultiplex.run();
        
    }
    
}
import com.integpg.system.IoEvent;
import com.integpg.system.Iolog;

public class InputMultiplexer implements Runnable {

    //grabs the Iolog to get IoEvents
    private Iolog _iolog = new Iolog();
    //time of the first input to find the start of the input pattern
    private long _startOfPatternTime = 0;
    //time where Iolog is refreshed as to not look at old IoEvents
    private long _refreshTimestamp = _startOfPatternTime;
    //array of IoEvents to evaluate from the Iolog
    private IoEvent[] _ioEvents;
    //value for checking pattern has more IoEvents to process
    private long _eventCaptureTime = 0;
    //input pattern to log
    private int _pattern = 0;
    //duration between inputs required to continue a pattern
    private static final int PATTERN_WINDOW_DURATION = 100;



    //function calls other functions to log input pattern in a infinite loop
    @Override
    public void run() {

        while (true) {

            _eventCaptureTime = System.currentTimeMillis();
            getIoEvents();

            lookForIoPattern();

            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {

            }

        }

    }



    //function checks the IoEvents of the Iolog and evaluates an input pattern
    private void lookForIoPattern() {

        //grabs the IoEvents of the Iolog
        for (int index = _ioEvents.length - 1; index >= 0; index--) {

            IoEvent currentIoEvent = _ioEvents[index];

            System.out.println(currentIoEvent.timestamp);

            //This value shows the state total for the IoEvent
            System.out.println("This is the current I/O state: " + currentIoEvent.states);
            //This value shows which input values were activated for the IoEvent
            int statesTurnedHigh = currentIoEvent.states & currentIoEvent.mask;
            System.out.println("This is the value of statesTurnedHigh: " + statesTurnedHigh + "\n");

            //grabs the start of the input pattern if its hasn't been assigned yet and if enough time passes between IoEvents it evaluates the pattern,
            //otherwise the pattern has an or statement performed on it with the current IO event
            if (statesTurnedHigh != 0) {

                if (_startOfPatternTime == 0) {
                    _startOfPatternTime = currentIoEvent.timestamp;
                    System.out.println("Start of pattern found.");
                }
                if (currentIoEvent.timestamp - _startOfPatternTime > PATTERN_WINDOW_DURATION) {
                    evaluatePattern(_pattern);
                    _startOfPatternTime = currentIoEvent.timestamp;
                    _pattern = currentIoEvent.states;

                } else {
                    _pattern = currentIoEvent.states | _pattern;
                }

            }

        }

        //checks if the pattern is done or if the loop needs to grab more IoEvents
        if (_startOfPatternTime != 0) {

            if (_eventCaptureTime - _startOfPatternTime > PATTERN_WINDOW_DURATION) {

                evaluatePattern(_pattern);
                _startOfPatternTime = 0;
                _pattern = 0;

            }
        }
    }



    //prints out the Input Pattern
    private void evaluatePattern(int createdPattern) {

        System.out.println("Pattern is " + createdPattern);

    }



    //grabs IoEvents and puts them into a class level array
    private void getIoEvents() {

        _iolog.refresh(_refreshTimestamp);
        _ioEvents = _iolog.getInputEvents();

    }

}

There has been an update to the Update Project for OS 4.8.

Name Version Release Date Size MD5
Series 3 All-In-One v4.8 Nov 11 2019 251.7 KB ef6a2613188b70725b155c9c026064b3

Browsers no longer support Java Applets.  Therefore, the web files have been removed from the JNIOR in this update. This fixes flash space issues. The applets can still be loaded from within the JNIOR Support Tool.  To load the Applets, right click on the JNIOR  in the Beacon Tab.  Then go to Tools -> Open Classic Monitor, Configure, Control Application.

Sometimes the JNIOR doesn’t appear to be working but follow these steps and you might be able to determine why. There are a few steps that you can take before contacting INTEG or declaring that the JNIOR is not functioning. Hopefully the steps below will help save some time.

The number one way for INTEG to help provide support is to send us a Snapshot using the Support Tool. We can use the Snapshot to look at logs, analyze your configuration and to look at network interactions. Snapshots are most effective when taken soon after the issue is noticed. If too much time has passed the logs and network information may no longer contain relevant information pertaining to the time of the issue.

Power

The JNIOR requires 12 – 24v DC. We recommend a power supply capable of 1 Amp.

The very first thing to check is to make sure the unit has power. No, I don’t mean “did you plug the JNIOR in?” We need to make sure that the internal power supply is functioning and that the wires going in to the connector on the outside of the JNIOR have not broken.

To check the internal power supply we need to verify that the BLUE LED is illuminated next to the power connector.

If the BLUE LED is not illuminated then we want to make sure the wires have not been broken. This can easily happen if there is stress put on the wires during installation or if the connector was not securely fastened before being shipped.

Operating System

Is the OS running? To check this remove power. Upon applying power the amber light next to the BLUE power LED should come on for two or three seconds and then go out. Another thing we can check is to unplug the Ethernet cable. As of JANOS v1.8 the Status LED will blink Morse code indicating the value of the last octet of the IP Address when the Ethernet cable is unplugged.

Ethernet

The first thing to check regarding Ethernet connectivity is that the lights on the Ethernet port are lit. If they are not, please check both end of the cable to make sure it is connected. If the cable appears to be properly connected and the lights are not lit, please try a different cable.

Check Beacon to see that the JNIOR is on the network. Beacon is a feature on the JNIOR that uses UDP to broadcast itself on the network. The JNIOR Support Tool implements beacon and will query the network for any JNIORs. Any JNIOR that hears the query will respond. Because this feature uses UDP a valid working IP Address is not necessary.

If the cable, lights and beacon all appear to be in working order then the last thing to check here is the IpConfig/Allow setting. That will need to be done using the serial port. You can read about that procedure in the Dangers of IpConfig/Allow.

As of JANOS v1.8 the Status LED will blink Morse code indicating the value of the last octet of the IP Address when the Ethernet cable is unplugged.

Serial Port

The serial port can be used to diagnose JNIOR issues. Most of the time the Ethernet connection will be used to do this but in the case that the Ethernet connection is suspect we will need to use the serial port. There are two serial ports on the JNIOR but the RS-232 port is the is the port that facilitates the command line functionality. To connect to the JNIOR for command line use you will need to use the following settings. 115200 baud, 8 data bits, 1 stop bit and no parity. Once the cable is connected and you launched your favorite serial application you will need to press enter to see the login prompt. You could also reboot the JNIOR to observe the banner.

Configuration

If the hardware steps above do not alert you to the issue you are having then configuration is most likely to blame. Please contact us INTEG for further assistance. We can walk you through configuration issues, connect to your computer via TeamViewer, or determine if your unit needs to be replaced.

In an earlier article we attempted to connect the JNIOR to a DMX512 network in a way that would allow a theater stage crew to control relays and other outputs through their main lighting control panel. Here with the programmable facet of the JNIOR we could help create complex special effects that can be triggered in-sync with lighting. In fact, DMX channel data can be used by the JNIOR application to trigger and manipulate activity on a LAN segment and thereby update computer screens and TV displays on stage. This can all occur with precise timing in concert with other lighting changes.

The DMX512 protocol and interface was developed over 50 years ago as a means to reduce wiring cost and to improve the mobility needed to support major concert tours in the music industry. It incorporated serial data transmission formats that were state-of-the-art at the time and that are still relevant today. Unfortunately the protocol employed a baud rate much higher than would be later recognized as standard in the computer industry. Also the limited capabilities for data synchronization and lack of error checking make interfacing difficult. Even though the JNIOR Model 410 is able to handle the RS-485 signals and was upgraded to receive 250 Kbaud data triggered on the specified serial Break Condition, we could not achieve reliable operation as a fixture through programming alone.

The issue relates to the design of the standard computer hardware component called the UART. The Break Condition that the DMX protocol uses to identify the start of a frame of data is not handled by the UART in a fashion that can be reliably used to synchronize data reception. At least it is not possible in a purely software implementation as we discussed previously. The answer lies in a simple hardware adapter that alters the DMX512 signals just enough to work correctly through the UART. We will see what that entails in the rest of this article.

DMX512 Fundamentals

Today DMX is defined by official standards. On the wire DMX512 uses EIA-485 differential signaling. We often refer to it as RS-485. You are probably more familiar with the term RS-232. As serial digital communications became more prevalent the distance limitations and noise susceptibility of RS-232 became more and more of concern. The solution, designated as RS-422, used balanced transmission lines over twisted pair which extended the distances that signals can traverse as well as the communication rates that can reliably be achieved. RS-422 connections however are point to point and as computer systems grew so did the need for networking. Soon RS-485 came along and added functionality that created a multi-drop environment where one talker can communicate with a number of listeners. RS-485 is what DMX512 needed where one (or more) lighting control panel must communicate with multiple lighting fixtures.

This basically amounts to a 3-wire network where there is one DATA+ (positive) data line and one DATA- (negative) data line along with a GND ground. The DMX standard details specific connectors (5-pin XLR) and wiring of sufficient gauge and quality. The world also wants to utilize 3-pin XLR connectors for DMX as these are prevalent in the industry through their use in audio applications. You will find a mixture of fixtures some with 3-pin and some with 5-pin connectors. Thankfully 3-pin to 5-pin adapters are readily available.

On the protocol side it was necessary to standardize. This would encourage lighting manufacturers to incorporate the technology. Over the years the protocol itself had been handled by different standardization groups and now is:

American National Standard
ANSI E1.11-2008 (R2008)
Entertainment Technology – USITT DMX512-A
Asynchronous Serial Digital Data Transmission Standard
for Controlling Lighting Equipment and Accessories.

In order to understand where we have difficulty we need to look deeper into the specifics of what is sent across the wires. You recall that DMX was invented to reduce wiring costs. Each channel in the protocol replaces a single power cable. The protocol allows for up to 512 channels and all of those multiplexed onto a single 3-wire network cable. That is a significant savings.

Each channel digitizes an analog signal into one 8-bit value. These can represent numbers from 0 to 255 and for lamps that is used to sufficiently cover the range from 0% to 100% brightness in 256 steps. Where once one channel controlled one lighting fixture, today multiple channels are assigned to each fixture to define attributes such as color and positioning in the case of motorized fixtures. In the serial world each channel is transmitted just as a byte of character data would with a start bit, 8 data bits and one or two stop bits. For DMX512 two stop bits are used. That is a total of 11 bits per channel.

The DMX protocol allows for the transmission of up to 512 channels. These are sent in sequence starting with channel 1 and up to channel 512. A Start Code is defined as channel 0 and the typical value for that is zero. The complete set of channels 0 through 512 (513 channels) is called a Frame. Frames are transmitted repeatedly one right after another with the start bit immediately following the prior stop bits at the defined rate of 250 Kbaud. We can now do some math. With 11 bits per channel and 513 channels that is a total of 5,643 bits. A bit at 250 Kbaud requires 4 microseconds and so the data part of the frame takes a total of 22.6 milliseconds. We can fit a little over 44 frames in a each second.

Now with a constant flow of channels each looking the same on the wire how do we know which one is channel 0 and which might be the one we need for our fixture? If we connect to an active DMX network we need a way to synchronize ourselves. For this the standard defines the use of a Break Condition to signal the beginning of a frame. In old days this was called an Attention Signal and it was used to wake up remote teletype equipment and there was actually a key on the Teletype for this. So back in those days this was a natural choice for DMX synchronization. A Break Condition amounts to a period of time where the signalling is held at the level of a Start Bit (Space) long enough to violate the normal byte format and cause a reception error. The receiver simply fails to see the Stop Bits where they are expected and raises a flag. This is intended to signal the beginning of a frame.

By this definition a Break Condition need only last long enough to mask the expected Stop Bits (11 bits, 44 microseconds). This causes a UART to signal a Framing Error indicating that the data it received was not properly formatted and followed by the expected Stop Bits. This error can then be used for Break detection and the synchronization of the DMX Frame. The current DMX512 specification defines the minimum time for this Break Condition to be 88 microseconds which is exactly the transmission time of two channels. The timing of this Break Condition has been reduced from prior versions of DMX512 and it is unclear if there is any risk that existing lighting fixtures may fail to operate when presented with the shorter pulse. The specification does not specify a maximum duration for the Break Condition and states only a “typical” duration of 176 microseconds.

After the Break Condition terminates there must be a brief period of time before the Channel 0 (Start Code 0x00) can be transmitted. This period is called Mark After Break and the current specification defines a minimum of 8 microseconds the time period of two bits. This too has been reduced from prior versions of the specification. A maximum duration of 1 second is defined for Mark After Break and no typical value is given.

This defines the entire sequence. First a Break Condition of sufficient duration is issued. This is followed by a Mark After Break also of sufficient duration. After this each of 513 Channels is sent with proper serial formatting. The first is the START CODE which for normal DMX is always 0x00. Following the final Stop Bits for the last Channel there can be a gap before the next Break Condition. These Frames are sent continuously and according to the specification at least one Frame needs to be sent every 1.25 seconds.

Here is what this looks like in reality. The wider pulse in the center is a Break Condition and Frame data can be seen to the right and left of it. Note that in this case all Channels are set to 0x00 and so we see only the Stop Bits for each.

One side note is that shown above are the CMOS logic signals observed after the RS-485 receivers. This signal is typically fed to the receiving hardware or UART. This image is consistent with our prior diagrams where the Marking condition is a HIGH or 1 and the Spacing condition a LOW or 0. The signals on the actual wire demonstrate the same timing but would involve dramatically different voltage levels.

There is one point that I have not mentioned. The total number of Channels included in a Frame is a maximum of 513 but that number is optional. A lighting controller may decide to only send 128 Channels in addition to the START CODE assuming that others are unused and thereby increasing the number of Frames per second. The specification defines a maximum Frame rate of around 836 Hz (Frames per second). This can accommodate fixtures that need higher Refresh Rates. The Refresh Rate for a DMX512 Universe of a full 512 Channels is around 44 Hz.

In the previous article we alluded to there being some difficulty in receiving these signals with standard computer hardware. We now have enough technical detail to understand what that reception problem might be. This is the topic for the next section.

The Issue with the DMX Break Condition

Now let’s look at the task of receiving a frame of DMX data from a software point of view. We will assume that you have configured the hardware to receive RS-485 signals. The JNIOR Model 410 AUX port has RS-485 capability when properly wired and configured. INTEG can provide those details and those are mentioned in other articles. The JANOS operating system has also been enhanced to accommodate DMX and includes the 250 Kbaud rate setting as standard.

In the previous article JNIOR as a DMX Fixture we covered both the proper hardware configuration for the JNIOR Model 410 and the simple Java application software that might be used to receive a frame of channel data. We took that a step further and let the JNIOR activate relays in response to changing channel levels. It is here that we noticed a reliability issue and then spent time to understand it. We discovered that it is a limitation in the design of the standard UART and not something specific to our software or even the design of the JNIOR. Here we will review those findings and then in the balance of this article present a solution.

As you can imagine it would not be acceptable for the JNIOR to receive an incorrect channel value and act upon it. On stage you might create a flicker and distract the audience or worse trigger some elaborate effect at a totally inappropriate moment. Neither contribute to receiving good performance reviews. Well our first attempt at having the Model 410 serve as a fixture worked but occasionally there was a glitch. A relay toggled inappropriately and this lead to an investigation.

We started by attempting to validate the frame of channels. We know that the START CODE should be 0x00. So we decided to first test the START CODE. Well, 0x00 was not what we were seeing and this led us to understand that the UART is not able to properly receive data immediately following a Break Condition. Let’s look deeper into it.

Every description of the inner workings of the UART describes the reception of data beginning with the detection of the Start Bit. They state that “A Start Bit is detected as the falling edge of the signal” (which at that point is moving from a Mark condition to a Space condition from HIGH to LOW). This makes sense since this can be used to synchronize the baud rate and the UART once detecting the falling edge delays 1/2 bit time to begin sampling. The first reading is then LOW (0) since it is a start bit.

The UART then can proceed to receive data bits one after another starting with the LSB (Least Significant Bit or D0). Let’s assume that we are configured for 8 data bits and no parity as is the case for DMX. Once all 8 Data Bits are collected and the byte of data fully accumulated then next bit sampled is expected to be HIGH (1) as this is the necessary Stop Bit. The UART sees the Stop Bit and pushes the data to the output buffer and notifies the system that data can be read from the port. You can see how this follows from the first figure in this article repeated here.

Logically then you can see how the UART might go back into some ‘Start Bit Search Mode‘  in order to pass over any number of remaining Stop Bits and dead time between character transmissions.

We mentioned previously that in the case of a Break Condition the Stop Bits are missing. Here the UART receives 8 Data Bits or what it hopes are 8 Data Bits and then fails to detect the Mark condition signalling the presence of a Stop Bit. The typical UART then pushes the data to the output buffer and signals the processor that data can be read from the port. It also sets a Framing Error flag and well-written serial drivers handle the error accordingly.

Here is where your logical thinking might fail you. Once the UART signals a framing error you would like to think that it reenters the aforementioned ‘Start Bit Search Mode’. This would take the UART through the balance of the Break Condition and past whatever Mark After Break is present to the very next falling edge of the signal. This then allowing it to reliably and properly receive the very next valid byte of data. Well, surprise, it does not work that way.

Instead the UART continues to sample bits based upon its internal baud rate clock. It accepts the very next LOW (0) bit as a Start Bit and proceeds to process the following 10 or 11 bit times as another byte of data. This is why from the software side a Break Condition usually presents itself as more than one 0x00 byte each with an associated Framing Error. By itself this is not an issue as you can accept one or more Framing Errors as an indication of the Break Condition. In fact you could use this to detect a short Break from a long Break. But let’s look closer at what happens at the very end of the Break.

At the conclusion of an arbitrarily long Break Condition the signal returns to a Marking state. We have reached the Mark After Break but it is highly likely that the UART is still accumulating hopeful data bytes. Eventually it sees the Mark as a valid Stop Bit. The result is that a byte is then output by the port and there is no Framing Error. There is no way for software to determine if this is the first valid data byte (START CODE) or a bogus trailing byte formed out of the end of the Break Condition.

In testing we can see that this indeed is occurring. Since data bits are transmitted from least significant to the most significant, depending on signal timing this bogus byte can be seen to contain any one of the following: 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE or 0xFF. Perhaps you can see that this result depends on just what Data Bit the UART thinks it is receiving at the point when the Mark After Break begins. There is actually one additional case and that being when the data is actually the first valid data byte after the Break. This effect depends highly on the duration of the Mark After Break as well.

Matters can be even worse. In DMX512 the Mark After Break can be as short as two bit times or 8 microseconds. That means that it is possible that the UART does not even look for a Stop Bit until the signal is deep into the START CODE byte. Since the START CODE is itself 0x00 the UART might then grab one of those data bits as a Start Bit and, well, fail to receive several channels of data. How can this be? Are UART designs defective?

Well let’s not jump to that conclusion just yet. Let’s give the hardware developers the benefit of the doubt at least initially. First we should understand that once the computer industry embraced serial data communications use of the Break Condition fell by the wayside. Protocols used Start of Header (SOH) bytes and other means for synchronizing data blocks. These tended to include byte counts, error checking and even error correction. These days there is even data compression and data encryption. The Break Condition not only fell out of use but also started to disappear from serial communications documentation.

Meanwhile the industry started to look into the reliability of data transmission lines. In the early days RS-232 cabling was not what it is today and it was very susceptible to external electrical noise. Also remember that we were still using machines developed in the early half of the 20th century. These were power hungry electro-mechanical contrivances that spewed out electrical noise with reckless abandon. RS-232 signals often experienced data disruptions some as brief as an incorrect value of a single bit up to the loss of entire blocks of bytes. There were even situations where communications were completely blocked out for lengthy periods of time. Perhaps for as long as the nearby noisy equipment remained in use. This led to better cabling. It led to improved communications standards like RS-422. It prompted the need for error detection and motivated a lot of creativity on the error correction front. Simultaneously the Federal Communication Commission (FCC) put forth standards for controlling RF and electrical noise emissions and prompted certifications making new equipment meet the stringent requirements.

A UART design that utilized a “Start Bit Search Mode” fails to perform properly in a noisy environment. In the case when a Stop Bit is damaged by noise and thereby missed by the UART, an approach that accepts the very next falling edge as a start bit falls on its face. It fails to re-synchronize quickly. Many bytes of data then are lost even though electrically the signals are undamaged. Error correcting schemes just could not handle it. They determined that the current UART approach performed much better and, well, what is this Break Condition anyway?

We can only guess at how we got to where we are today. It is actually a surprise that a 50-year old protocol would still be as active today and it would still rely on synchronization techniques like the Break Condition. Of course it is not really an issue as DMX fixtures are developed to properly receive these signals. We are just a bit hampered in trying to use standard computer hardware. So what can we do about it? That is our next topic.

Correcting the DMX512 Protocol

We stand little chance of “correcting” the DMX512 protocol. With over 50 years worth of legacy DMX equipment out there a change in the design of the protocol is just not an option. The ability for DMX to inter-operate with standard computer hardware is just not that critical of a need. We have also exhausted any possible software solution to this issue. So what can we do? Some kind of hardware solution will be needed if we want to develop a JNIOR that can be used as a DMX fixture. What form will that take?

Obviously lighting fixtures all over the world read DMX channels seemingly without difficulty. So we know we can do it. Does this require a custom UART implementation in some FPGA component? Do we have to dedicate some PIC processor or other device to process incoming DMX bit by bit? Are there standard DMX chip level devices out there to make it easy? It certainly all cries out for some research. But first let’s see if there is some simple and creative way to address the issue.

The problem breaks down into two separate issues:

  1. The UART is unable to synchronize after a Break condition and reliably read the first START CODE byte.
  2. The trailing edge of the Break Condition can generate unexpected data not identified with a Framing Error.

Clearly if we use a Framing Error indication to signal the reception of a Break Condition and we are 100% assured that the next valid data byte is accurately representing the START CODE we are good to go. We assume then that the processor has enough horsepower to receive and buffer all 513 channels (if they are present) without error. This can be done with low-level interrupt routines avoiding any dependence on the processing load in the JNIOR. In fact all of this has already been implemented in JANOS and deployed into the field. Those techniques were tested in the prior article.

The Mark After Break condition specified by the DMX512 protocol is a minimum of 8 microseconds. That is just two bit times. This is unfortunate. If this Mark After Break condition were to be held at least 11 bit times (44 microseconds) then any UART would be assured of seeing some part of the condition as valid Stop Bits. The UART then would be guaranteed ready to receive the very next data byte which is the START CODE.

If we somehow could extend the Mark After Break that would insure the reliable reception of the channel data. That by itself is not enough since we know that the trailing edge of the Break Condition can generate a data byte that is not flagged with a Framing Error. This would confuse us as there is no real way to determine if this is the START CODE or a bogus addition to the stream.

Now if we could somehow limit the Break Condition to a single byte we would receive one and only one byte flagged with a Framing Error. The UART would not see an additional Start Bit and thereby insure that the next byte we see is in fact the START CODE. We know that the Break Condition is at least 88 microseconds at its shortest. That is exactly two data byte times (each of 11 bits = 1 start bit + 8 data bits + 2 stop bits). So if we truncated the Break Condition at exactly 44 microseconds which would generate 1 byte with a Framing Error, there is another whole byte’s worth of time that could be added to the Mark After Break. This would satisfy our interest in extending the Mark After Break for at least a byte time. At a minimum it would then be 52 microseconds (44 borrowed from the Break + 8 original microseconds).

The Hardware Solution

Our hardware needs to truncate the Break Condition. We need only hold it long enough to mask the first Stop Bit and thereby force the Framing Error. This needs to be achieved without risk of causing other Framing Errors. With a little thought we developed the following logic.

This circuit is inserted in the CMOS logic stream after the RS-485 receivers and before input to the UART. The RXD signal from the receiver enters at the left. We will use the OR gate (U7) to truncate the Break Condition. This will pull the signal HIGH at the appropriate time but otherwise allow the normal serial stream through. The output then is TXD to be delivered to the UART on the right.

The CD4024B (U6) is a 7-stage counter and it is reset (RST) or restarted with any HIGH Marking condition on the incoming data. This means that the count is not allowed to progress very far except during the Break Condition where there is no reset (RST). This in essence times the duration of the Break Condition. Note that when the output of the 7th stage goes high (count >= 64) the OR gate then pulls the TXD signal high effectively truncating the Break Condition. The signal output is then held HIGH until the Mark After Break arrives and resets the counter. At this point the incoming signal is HIGH and we have effectively transferred time from the Break Condition to the Mark After Break. This is exactly what we want.

The UART will throw the Framing Error as soon as the first Stop Bit is not detected. We don’t want it to see any potential Start Bit after that. To be safe then we truncate the Break Condition after the 10th bit time right after the first Stop Bit. This means that we must truncate the Break Condition precisely after 40 microseconds and this must occur at the 64th count when the 7th stage goes high. As it turns out 40 microseconds divided by 64 is 0.625 microseconds the precise period of a 1.600 MHz clock. Those are readily available. So we clock the counter with a 1.600 MHz signal using oscillator U4.

One last detail to consider. There is no upper bound on the duration of the Break Condition. That means that once we truncate the Break Condition we need to hold it for potentially a very long time. So we cannot allow the counter to continue to run. Once the 7th stage goes HIGH we need to hold it there. A second OR gate (U5) masks the incoming 1.600 MHz clock signal at that point effectively stopping the counting. And, miraculously, we’ve got it covered.

To test this we created a prototype adapter which implements an isolated DMX512 standard port. The signal passes through our circuit and then a standard RS-232 transceiver is used to communicate with the JNIOR AUX port. One advantage this has is that any Model JNIOR with an AUX port can be used as a DMX fixture. Whereas only the Model 410 supports RS-485 directly and can be used as described in the prior article.

Here the few components involved sit in the lower lefthand corner. These Surface Mount devices take up almost no real estate and this is perfect for a new model of the JNIOR sporting a DMX512 input. Okay, so does the circuit work?

Here we see another oscilloscope trace. The yellow signal is RXD as received from the RS-485 receiver. This is what enters the schematic from the left. The blue signal is TXD and what we will supply to the UART. This exits on the right of our schematic. The wider pulse in the center is our Break Condition.

On the yellow trace we see that the Break Condition supplied by the DMX network is about 100 microseconds and it is followed by a brief Mark After Break which looks to be somewhat less than 50 microseconds. We know that this signal is problematic as it is from the same source used in the prior article. Note here that the START CODE and all channels happened to be 0x00. So those high pulses are Stop Bit pairs.

Now the blue trace is the result. The Break Condition has indeed been truncated. The vertical cursor lines are positioned to measure the duration of the new Break Condition. On the right we see the delta-t to be the precise 40 microseconds we had hoped for. We can also see that the balance of the time in the Break Condition has now been added to the Mark After Break.

Does this allow the JNIOR to be used as a DMX fixture? In fact it does and there is absolutely no glitch or reliability concern. Here is a short video showing relays responding to a DMX channels. A channel value greater than 127 is used to signal closure of a relay. The JNIOR’s 8 relays are mapped to consecutive channels.

Success!

Of course this would need to be evaluated with a wide range of DMX512 signal sources. The Java application on that JNIOR in the video is essentially that discussed in the previous article. It would be useful to reiterate its operation but that is beyond the scope of this article. If you should be interested in using a JNIOR as a DMX fixture just let us know. We can likely supply you with one of these prototype adapters and the application programming is open source from us. If you already have a JNIOR then your are almost there.

Now we have everything that we need to create another JNIOR Model with its own Isolated DMX512 input!

We should note that not all UARTs are created equal. There are likely UART implementations that do properly handle synchronization after the Break Condition. If you have one of those then you are golden. In the case of the JNIOR we were not so lucky. While the adapter was described above as prototype we do have several that we can supply. It is not clear that there would be any long term demand for this. A model of the JNIOR directly providing a DMX512 electrically isolated input is now feasible and would likely include the circuit as described here. Contact INTEG to find out more.

Update

We can provide the adapter (as shown) along with a power supply and instructions.  The adapter can be used in any serial application and not just with the JNIOR however as discussed in the article you would need to accommodate the unique Baud rate and trap the framing error for synchronization. The document supplied includes an example application for the JNIOR and a schematic.

Note that straight-thru terminals are provided allowing you to tap either 3-wire or 5-wire DMX signals.  You may wish to splice into a DMX extension cable (not provided) to give yourself cabling terminated by the desired (3 or 5 pin) DMX XLR connectors. An isolated DMX port is implemented and so your JNIOR or PC is not directly connected to the lighting system.

The above kit is INTEG P/N A00-00155 – DMX512 SERIAL PRE-PROCESSOR.

Depending on the application, something going wrong and stopping it from running could lead to big complications. Thankfully, a watchdog can monitor your application and react how you want it to using the Watchdog class. The watchdog can stop, restart, and report on applications not responding to it and more. Watchdogs have configurable timeframes, and when they aren’t updated before the time frame expires they trigger.

The watchdog is a very powerful concept. Wikipedia says:

watchdog timer (sometimes called a computer operating properly or COP timer, or simply a watchdog) is an electronic timer that is used to detect and recover from computer malfunctions. During normal operation, the computer regularly resets the watchdog timer to prevent it from elapsing, or “timing out”. If, due to a hardware fault or program error, the computer fails to reset the watchdog, the timer will elapse and generate a timeout signal. The timeout signal is used to initiate corrective action or actions. The corrective actions typically include placing the computer system in a safe state and restoring normal system operation.

Usage

The sample below is very basic. You will need to adjust the duration and location of the watchdog for your application.

package com.integ.watchdogsample;
 
import com.integpg.system.JANOS;
import com.integpg.system.Watchdog;
 
public class WatchdogSampleMain {
 
    public static void main(String[] args) throws InterruptedException {
        JANOS.syslog("WatchdogSample started");
 
        // create a watchdog that will reboot the jnior if the watchdog is 
        // not fed once every 5 seconds
        Watchdog watchdog = new Watchdog("WatchdogSample");
        watchdog.setAction(Watchdog.WDT_REBOOT);
        watchdog.setDuration(5000);
        watchdog.activate();
        JANOS.syslog("WatchdogSample activated");
 
        // loop for 30 seconds.  we will feed the watchdog in this loop.  
        // when the loop stops the watchdog will timeout and reboot the jnior.
        long loopExpiration = System.currentTimeMillis() + 30000;
        while (loopExpiration > System.currentTimeMillis()) {
            System.out.print(".");
            // feed the watchdog
            watchdog.refresh();
            // sleep for a second
            Thread.sleep(1000);
        }
 
        // now that the loop is finished.  the unit will reboot soon.
        JANOS.syslog("WatchdogSample loop finished");
    }
 
}

This is what we see in the log after the unit has come back up.

01/15/19 08:37:36.361, FTP/10.0.0.27:62888 uploaded /flash/WatchdogSample.jar [115.3 kbps] 
01/15/19 08:37:44.081, WatchdogSample started 
01/15/19 08:37:44.203, WatchdogSample activated 
01/15/19 08:38:14.307, WatchdogSample loop finished 
01/15/19 08:38:18.451, ** Assertion: WatchdogSample watchdog triggered reboot (Line 1278) 
01/15/19 08:38:18.483, ** Terminating: System 
01/15/19 08:38:20.971, ** Reboot on assertion: WatchdogSample watchdog triggered reboot (Line 1278) 
01/15/19 08:38:20.997, -- JANOS 410 v1.7.1 initialized (POR: 1546)

Here are the options that are available to choose from when the watchdog expires.  You see that we assign the action in the setAction() method above.  watchdog.setAction(Watchdog.WDT_REBOOT);

WDT_REBOOT

This is the default action. Expiration of the watchdog timer causes the unit to reboot.

WDT_APPLICATION

This action indicates that a watchdog timer expiration is to be handled by the application itself. The system takes no action.

WDT_TERMINATE

When the watchdog timer expires the system will terminate the application.

WDT_BREAK

This interrupts the current application (similar to Ctrl-C interruption) when the watchdog timer expires.

WDT_RESTART

When the watchdog timer expires this will interrupt the current application and restart it.

WDT_MESSAGE

When the watchdog timer expires a WM_WATCHDOG (0x11) message will be sent through the system message pump. The content contains the text associated with the watchdog.

WDT_EVENT

Watchdog timer expiration will notify the first thread in the application that is waiting  for notification using waitOnWatchdogNotify().

This sample shows you how to use the Immutable class. The immutable class represents persistent storage that can be accessed at the low level as an array of primitive types. This information will withstand reboots and application terminations. You can view Immutable data by typing the ‘nv’ command in the command line of a JNIOR. If using only one data type, you can express to create an immutable array of that data type, but if you want your array to have mixed data types inside it, you have to use a byte array. 

Using Immutable Blocks

This example shows the use of an array of longs. The long values in this application are date values that represent when the application was started. The long array is part of an Immutable block, therefore the application start times don’t go away until overwritten or manual removed. This application holds up to the last five application start times.

package immutableexample;

import com.integpg.system.Immutable;
import java.util.Date;

public class ImmutableExample {

    public static void main(String[] args) {
// get an array of long values that represent the last 5 boot times 
        long[] lastFiveBootTimes = Immutable.getLongArray("BootTimes");
// if the array does not already exist then create an array of 5 long values 
        if (lastFiveBootTimes == null) {
            lastFiveBootTimes = Immutable.createLongArray("BootTimes", 5);
        }
// shift the previous 4 boot times 
        for (int i = 4; i > 0; i--) {
            lastFiveBootTimes[i] = lastFiveBootTimes[i - 1];
        }
// assign the most recent boot time 
        lastFiveBootTimes[0] = System.currentTimeMillis();
// loop through our last five boot times and print them in a readable format 
        for (int i = 0; i < 5; i++) {
            long bootTime = lastFiveBootTimes[i];
            if (bootTime > 0) {
                System.out.println(new Date(bootTime));
            }
        }
    }
}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. After it has successfully run, I run the application multiple times, and it shows each time it runs a new application start time added to its immutable array.

JANOS supplies a Message Pump wherein messages of various types may circulate between processes.

 

JANOS supplies a Message Pump wherein messages of various types may be circulated between processes or application. These messages may be user defined.
Message numbers below 1024 (0x400) are RESERVED by the system.
The following are the system defined message types.

SM_SHUTDOWN (0x01)

This message is generated by the system prior to shutdown. When received applications MUST forward the message by returning it to the pump and exit in an expeditious fashion. The JNIOR is about to reboot.

SM_PROBE (0x02)

This message is generated by the system periodically. When receive applications MUST forward the message by returning it to the pump. This is used to detect listeners that are no longer responding or that are not properly forwarding messages. The system expects to see this message return to it in a prompt fashion.

SM_GCRUN (0x10)

This message indicates that the Garbage Collection (GC) has completed. When received applications MUST forward the message by returning it to the pump.

SM_WATCHDOG (0x11)

This message is generated by a application watchdog configured to send then message on timer expiration.

SM_SYSLOGMSG (0x12)

System log messages can be sent to an external Syslog Server. This message also passes the log information to listening applications.

SM_PWRLOST (0x20)

When Ride-Thru Power support is available this indicates the lost of external power.

SM_PWRGOOD (0x21)

When Ride-Thru Power support is available this indicates that external power has been restored.

SM_PWRREADY (0x22)

When Ride-Thru Power support is available this indicates that the supply is fully charged and ready to provide maximum holding capacity.

SM_REGUPDATE (0x40)

This message is generated whenever a registry entry is updated or removed. When received application MUST forward the message by returning it to the pump.

SM_WEBSTARTUP (0x60)

Message sent when the Web Server process is activated.

SM_WEBSHUTDOWN (0x61)

Message sent when the Web Server process is terminated.

SM_PROTCMDMSG (0x70)

This message is generated when the JNIOR Protocol receives a custom command message. When received an application MUST either forward the message or provide a SM_PROTCMDRESP response.

SM_PROTCMDRESP (0x71)

This message is generated by an application in response to a SM_PROTCMDMSG command message. It is intended for the JNIOR Protocol server. When received applications MUST forward the message by returning it to the pump.

SM_PIPEOPEN (0x80)

This message is sent by the Web Server when a piped websocket connection has been established. The message contains the client IP Address and Port as well as the target message number.

SM_PIPECLOSE (0x81)

This message is sent by the Web Server when a piped websocket connection has terminated. The message contains the client IP Address and Port as well as the original targeted message number.

SM_USER (0x400)

Lowest allowed user defined message number. Applications that intend to exchange messages SHOULD attempt to define globally unique message identifiers. These must be values from 1024 and up. Message numbers below SM_USER are RESERVED by the system.

NOTE: Before creating the setup described in this post on your JNIOR 410, please download the update project below and install it on your 410 using the JNIOR Support Tool. This is required to get the JNIOR to create a DMX connection.

Name Version Release Date Size MD5
DmxPort for enabling DMX on 410 Mar 17 2021 3.5 KB 299c66717c03a9c9b702716d9d56d095

This article is the first of two addressing the issues encountered in, and a means to simplify, the processing of the DMX Universe data stream using a standard UART serial receiver. The follow-up article is entitled JNIOR as a DMX Fixture Revisited.

The Model 412DMX generates a DMX512 Universe and allows the JNIOR to control DMX fixtures like those used in stage lighting. What if you needed a fixture with relays that can be controlled by DMX? Perhaps you need to output channels over a 4-20ma loops. Maybe you need a 10 VDC output signal to control LED house lighting. Can the JNIOR receive DMX? Can the JNIOR be a DMX Fixture?

We showed you how you could control DMX fixtures with a standard Model 410 in a White Paper available here:

  AN01 DMX512 Implementation [ Jul 20 2017, 101.27 KB, MD5: e1b0203f177d1866e56cfbfdd0e221d4 ]

Now we have the 412DMX JNIOR designed for that purpose. Can the Model 410 also serve as a DMX fixture? Yes, it can. I’ll show you how here and we’ll see how we manage to accommodate some of the unique aspects of the DMX512 format with the JNIOR.

Cabling

We can use the JNIOR Model 410 because the AUX port is compatible with RS-485. In the white paper explaining how the 410 can be used to control DMX fixtures we described an adapter cable taking the DB9 output from the JNIOR and presenting the proper female XLR connector for DMX. Now since a DMX fixture always has both a male and female 5-pin XLR connectors, our cabling has to be slightly different. Note that you can do this with the 3-pin XLR (as I have) if that is appropriate for your situation.

Here is an example of one that we put together.

modified Series 4 DMX AUX port cable

This can be constructed by splicing into a standard DMX extension cable. A number of DB9 adapters with screw terminals like the one pictured can be found on Amazon. Note that you will want one with large screws compatible with larger wire sizes. DMX wiring is typically of a larger diameter and you will need to successfully clamp two wires in each of three positions on the adapter.

Here is the pin numbering. Note that wire colors vary.

        Signal           XLR      DB-9 Male
--------------------  ---------  -----------
Signal Ground (GND)       1          5
Data (D-)                 2          3
Data (D+)                 3          7
Not Used (NC)            4,5     1,2,4,6,8,9

This cable allows the JNIOR to be a DMX FIXTURE.

THE RESULTING DMX CONNECTION IS NOT ISOLATED. We recommend using an isolated power supply for the JNIOR and not sharing that voltage with other circuits. Take great care in making ground connections. Note that the JNIOR relay outputs are naturally isolated.

Serial Connection

Connect the adapter to the Model 410 AUX serial port as I have in this photo and connect this to the DMX network. Note that the 412 and 414 are not RS-485 compatible and cannot be used for this purpose.

modified Series 4 DMX AUX port cable

The serial port parameters should be set as follows. This is done through the Dynamic Configuration Pages (DCP) that should come up when accessing the JNIOR using your browser. You enable the RS-485 mode here so the AUX port output doesn’t disrupt the DMX communications before you have a chance to run the DMXFIXTURE application that I will describe. That application will also configure the AUX port just to make sure that all is well.

JNIOR Aux port settings

If you encounter “Applets” instead of the DCP then your Series 4 needs to be updated or you have a Series 3. The latter also cannot be used for this application. You will need to update your JNIOR to JANOS v1.6.6 or later for the functionality to be described here.

Data

With the JNIOR Model 410 wired to the DMX network and the AUX serial port properly configured the unit should be receiving data. There is a simple way to check that. You can see data without any application running just by using the IOLOG command. Here we enter the Console (or Command Line Interface) and use this command.

InfoComm_LED /> help iolog
IOLOG

Options:
 -T             Indicate transitions
 -R             Reset logs
 -A             AUX Serial log
 -S             Sensor Port log
 -O             Output to stdout

Generates jniorio.log file from available logs.

InfoComm_LED /> iolog -ao
--  07/02/18 15:42:46.098
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--80--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--FF--00--FF--80--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--83--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--80--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--FF--00--FF--80--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--83--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--80-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--FF--00--FF--80-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--83--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-80--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--FF--00--FF-    ................
-80--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--83--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-    ................
-00--00--00--00--00--00--00--00--00--00--00--00--00--00--00-        ...............

InfoComm_LED />

If you scan down in the above output and look through the data you will see that there are a couple of channels at 100% (0xFF) and a couple near half (0x80’ish). There are two pretty major issues in trying to read these bytes with standard library read() functions.

  1. How do we know how to find Channel 1? There are many more than 512 bytes shown here. If you read 512 bytes what you get could start anywhere.
  2. The data rate at 250 Kbaud supplies 44 complete channel sets per second! That absolutely will overrun the buffer before you can process any of it. The overrun would likely further obfuscate the data.

The fact is that the standard serial communications routines that you may be used to are just not usable here. JANOS will come to the rescue. But first let’s take a look at the data stream so we understand how this is to be resolved.

DMX Format

The DMX data on the RS-485 lines conforms to standard asynchronous serial data with 8 data bits, 2 stop bits and no parity. The bits are marched out from least significant (LSB) D0 to the most significant (MSB) D7. Each byte is called a “Slot”. The standard implementation transfers a START CODE and 512 channels in a total of 513 slots. The START CODE for normal DMX data is 0x00.

The beginning of the sequence is signaled with a Break Condition. This BREAK can be detected by the fixtures which allows them to synchronize with the stream. After the BREAK comes the START CODE (0x00 – NULL START) followed by the value for Channel 1 on through to Channel 512. Not all 512 channels need to be part of the transmission. The number of channels may vary by DMX controller. The complete implementation provides all 512.

On the oscilloscope the BREAK looks like this. Here all of the channels are 0X00 and so you see only the STOP BITS. That long low pulse is the BREAK.

The issue is that the BREAK is difficult to handle with the standard serial port. It results in a FRAMING ERROR. During the break the signal is held at a low level. When the receiving serial UART expects the STOP BITS and they aren’t there it throws a FRAMING ERROR. While that can be detected and your application can be notified there still is no way to insure that the next bytes read from the port are those that follow the break. They may have been buffered some time before. They may be overrun by oncoming data.

In order to handle this and properly capture a reliable channel set, there must be a special function for that purpose in the AUX port class (AUXSerialPort). Of course, being the author of JANOS, I have implemented exactly what we need. And, those details are next…

Packet Capture

To read the DMX Packet (START CODE plus up to 512 Slots/Channels) we need to detect the Break Condition and then reliably collect as many as 513 serial bytes that immediately follow. Under many other RTOS implementations we would need to write an interrupt driven routine both to detect the Break condition and then also to collect the data. The JNIOR executes application programs written in a managed language (Java) and one does not have low level access to write things like serial interrupt routines. That is actually a good thing as the user generally does not have the programming experience. Such low level user programming often leads to unstable/unpredictable operation.

Here we rely on JANOS to maintain reliable operation. Low level interrupt routines have already been implemented to buffer incoming serial data and otherwise issue a notification of errors. Recall that the Break Condition manifests itself and one or more FRAMING ERRORS. But we have already established that reading buffered serial data and receiving asynchronous notifications is not going to be sufficient for capturing a DMX packet. This is where we benefit from having developed JANOS in-house and having authored 100% of it. Here we identify a need and are able to promptly and correctly implement a solution.

AUXSerialPort.readAfterBreak(byte[] buffer)

I have added the readAfterBreak() method to the AUXSerialPort class in the JANOSClasses.jar library. From the naming its use is self-explanatory. Here you create a buffer as a byte array and pass it to JANOS. The operating system enables the capture and then blocks the thread until the data collection completes. At the low-level JANOS sets up the buffer with a pointer and goes into a kind of ‘armed’ state. The interrupt routine that detects FRAMING errors has a tiny bit of code that checks for an armed capture and ‘triggers’ the collection of data. The interrupt routine that collects and buffers serial bytes from the port has code to set each byte aside into the buffer that you have provided. Once triggered the capture passes into the a ‘collection’ mode. When the buffer is full (or when another Break Condition is detected) the capture is ‘complete’ and the application program can proceed now with a byte array containing the DMX data.

Now to benefit from this new feature, you will need to update your Series 4 to run JANOS v1.6.6 or later. At the moment this is Beta code. We would make it available if you were to want to try this before its release. All you need do is ask.

Next we need to try it out…

DMX Capture Test

Here we create a project in Netbeans (making the few settings needed to target it for JANOS) and create the following test program. This merely takes control of, and fully configures, the AUX port in case it has not been configured through the DCP. Lines 23 and 24 test our new method. The rest merely dumps the byte array content for review.

package dmxfixture;
 
import com.integpg.comm.AUXSerialPort;
import com.integpg.comm.SerialPort;
 
public class Dmxfixture {
 
    public static void main(String[] args) throws Throwable {
 
        // AUX port access and configuration.  We need to open the port to gain exclusive access and
        //  set the proper baud rate and format.  We enable RS-485 mode and make sure that the receivers
        //  are enabled.  With normal RS-485 you would disable the transmit drivers.  Our adapter doesn't
        //  bridge the transmit and receive lines anyway and the DCP configuration automatically disables
        //  the drivers.  It is here for clarity.
        AUXSerialPort aux = new AUXSerialPort();
        aux.open();
        aux.setSerialPortParams(250000, 8, 1, SerialPort.PARITY_NONE);
        aux.setRS485(true);
        aux.enableReceivers(true);
        aux.enableDrivers(false);
        
        // capture a complete frame using our new method
        byte[] data = new byte[513];
        aux.readAfterBreak(data);
        
        // The remainder here is a fancy dump (skipping the START CODE).  Note how JANOS implements the
        //  printf formatting for us.
        for (int i = 1; i < data.length; i++) { 
            if (i % 10 == 1)
                System.out.printf("%04d  ", i);
            System.out.printf("%4d ", data[ i ] & 0xff);
            if (i % 10 == 0)
                System.out.println("");
        }
        System.out.println("");
    }
    
}

To run this we first build it in Netbeans. Then using the DCP we open the Folders tab and select the /flash folder. We then drag the dmxfixture.jar file from the project to the /flash folder (it can be executed from the root too). Then under the Console tab we log in and execute the application. The following is the result.

InfoComm_LED /> dmxfixture
0001     0    0    0    0    0    0    0    0    0    0 
0011     0    0    0    0    0    0    0    0    0    0 
0021     0    0    0    0    0    0    0    0    0    0 
0031     0    0    0    0    0    0    0    0    0    0 
0041     0    0    0    0    0    0    0    0    0    0 
0051     0    0    0    0    0    0    0    0    0    0 
0061     0    0    0    0    0    0    0    0    0    0 
0071     0    0    0    0    0    0    0    0    0    0 
0081     0    0    0    0    0    0    0    0    0    0 
0091     0    0  255    0  255  128    0    0    0    0 
0101     0    0    0    0    0    0    0    0    0    0 
0111     0    0    0    0    0    0    0    0    0    0 
0121   131    0    0    0    0    0    0    0    0    0 
0131     0    0    0    0    0    0    0    0    0    0 
0141     0    0    0    0    0    0    0    0    0    0 
0151     0    0    0    0    0    0    0    0    0    0 
0161     0    0    0    0    0    0    0    0    0    0 
0171     0    0    0    0    0    0    0    0    0    0 
0181     0    0    0    0    0    0    0    0    0    0 
0191     0    0    0    0    0    0    0    0    0    0 
0201     0    0    0    0    0    0    0    0    0    0 
0211     0    0    0    0    0    0    0    0    0    0 
0221     0    0    0    0    0    0    0    0    0    0 
0231     0    0    0    0    0    0    0    0    0    0 
0241     0    0    0    0    0    0    0    0    0    0 
0251     0    0    0    0    0    0    0    0    0    0 
0261     0    0    0    0    0    0    0    0    0    0 
0271     0    0    0    0    0    0    0    0    0    0 
0281     0    0    0    0    0    0    0    0    0    0 
0291     0    0    0    0    0    0    0    0    0    0 
0301     0    0    0    0    0    0    0    0    0    0 
0311     0    0    0    0    0    0    0    0    0    0 
0321     0    0    0    0    0    0    0    0    0    0 
0331     0    0    0    0    0    0    0    0    0    0 
0341     0    0    0    0    0    0    0    0    0    0 
0351     0    0    0    0    0    0    0    0    0    0 
0361     0    0    0    0    0    0    0    0    0    0 
0371     0    0    0    0    0    0    0    0    0    0 
0381     0    0    0    0    0    0    0    0    0    0 
0391     0    0    0    0    0    0    0    0    0    0 
0401     0    0    0    0    0    0    0    0    0    0 
0411     0    0    0    0    0    0    0    0    0    0 
0421     0    0    0    0    0    0    0    0    0    0 
0431     0    0    0    0    0    0    0    0    0    0 
0441     0    0    0    0    0    0    0    0    0    0 
0451     0    0    0    0    0    0    0    0    0    0 
0461     0    0    0    0    0    0    0    0    0    0 
0471     0    0    0    0    0    0    0    0    0    0 
0481     0    0    0    0    0    0    0    0    0    0 
0491     0    0    0    0    0    0    0    0    0    0 
0501     0    0    0    0    0    0    0    0    0    0 
0511     0    0 

InfoComm_LED />  

We note that channels are correct. Here we go over to the 412DMX controlling this DMX network and check Kevin’s DMX panel page for comparison.

DMX control panel

Putting it to Work

Now we can receive a DMX frame and read the individual channels what can we do with it? I mean other than dump it?

Well Kevin has defined an eight channel fixture starting at DMX channel 121. The idea being that each channel would correspond to a JNIOR Relay Output. Channel settings from 0-127 would result in an open/off relay and values in the range 128-255 would close the relay. You can imagine any use that you would want given the flexibility that you now have in JNIOR programming. Let’s implement this particular fixture.

The approach will be to sample a DMX packet periodically and set the relays appropriately. There is no need to catch every DMX packet and in fact we are not likely going to be able to do that. We are also going to be considerate of the JNIOR CPU and anything else that the unit might want to be doing. We will sample say every 1/4 second and sleep in between.

Here is the program. This uses an infinite loop to sample the DMX stream about 4 times a second. The starting address must be defined in the Registry. This could be cached. With this implementation you can change the starting address without rebooting or restarting the DMXFIXTURE program. It is presume that you would start the DMXFIXTURE program automatically at boot with a Registry Run key.

package dmxfixture;
 
import com.integpg.comm.AUXSerialPort;
import com.integpg.comm.SerialPort;
import com.integpg.system.JANOS;
 
public class Dmxfixture {
 
    public static void main(String[] args) throws Throwable {
 
        // AUX port access and configuration.  We need to open the port to gain exclusive access and
        //  set the proper baud rate and format.  We enable RS-485 mode and make sure that the receivers
        //  are enabled.  With normal RS-485 you would disable the transmit drivers.  Our adapter doesn't
        //  bridge the transmit and receive lines anyway and the DCP configuration automatically disables
        //  the drivers.  It is here for clarity.
        AUXSerialPort aux = new AUXSerialPort();
        aux.open();
        aux.setSerialPortParams(250000, 8, 1, SerialPort.PARITY_NONE);
        aux.setRS485(true);
        aux.enableReceivers(true);
        aux.enableDrivers(false);
 
        // here we create an infinite loop to continuously process the DMX data
        byte[] data = new byte[513];
        for (;;) {
            
            // capture a complete frame
            aux.readAfterBreak(data);
            
            // Obtain the starting address.  If it is invalid or not defined no action is taken.
            int addr = JANOS.getRegistryInt("DMX/Address", 0);
            if (addr > 0 && addr < 505) {
                
                // Although we don't have to we are going to collect all of the relay states
                //  and set them simultaneously.  This will also take advantage of signed values
                //  in Java.  Values in the range 128-255 will appear to be negative if we don't
                //  mask them with 0xff.
                int bits = 0;
                for (int i = 0; i < 8; i++) {
                    if (data[addr++] < 0)
                        bits += (1 << i);
                }
                JANOS.setOutputStates(bits, 0xff);
            }
            
            // sleep for a quarter second
            System.sleep(250);
        }        
    }
    
}

This program should be pretty easy to follow. Let’s test it.

Demonstration

A video can best demonstrate the operation of this program. Here we have a DMX application running on a 412DMX (10.0.0.242) allowing us to vary the channels that we associate with our 410 fixture. A separate Model 410 running our DMXFIXTURE (10.0.0.250) program can be monitored remotely through its DCP page. Here we overlap the two browser entities and we can see how modifying the channel fader results in the relay status change out across the DMX network.

Reliability

Let’s look into potential error conditions and the reliability of this approach. The DMX format typically supplies nearly 44 frames per second. If there is a communications error, due to electrical noise for instance, one and possibly up to a few frames might be in error. For a light fixture this might cause a minute flicker or some small flinch in pointing. But, given the frame rate it is quickly corrected and might not be even noticeable. If we are interpreting a frame with our program we need to be extra careful not to trigger a chain of events based upon an error packet.

Typically in data protocols we would have some form of checksum or CRC which we can use to identify an erroneous transmission so it can be ignored. There is no such thing in the DMX512 protocol. So what steps can we take?

Well to start we should verify that the START CODE is the expected NULL START 0x00 and ignore any frame with a different code. The controller might actually be inserting those and we must ignore them. I will adjust the program to check this.

Well… The START CODE is returning 128 (0x80) and the channels appear to be properly registered (e.g. in the right place). Now to look into this.

Synchronization After Break

The DMX512 specification defines the width of the Break Condition as something greater than 92 microseconds. It is important to note that it is something greater than twice that of a single slot time (the time to receive a single byte) of 44 microseconds (11 bit times – start bit, 8 data bits and 2 stop bits). It is not a precise multiple of slot times or even bit times. This forces the receiver to synchronize with each and every packet.

Given this I could make the argument that the Mark After Break should be at least one slot time of 44 microseconds in order to insure that the leading start bit of the first slot is successfully interpreted. The DMX512 specification however specifies the minimum Mark after Break of 12 microseconds. This puts us at the mercy of the UART design and its ability to synchronize following a Break Condition of arbitrary length. There are a number of possible outcomes that depend on what the UART decides is the first STOP BIT once the Break Condition passes.

  • For example, if the beginning of the Mark After Break is seen as a valid STOP BIT then a 0x00 byte is received AHEAD OF the normal NULL START code 0x00. This extra 0x00 can be interpreted as a valid START CODE but all of the channel slots are off by 1. Channel 2 would have the value for Channel 1. This is an ERROR!
  • If the Mark condition just slightly into to Mark After Break is interpreted as a valid start bit then an extra 0x80 is received AHEAD of the START CODE. This might be seen as a bad packet if the START CODE is verified. Channels are also shifted if values are used. This is a ERROR!
  • The above continues with each bit time advance into the Mark After Break generating an initial extra byte of 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE and 0xFF depending on the length of the Mark After Break. In each case the START CODE would then be considered the Channel 1 value. ERRORs result!
  • With a short Mark After Break the UART might look at a low bit value in the START CODE as a missing STOP BIT and generate yet another FRAMING ERROR. Again depending on the timing the START CODE might be returned as 0x80 with the first STOP BIT actually being interpreted as the MSB. In this case the Channel data is properly positioned. This is actually the most common mode I am seeing in the current set up. It is timing sensitive. This is also an ERROR!

If you follow this logic you might see that it is possible that it may take a couple of regular slot times before the UART grabs something it is happy about. It is all about the synchronization aspect of the hardware design.

The question is how to know when you are receiving valid data and properly aligned slots? Is there a solution to this?

A UART that requires a Marking Condition before attempting to detect a START BIT (falling edge) would function properly. Apparently they don’t work this way. At least not all of them.

UART Issue

The problem that we run into is an ancient design flaw in serial ports.

A Framing Error results when the UART (RX SCI) expects a Stop Bit and none is detected. A Stop Bit is a high (1 Marking) and during a Break Condition the signal is held low (0 Space) so a Framing Error is quickly encountered. Now most descriptions of UART logic suggest that after a Break the UART locates the next Start Bit (0 Marking) and that this is detected by a high to low transition of signal (1 -> 0). Logically it is done that way for asynchronous reception as the UART clock needs to synchronize and then sample the middle of each bit period.

In reality after a Framing Error the UART seems to see the next low (0 Space) as a Start Bit and continues to read bit data. As a result Framing Errors are repeated throughout the break period. A bogus byte value might appear to be properly read if the tail end of the Break Condition aligns with the UART in a way to make the high (1 Marking) after the Break look like a Stop Bit.

The likelihood of this bogus data byte and its content can vary depending on the length of the Break and the length of the Marking after the Break and before actual data is present. Since bytes are serialized LSB first these extra bytes look like one of 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 and even 0x00.

If the Marking after Break is brief (only a few bit times) and the alignment falls such that the UART looks at bits in the first byte of data for that magic Stop Bit, you will receive an incorrect value for the fist byte. It is conceivable that the UART might take several bytes before synchronizing and providing real data.

If the UART simply fell into a mode whereby it actually did search for the next Start Bit by looking for a valid high to low transition (1 -> 0), you would get a single Framing Error followed by the proper collection of data. But no… after 50+ years we have not addressed this issue. I half recall struggling with this exact thing maybe 30 or so years back now. The fact that it is still an problem is not impressive.

I guess I shouldn’t be surprised in that these hi-tech MCU processors all still include the Real Time Clock (RTC) circuit first designed for the very first digital watches in the late 1960’s. This forces us to parse time into Day, Month , Year, Hour, Minute and Seconds as if setting a watch on your wrist. In fact Seconds can only be reset to 00 and not directly set. On boot we have to read the time and reassemble it into Linux or Internet time as a tally of milliseconds since some epoch. Lots of work that causes loss of precision. And the ideal would be a non-volatile battery-backed 64-bit millisecond counter. Sometimes silicon space is limited and this counter would save lots of that. But no… these integrated circuit companies aren’t as swift as we would like to think.

Since DMX512 signals can have different lengths of Break and Marking after Break and these can vary depending on source, and since the protocol has no leading header that can be used in identifying valid frames, we are NOT ABLE to reliably receive data. Note that if the DMX512 Standard had forced the Mark After Break to be at least one data Slot long (> 44 microseconds) then UARTs would likely properly synchronize and reliably present the first byte of data. But the spec does not and the problem is that changing the standard now does not correct all of the DMX controllers already in use all over the world. So it is what it is.

So for us to insure that we read a valid frame, we need to resort to some trickery, filtering and indeed AI. While that can be fun, it’s unfortunate.

Name Version Release Date Size MD5
JANOS - UPD v2.3 Feb 03 2023 954.6 KB a1b9bcde0a4768bfdcfbc11704c06634
Series 4 All-In-One Update Project v2.3 Feb 03 2023 1.8 MB 9308e8af6b59c480a3a75ff43158ab40
Core JANOS Update Project v2.3 Feb 03 2023 1.1 MB 46faa801012faeae4f4b1310e18706c8
JANOS Release Notes v2.3 Jan 25 2023 447.5 KB eee5c466e41038127aa4a37f5c67a294

The release fixed an issue with the Ethernet becoming “locked up”. The JNIOR could become unresponsive while servicing the network on busy networks.

Build 1.0

  • Corrected memory issue with KILL and message loop use
  • Corrected garbage collection issue with static classes in the JVM
  • Corrected memory issue with serial port buffer resizing
  • Delayed Java Thread startup to insure completion of initialization
  • Added KILL -A feature to terminate all applications

 

Initial (January 25 2023)

  • Initialized the Working Directory for command line scripting
  • Increased network frame buffers to improve throughput
  • Increased number of available application watchdogs from 8 to 16
  • Added WDT_SILENT so watchdogs can be used to schedule programs and not logged as triggered
  • Updated PS process listings to display pending watchdogs as scheduled execution
  • Improved PING statistics
  • Eliminated assertion in loading classes using InvokeDynamic
  • Eliminated memory leak in JVM class caching
  • Corrected IO signature performance with IO changes
  • Corrected TAB auto-complete issue with second parameter
  • PHP Registry lists now sorted by name
  • Eliminated chance of socket deadlock that would require a hard reboot
  • Added check for network during boot logging to avoid reboot loop

JANOS 2.2 Release June 28, 2022

This release was issued to support manufacturing and component changes forced by supply chain issues. Because of this, an update to the OS was required to handle this change. Units made June 22nd, 2022 or later will NOT be able to roll back to earlier version of JANOS.

  • Corrected bug in creating multidimensional arrays
  • Improved DEFLATE compression performance with binary files
  • Corrected issue with '%' sign when logging to the syslog
  • Fixed dropped serial character when port is closed
  • Added experimental debugging tools

JANOS 2.1.1 Release December 15, 2021

  • This release was issued to support manufacturing and component changes forced by supply chain issues and COVID

JANOS 2.1 Release August 10, 2021

All New Help system. Use the [Help Search] link in the lower right on the JNIOR Web UI.

  • Eliminated external SYSLOG Server related memory leak
  • Corrected Regex issue with the OR operation
  • Corrected PHP ereg() and eregi() functions
  • Implemented a greatly expanded Help System
  • Added PDF MIME type to the WebServer and Email systems
  • Corrected JRMON latched input [R]eset command, no longer affects relays
  • PHP read file access expanded to include ZIP virtual folders
  • Corrected PHP issues with JSON arrays
  • Corrected Order of Precedence issue with PHP mathematical expressions
  • Corrected the operation of Regex '*' and '+' quantifiers when used following a group
  • Corrected RENAME behavior when attempting to alter case of a filename
  • Enabled PHP logical string comparisons ==, !=, <, <=, >, and >=
  • Enhanced security for JANOS-Session-Id cookies
  • Corrected JANOS-Session-Id handling when multiple cookies are present
  • Improved non-volatile aspect of command line history
  • Corrected issue with network capture completion
  • Fixed issue introduced in v2.0 with IpConfig/Allow
  • Corrected issue with using EXIT in the Console tab of the WebUI
  • Added SHA256 (SHA2) to the MANIFEST database
  • Fixed issue resulting in blank Registry keys being displayed
  • Introduced new expanded Help System

JANOS 2.0 Release March 4, 2021

  • Improved serial diagnostics during boot
  • Added DST rules for New Zealand timezones
  • Added File Sharing. Disabled by default
  • Logs prior Registry key values along with changes
  • Enabled NetBIOS name resolution and disabled LLMNR
  • Allow product "Birthname" such as jr817120068 to be always valid in name resolution
  • Corrected Websockets login issue
  • Fixed issue with HTML Email content
  • Added SHA384 and SHA512
  • Added text form of IP address to certificate to appease Microsoft IE
  • Enhanced Registry key settings to inform as to reboot requirements
  • Improved Email error reporting
  • Added Galois/Counter Mode (GCM) to TLS security suites
  • Removed legacy Registry editor
  • JANOS renews its own self-signed certificates
  • Added JSON support to PHP
  • Added Command Line text editor
  • Added Elliptic Curve TLS suites
  • Added BAT file enhancements and scripting support
  • Added the ability to retrieve files from remote servers to JRUPDATE
  • IP address filtering overridden by SAFE MODE
  • Add capture filter information to pcapng capture file
  • PHP scandir() changed to return absolute file path
  • Issue with /etc folder content in scandir() corrected
  • Corrected issue with nested PHP foreach loops
  • Added PHP date and time formatting function date()
  • Console command line history search and selection enhancements
  • Added PING Flood Mode and addressing validation option
  • Corrected issue with ZIP/JAR decompression failing with some large binary files
  • Added support for the standard loopback address range
  • Default WebServer/Path is now /flash/www/config allowing relocation of the default configuration pages
  • Corrected Registry issue with of Type 10 temperature sensors
  • Batch parameter %0 now returns the command from the command line
  • Corrected runtime issue with PHP replacing existing array content
  • Addressed differences in Linux based terminal sessions
  • Extended the ECHO command for use in scripting
  • Added JMP Protocol port for use in defining capture filters
  • Added JMP port and BuildTag to Beacon protocol
  • Corrected PHP @strrpos()@ and syntax shortcomings
  • Enhanced ARC/ZIP/JAR command
  • Improved compatibility with Linux terminal emulators

JANOS 1.9 Release February 3, 2020

Release Notes

We have released JANOS v1.9 which has several changes and bug fixes. Most notably with TCP packet generation. While it is not wrong to send data in multiple TCP packets, many devices incorrectly implement TCP clients and fail when this case arises. This version adjusted the release of socket data to reduce the chances that a message might be split across separate TCP packets. This had been a recent issue with some MODBUS client devices.

  • Added support for Reverse LLMNR allowing network scanners to label IP addresses with hostnames
  • Adjusted the release of socket data to reduce the chances that a message might be split across separate TCP packets
  • Corrected Sockets race condition that caused occasional reception delays and blocking
  • Fixed the incorrect signed display of large input counter values in JRMON and JMP Protocol
  • Adds a BEACON announcement in the event of an IP conflict
  • Improved NONCE management eliminating possible issues in the presence of port scanners
  • Eliminated chance of buffer overrun occurring in FTP transfer
  • Beacon REBOOT now works in all cases
  • Eliminated potential difficulty in obtaining network capture file

JANOS 1.8 Released June 17, 2019

Release Notes

We have released JANOS v1.8 which adds the JMP Protocol. The JANOS Management Protocol (JMP) is essentially the JSON message interface utilized by JANOS Websockets. The JMP Protocol has been exposed on its own TCP/IP port. This encloses the JSON messaging in a JSON array along with the JSON Object length making reception of the messages easy. The JMP Protocol will be used by the QSC Q-SYS JNIOR component.

  • Implements the JANOS Management Protocol JMP
  • Adds "Block" command to JSON interfaces
  • Web Server limits the effects of extremely slow connections.

JANOS 1.7.1 Released December 3, 2018

Release Notes

  • Watchdog no longer causes reboot from foreground execution
  • REGEX Alternation '|' has been corrected to properly work in Group
  • Corrected NULL Pointer write issue when a Group which employs alternation appears at the start of a REGEX expression
  • Resolved message pump memory issue relating to process termination
  • Expand the channel range for setOutputRelay() from 0-11 to 0-15
  • Corrected network capture filtering when an IP address is to be excluded
  • Supports networks using Jumbo Frames
  • Eliminated assertion associated with improper use of '%n' in System.out.printf.

JANOS 1.7 Released July 26, 2018

Release Notes

  • Added ability to load single CA Certificate to be supplied on TLS connection
  • Support TLS Client Certificate Verification on outgoing connections
  • Added legacy PKCS1 support for externally generated certificates
  • Corrected array issue with processing of deferred email transmissions
  • Corrected memory issue with TAB use on the Command Line

JANOS 1.6.5 Released May 22, 2018

  • Corrected FTP listing issue created by the v1.6.4 release
  • Corrected getRegistryList method memory leak
  • Corrected 412DMX light Flickering
  • Corrected 412DMX NAND Flash processing issue
  • Corrected FTP transfer restart issue
Name Version Release Date Size MD5
Series 4 All-In-One Update Project v2.3 Feb 03 2023 1.8 MB 9308e8af6b59c480a3a75ff43158ab40
    • JANOS updated to 2.3
    • Serial Control 7.2
    • Serial-to-Ethernet 6.2
    • SNMP 3.1
    • Modbus Server 1.9
    • Slaving 3.1
    • WebUI Pages 3.2.1

Series 4 All-In-One 2.2 Release June 28, 2022

Name Version Release Date Size MD5
Series 4 All-In-One Update Project v2.2 Nov 28 2022 1.8 MB b7a5a516026b226736f97539113528c1
    • JANOS updated to 2.2
    • Serial Control updated to 7.2
    • Serial-to-Ethernet updated to 6.2
    • SNMP 3.1
    • Modbus Server updated to 1.9
    • Slaving updated to 3.1
    • New Bundled Web Pages Install
    • WebUI Pages updated to 3.2.1

Series 4 All-In-One 2.1.1 Release December 15, 2021

  • JANOS updated to 2.1.1
  • Serial Control 7.0
  • Serial-to-Ethernet 6.1
  • SNMP 3.1
  • Modbus Server 1.7
  • Slaving 2.0
  • WebUI Pages 3.1.0
  • This release was issued to support manufacturing and component changes forced by supply chain issues and COVID

Series 4 All-In-One 2.1 Release August 10, 2021

  • JANOS updated to 2.1
  • Serial Control 7.0
  • Serial-to-Ethernet updated to 6.1
  • SNMP 3.1
  • Modbus Server 1.7
  • Slaving 2.0
  • WebUI Pages updated to 3.1.0
  • New Web Page Manual Install

Series 4 All-In-One 2.0 Release March 8, 2021

  • JANOS updated to 2.0
  • New Tasker 6.0 install
  • Serial Control updated to 7.0
  • Serial-to-Ethernet 6.0
  • SNMP updated to 3.1
  • Modbus Server 1.7
  • Slaving updated to 2.0
  • WebUI Pages (was called Dynamic Configuration Web Pages) updated 3.0.1. WebUI Pages now uses flash/www/config.zip file instead of flash/www.zip which has been renamed to flash/www.zip.old

Series 4 All-In-One 1.9 Release May 1, 2020

  • JANOS updated to 1.9
  • Serial Control 5.0
  • Serial-to-Ethernet 6.0
  • SNMP updated to 2.6
  • Modbus Server 1.7
  • Slaving 1.5
  • WebUI Pages (was called Dynamic Configuration Web Pages) updated to 2.4

Series 4 All-In-One 1.8 Release June 18, 2019

  • JANOS updated to 1.8
  • Serial Control 5.0
  • Serial-to-Ethernet updated to 6.0
  • SNMP 2.4
  • Modbus Server 1.7
  • Slaving 1.5
  • WebUI Pages (was called Dynamic Configuration Web Pages) updated to 2.3

String Converter is an application that works as a middle man between two devices trying to communicate with each other, converting the commands between them so they can understand one another. This post aims to explain how this application is setup to work after installing it on your JNIOR.

To configure StringConverter, you’ll first open a web browser and enter the in the URL your JNIOR’s IP address followed by “stringconverter”. For example, if your JNIOR’s IP address is 10.0.0.100, StringConverter’s URL in the web browser will be “10.0.0.100/stringconverter”. 

After accessing StringConverter’s Web Page, the first thing you’ll need to do is setup the connection settings at the top of the page. There are two connections you are setting up: one for the device sending to the JNIOR (Server Settings), and one for device the JNIOR is sending to (Client Settings). This communication can go from Client, to JNIOR, to Server as well though.

String Converter handles the connection scheme of Server -> JNIOR -> Client AND Client -> JNIOR -> Server

Ethernet and Serial Connections

When settings up the connections for String Converter, you can either have a Serial connection or an Ethernet connection for the Server and Client. Serial and Ethernet connections will require different settings to connect, but will always have a field for the Termination String. So before explaining the settings of each type of connection we’ll go over the Termination String. The Termination String is used to determine when the end of a command has been reached. Termination Strings are not required, but if not entered String Converter will wait for a timeout. This means after a device has sent to a command to the String Converter application, it will wait for small amount of time and if nothing else was sent it assumes the command has been fully sent.

Ethernet Settings

For the Ethernet settings, for the Server Settings only the port number value is listed, because the IP will always be the JNIOR’s IP. The port value should be set to listen for the device sending to it. (If the device is sending on port 9222, the set the server port number value to 9222) For the Client, the IP field will be there and requires the IP and port number of the device the JNIOR is sending to.

Serial Settings

For both Server and Client Serial Settings, you only have to declare if the Serial connection is going to the AUX or COM (RS-232) port of the JNIOR. 

As the note says in the picture, both the Server and Client can’t be set to the same Serial port. StringConverter will not save if this happens.

If the device connecting to the JNIOR has specific Serial settings, you’ll need to set the JNIOR to match them. This is set on the JNIOR Web Page in the Serial I/O section under the Configuration Tab.

Lastly, when entering the connection settings for the Server and Client, fields other then the termination string can’t be left empty. This is true for both Serial AND Ethernet connections of the Server and Client, meaning if you are using a Serial connection for the Server or Client, the Ethernet settings for them cannot be left blank even while hidden. String Converter’s web page will not let you save if a field (other then the Termination String) in the Server or Client’s connections settings is left blank. Dummy data can be entered to get around this.

Conversions

Once the connection settings have been entered, the next section to setup is the Conversions. In this section there are conversions from the Server to the Client, and conversions from the Client to the Server. 

The arrows between the conversions indicate what the command is being converted to. For example if under Server to Client Conversions you have “test  >>>  testing”, that means that if the Server sends “test” to the String Converter application, it will convert it to “testing” and pass that command over to the Client. 

NOTE: When making conversions, make sure a command doesn’t have multiple conversions. An example would be having one conversion be “test  >>>  testing” and another conversion be “test  >>>  tester”. StringConverter wouldn’t know which conversion to use for test because it has more then one defined, and will not save if you do this.

Hex

Hex can be entered in conversions regardless if its being sent from the Server or Client. Hex values should be formatted as \x00 for each hex value with no spaces between them.

Regex

Regex or Regular Expression, is a sequence of characters that represents a search pattern in text. Regex can be used to represent certain parts of text without specifically entering them. A good example of how this is useful is if you are trying to make conversions in StringConverter for commands that set the volume of device. If the devices range of volume is 1 – 100, and you want conversions to handle each volume level, you’d have to make one hundred conversions! To avoid that, you can use a regex pattern to represent the digit of the volume, while specifying the rest of the command that would be used to set the volume. When implementing Regex for each grouping of values, they can each be substituted in for by order. In the order they are defined in the conversion from left to right, the first grouping is represented by %1, the second by %2, the third by %3, etc. regexr.com is a good place to try out testing and understanding regular expressions if you are unfamiliar with them.

Saving

After you have defined your connection settings and conversions correctly. You’ll want to save your settings for StringConverter. Either at the bottom right or top right of the page should have a Save button. Select this, and if there are no errors in your configuration it will save. If it doesn’t save, then that means you need to look back through and make sure you have everything filled out, that no commands have multiple conversions for themselves, and that the Serial setting aren’t set to the same Serial port. After saving, the last step is to restart the StringConverter application. The easiest way to do this is by rebooting the JNIOR. This is needed to make sure the JNIOR is listening and connecting on the right connection settings. Now StringConverter should be ready to convert commands between your two devices!

We have given the knowledge-bases a new look and feel.  This is intended to make finding information easier.  Once within the knowledge-base, a new vertical navigation menu on the left hand side will help you find similar posts while staying within that knowledge-base section. There are 5 different Knowledge Bases that were created based off the amount of content on our site pertaining to an application or use for the JNIOR. Here is a brief overview of each knowledge base.

General Knowledge Base

The General Knowledge Base focuses on providing posts that explain configuring and using the JNIOR Web UI and Support Tool, the hardware capabilities of the JNIOR, and steps that can be taken to troubleshoot when things don’t work. This Knowledge Base is where general questions about the JNIOR can be solved.

Tasker Knowledge Base

The Tasker Knowledge Base contains posts going over specific features of the Tasker application. Creating and managing workspaces, setting up connections to different devices through Tasker, and setting up Triggers and Schedules to activate tasks in Tasker.

Cinema Knowledge Base

The Cinema Knowledge Based contains posts over specific features of the Cinema application. It can explain how to create and execute macros, setup the Preshow and Cinema Server Clients, and how to troubleshoot connections made to the Cinema application.

DMX Knowledge Base

The DMX Knowledge Based contains posts over specific features of the DMX application. It can explain how to create triggers, scripts, and fixtures, how to potentially use a JNIOR 410 as a DMX controller, and how to use the JNIOR as a DMX fixture itself.

Embedded Programming Knowledge Base

The Embedded Programming Knowledge Base contains a wide variety of coding examples to create applications that run on the JNIOR. Here the JANOS runtime library can be downloaded and used in projects. Each section contains examples of short applications that can show how to do certain functionality on the JNIOR.

What is the tail command?

The tail command is used to display the last n lines of a specified file.  By default the tail command displays the last 10 lines of a file.  This can be changed by using the -n argument and specifying a new value.  If the specified file does not contain at least n lines then a the .bak version of the file will be prepended, if it exists.

Another powerful feature of the tail command is its ability to monitor and display file changes in real-time.  The specified file in monitored for changes once a second and only the changed portion of the file is displayed.

Usage

tail [OPTION]... [FILE]...
Short OptionsLong OptionOption ValueDescription
-n–linesNUMBERThe number of lines that should be displayed from the end of the file
-f–followMonitor the file in real-time

Default Usage

The default usage will show the last 10 lines of the specified file.

Specify number of lines to show

We can use the -n or --lines option to specify 20 lines.

Update the file in real-time

Use -f or --follow to follow the file in real-time.  New entries will be displayed.  This command will not return to the prompt until ANY key is pressed.

How to Install tail

There are multiple ways to get tail on your JNIOR.

Update Project

[Download not found]
Name Version Release Date Size MD5

jrget

You can issue the following jrget command from the command line. Go to the getting started with the jrget utility post to learn how to use the command line tool if you need help.

jrget tail

The JNIOR 410 is capable of handling RS-485. To do this you need to wire it correctly.

While RS-485 is commonly referred to as 2 wire, it really should include a third wire for ground. You can get away with 2 wires as long as there is a common ground between all devices. This is hard to guarantee, especially on long runs. Including the third wire is always a good idea.

RS-485 should also include termination resistors at the end of the bus. This helps prevent reflection on the wire from corrupting the communications.

Here is an article from TI on Ten Ways to Bulletproof RS-485 Interfaces.

2 wire

Again, while referred to as 2 wire, a ground wire is good practice.  In this wiring scenario D- will be landed on pin 3 and a small jumper wire will be used to connect pin 3 to pin 2.  D+ will be landed on pin 7 or pin 8 and a small jumper wire will be used to connect pin 7 to pin 8.

        Signal         DB-9
--------------------  ------
Signal Ground (GND)      5
Data (D-)                2, 3
Data (D+)                7, 8

4 wire

While referred to as 4 wire, a ground wire is good practice.

        Signal         DB-9
--------------------  ------
Signal Ground (GND)      5
RS485 TX-                2
RS485 RX-                3
RS485 RX+                7
RS485 TX+                8

DB9 Breakout Connector

You can make wiring of the DB9 connector easier by obtaining a breakout board like this one from Amazon.

Here is an example of wires landing on pins 7 and 8 with a small jumper wire.

RS485 to RS232 converter

Use an RS485 to RS232 converter and let the JNIOR handle the RS232 data.  This will enable 412 and 414 JNIORs to handle RS485.

The Support Tool has a macros tab for creating macros that are used in the Cinema application. Creating macros is a great way to get more functionality from issuing commands to the JNIOR. This post will explain how to create and upload macros to your JNIOR.

To create macros you need to have the support tool download, which you can get here. Once the support tool is downloaded, you’ll open it and go to the macro tab. In the macro tab is where you can create and upload macros to your JNIOR. To add a new macro, you’ll select the ‘add’ button at the bottom left of the update tab and select ‘macro’. With the new macro added, you can click on the new macro to edit its name.

After adding and naming the macro, you can then add actions to the macro. The actions are on the right side of the update tab and you can add new actions at the bottom of the action view, or edit existing ones by selecting them and editing the values in their columns. By selecting the macro and then the action you can select the arrow button between them to add the action to the macro.

Once you finish adding your macros and actions, you’ll then need to save and publish your macro file to your JNIOR by selecting the ‘publish to JNIOR’ button. This will prompt you to save your macro file. After you save, you can then select your JNIOR to publish to. With that you’ll have created and published your macro file to a JNIOR. Now when the JNIOR receives a command to execute a macro you created, it will go through and execute each action inside the macro in order.

View on GitHub

The PowerEventLog application uses an immutable array to keep track of when the JNIOR turns on and off. It takes the values in an immutable array and stores them in a log file called powereventlog.

The application starts by checking if another instance of  itself is already running. If there is one already running, the instance of it trying to launch terminates itself. After checking that, it then gets the time that the application started on the JNIOR. The Immutable block is then returned (or created if it doesn’t exist yet.) to hold/retrieve the values of when the JNIOR last turned off and when it booted up again. The stop and start times of the JNIOR are re-formatted as date strings to be more readable. The log files being created are then checked to see if a backup needs to be created. Lastly, the stop and start times of the JNIOR are written to the log file, and then the times are updated for the next time the JNIOR turns off.

View on GitHub

JBakup is an application that is running on the JNIOR to help extend the life of your log files.  It does this by monitoring the filesystem for the creating of a .log.bak file.  This logic runs just once every 15 minutes.  When a .log.bak file is found that has NOT been previously processed then it is added to the .zip of the same name in the flash/baks directory.

The JAVA application doesnt take care of the zipping of the backup file data but rather creates a script that the OS executes using the ARC command.

The code is small and should be easy to follow.

After configuring the JNIOR properly, a way to send an email from it is to use the MailComposer class. This function has the user define the email being sent by building different parts of the email (Email address being sent to, Attachments to add, anyone that needs CC’d, subject, message, etc). Once these are all defined, you can use the MailComposer’s send() function to submit the email.

package emailexample;

import com.integpg.system.JANOS;
import com.integpg.system.MailComposer;

public class EmailExample {

    public static MailComposer mail = new MailComposer();
    
    public static void main(String[] args) {
        
        mail.setToAddress("YOUR EMAIL HERE");
        mail.setSubject("MailComposer Test");
        mail.setMessage("This was built and sent using the MailComposer Class.");
        mail.send();
        
    }
    
}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. After it has successfully run, I check my email and have received one from the MailComposer example.

After configuring the JNIOR properly, a way to send an email from it is to use theJANOS.sendmail() function. The .sendmail() function needs the name of a mail-profile on the JNIOR that you defined earlier, the subject of the email, and the email’s message.

package emailexample;

import com.integpg.system.JANOS;
import com.integpg.system.MailComposer;

public class EmailExample {

    public static MailComposer mail = new MailComposer();
    
    public static void main(String[] args) {
        
        JANOS.sendMail("YOUR EMAIL-PROFILE HERE", "EmailExample", "This was built and sent from the JANOS class.");

    }
    
}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. After it has successfully run, I check my email and have received one from the JANOS.sendmail() example.

You can easily pulse an output using Tasker.  From an open Workspace you will click + Add Action… to get the Add Action dialog.  From there you will select Pulse Relay (channel, duration).

Once the action has been added you will need to configure the correct channel and duration.

On every JNIOR, there is a System Message Pump that is constantly circulating any message sent between applications. Each message sent around the system has a unique type that identifies the message. This is done so when an application receives a message, it can determine if the message was meant for it. If the message was for that application, it consumes the message and reacts accordingly for the what the application is doing. If its not meant for it, then it simply re-broadcasts the message so the next application can evaluate the message until the correct application receives it. 

Message Types

As far as the different types of messages that can be sent, there are two groups. The first group is the system messages, which are predefined and reserved only for the OS to use when its performing checks and tasks. Message numbers below 1024 (0x400) are reserved for the system. The most common example of this is the SM_PROBE (0x02) message. This is a message that isn’t supposed to be consumed by other applications and is supposed to make its way back to the OS after its sent. If the message doesn’t come back, then it knows somethings wrong, and an application is consuming messages it shouldn’t be. It fixes this by restarting the OS. Here are other predefined system examples the JNIOR OS uses. The other group of messages are user defined messages. These messages can have any message number at or above 1024 (0x400), and can be given any message a user would wish to define for the message. 

Message Example

Below is an example of two applications communicating with one another using a user defined message. They use the System class to declare a MessagePump and SystemMsg objects. The first application opens the message pump and permanently loops, only pausing the loop when its listening for the message. When it receives a message with type 1600 it prints the string in the message and continues the loop again. The second application opens the message pump, sends a user defined message containing a string and the message number 1600, and then closes the pump.

package messagepumpexample;

import com.integpg.system.MessagePump;
import com.integpg.system.SystemMsg;
import static java.lang.Thread.sleep;
import java.util.Vector;

public class MessagePumpExample {

    private static final MessagePump MESSAGE_PUMP = new MessagePump();
    private static final Vector LISTENERS = new Vector<>();
    
    public static void addListener(MessagePumpListener listener) {
        
        synchronized (LISTENERS) {
            LISTENERS.addElement(listener);
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        MESSAGE_PUMP.open();
        while (true) {
            System.out.println("looping");
            // read all messages from the message pump
            SystemMsg systemMsg = MESSAGE_PUMP.getMessage();
            // we must repost as fast as we can
            MESSAGE_PUMP.postMessage(systemMsg);
            String message = new String(systemMsg.msg); 
            if (systemMsg.type == 1600) {

                System.out.println("Recieved command 1600.\n");
                System.out.println(String.format("The message was: %s\n", message));

            }
            sleep(10);
        }
    }
    
}
package messagepumpexamplesender;

import com.integpg.system.MessagePump;
import com.integpg.system.SystemMsg;
import static java.lang.Thread.sleep;

public class MessagePumpExampleSender {

    private static final MessagePump MESSAGE_PUMP = new MessagePump();

    public static void main(String[] args) throws InterruptedException {
        MESSAGE_PUMP.open();
        SystemMsg systemMsg = new SystemMsg();
        systemMsg.type = 1600;
        systemMsg.msg = "This message is from the MessagePumpExampleSender".getBytes();
        MESSAGE_PUMP.postMessage(systemMsg);
        sleep(5000);
        MESSAGE_PUMP.close();
    }
    
}

I put the built jar files of these example applications into the JNIOR’s flash folder and ran one from from the Web UI’s console tab and the other from a command line connection. As shown below, one application constantly loops through itself, pausing when its trying to get a message from the message pump and then printing the message out when it does. The other sends the message the first one is listening for.

NOTE: In the picture above, the message only prints out once, while other times it just goes through the loop without printing the message. This is because we only handle one type of message, 1600. If it continues through the loop without printing a message, it means it got a message with a number type that wasn’t 1600. The other message its getting is most likely the SM_PROBE (0x02) message.