Programming Tips

Once a JNIOR is up and running in an application it rarely needs attention. In fact many users forget that it is even there. It is however good practice to check the system logs once and a while. Fortunately there are a number of ways that you can do that. If you open the DCP (Dynamic Configuration Pages) by accessing the unit with a browser there is a ‘Syslog’ tab. This displays the log with the most recent events right at the top. You can also go to the ‘Console’ tab or otherwise open the Command Line through a Telnet connection or the serial port where you can list the log content directly to the screen or window. In this case the latest entries are the last listed.

If you are developing a new application and testing it on the JNIOR you may wish to monitor the log more closely. Naturally you can leave the DCP open on the ‘Syslog’ tab and new events would just pop up when they are logged. That might not be as convenient as it sounds especially if you are building a network-facing application and are constantly testing and working with the JNIOR using various browsers. Perhaps you are rebooting the unit causing the DCP to reconnect far too often. More typically we periodically make a Command Line connection through Telnet and manually list the log. Here we make use of the CAT command.

mqtt-test /> help cat
CAT filespec

 -H             Dump file in hex
 -J             Formats JSON
 -P             Displays last page

Displays the contents of a file.
Aliases: CAT, TYPE

mqtt-test /> cat -p jniorsys.log

Now the jniorsys.log file is limited to about 64KB characters. That can represent a lot of lines. Do you really want to list those every time? Here we see that the CAT command also provides the -P option which will show only the last page (25 lines) of the file. Of course you do have to remember to include the option. One side note here is that with JANOS you can supply the options anywhere on the line. So if you at first forget to include the -P you can place it after the filename. No problem.

We can improve on this by making use of JANOS batch file capabilities. A batch file is a kind of script file that can contain commands to be executed one after another. Most operating systems, JANOS included, provide some facility for batch execution. But you might be wondering how do you create batch files or if you do that externally how do you get them onto the JNIOR? Well here’s a tip: You can create them on the fly. Of course, the simpler the file the easier that can be accomplished.

For example we will create a simple batch file called log.bat as as kind of short hand that we can use when we want to display the System Log. Here we simply ECHO the command routing the text to the file. Immediately we can use the short batch file name to execute the command.

mqtt-test /> echo cat -p jniorsys.log > log.bat

mqtt-test /> log
cat -p jniorsys.log
10/03/18 18:54:15.850, FTP/ uploaded /flash/MQTT.jar [325.8 kbps]
10/03/18 18:54:24.571, ... (etc.)

Here we see that we used the ‘>’ pipe character to route the output to the specified file. If you need to build a batch file with more than one command you can append to it using ‘>>’ as well. The power here comes in combining commands to achieve some goal. The advantage being that you can repeat the procedure easily using the batch file name as shorthand. While batch files in JANOS are not as fully featured as you will find in Linux or MS-DOS systems most of the basics are there.

Suppose instead we want to list only today’s events. Here we create our batch file in way that lists only those entries with today’s date. Check it out.

mqtt-test /> echo grep %DATE% jniorsys.log > log.bat

mqtt-test /> log
grep 10/04/18 jniorsys.log
10/04/18 12:10:48.657, Ending session Command/ (pid 132)
10/04/18 12:37:53.642, Command/ login 'jnior' (pid 405)
10/04/18 12:38:05.179, FTP/ login 'jnior'
10/04/18 12:38:05.711 ... (etc.)

And there you go. You now have a simple way to check recent System Log activity. Now I bet that you are thinking how you might alter this to be even more helpful. Well, if you find that you cannot achieve what you have in mind just let us know. An advantage that you have with INTEG is a direct link to the technical team and the advantage we have is the power to implement what you need.

Digital Files are a given entity in the programming world. They can contain 0 to many bytes each of 256 values. Those could be ordered to represent everything from common text (ASCII) to binary bit streams (compressed data) and everything in between. Files therefore have a size and they also have a timestamp. These days that timestamp represents the date and time of the last modification to the file. They also carry permissions which can control who can access the file or even know of its existence.

There is also location. In part that means where the file is positioned within a directory or folder structure. We are also concerned with the type of media in which the file is stored. You know, did you put the file on a memory stick, on the hard drive or in the Cloud? This aspect of “location” is what we are going to consider here in this topic. Files stored on your JNIOR end up in one of four different areas but yet all appear to be in the same place. Where your file is located can affect performance and the longevity of the your data.

Each JNIOR contains multiple memory components each of which can provide for file storage. These are integrated into a single File System. There are 4 types of storage: RAM, DRAM, Flash and ROM. You actually utilize them all in routine operation. Let’s look into it.

Non-volatile Battery-Backed Static Random Access Memory (SRAM)

When you enter the JNIOR’s Console (Command Line Interface) either through the serial port, using Telnet or by opening the DCP, your working directory is the root of the File System or “/”. By performing a DIR/LS command with the -L option you see content details generally containing the system’s basic log files. You can also see that there are a number of sub-directories or sub-folders. I struggle with terminology here. Do you use “directory” or “folder”? I think that I haphazardly vacillate between the two.

bruce_dev /> dir -l
total 10
drwxrwxrwx   1 root      root           8 Jan 26 08:22 .
drwxrwxrwx   1 root      root           8 Jan 26 08:22 ..
dr-xr-xr-x   1 root      root           1 Dec 31 1999  etc
drwxr-xr-x   1 root      root          58 Jan 26 07:38 flash
drwxrwxrwx   1 root      root           0 Jan 25 15:13 temp
-rw-r--r--   1 root      root       40968 Jan 26 08:13 jniorsys.log
-rw-r--r--   1 root      root         956 Jan 26 08:13 jniorboot.log
-rw-r--r--   1 root      root        1005 Jan 26 08:00 jniorboot.log.bak
-rw-r--r--   1 root      root       40302 Jan 26 07:38 web.log
-rw-r--r--   1 jnior     root       22434 Jan 25 14:53 manifest.json
  1763.2 KB available

bruce_dev />

Now you might immediately notice that there is only 1763 KB available. That’s not very much! Is that it?

No. But the File System root is located in a 2MB SRAM. This content is protected from loss by a battery. In fact, the battery is there for this purpose and to retain the current time and date during power outage. We built some JNIORs with a more expensive 4MB part but eventually realized that it wasn’t necessary. The bulk of your file storage will be located elsewhere.

The advantage of the SRAM is it’s speed and re-usability. In addition to the file system root, JANOS locates the Registry and other immutable memory blocks here. But space here is limited and it is best to preserve this area for system use. Data stored here does come with the risk of loss. This is a small probability but not an insignificant one. First of all the battery could die. If your JNIOR is powered 24/7 the battery should be there for you for 10 years and more. But if you power down the JNIOR routinely you may get 5 or 6 years out of it. Thankfully the Series 4 batteries are replaceable and you can get them at your local convenience store. Some customers though are happy to leave the dead battery not caring if their root folder is then volatile.

Perhaps more likely is that you decide to wipe the memory. You may have an application issue that gets the system into a problem condition. It is possible and we might recommend that you “business card’ the battery. So by that we mean that you remove power from the unit, open it and slip a piece of something (business cards work well) under the battery tab for a few seconds. This clears the SRAM (and the clock). Typically you only lose the logs. The Registry and therefore your configuration is backed up by another file stored in another area. But don’t worry, we recommend that procedure very very infrequently.

If you are programming your own JNIOR you might get yourself into a reboot loop. Basically your application starts up and performs something incorrectly that throws an assertion (system restart). The JNIOR reboots and restarts your application and another assertion ensues. Okay, not a great situation. JANOS eventually will detect some forms of reboot looping and it may decide to reformat the SRAM as a last ditch effort to restore access to your JNIOR. It sounds terrible but again it is a very very rare thing.

The point is that data stored in the root of the file system offers good performance and immediate data retention. It is not your best choice for long term storage. For that you want to use the Flash memory.

Flash File System

Flash memory retains data even in the absence of power. Files written in Flash memory are therefore retained even when the battery is removed. For that reason it is the best location for long term data storage. This is where you should place all of your programs, web site files and whatever else needs to be kept around. Everything under the /flash directory/folder is located in Flash memory.

bruce_dev /> dir -l flash
total 60
drwxr-xr-x   1 root      root          58 Jan 26 07:38 .
drwxrwxrwx   1 root      root           8 Jan 26 08:22 ..
drwxr-xr-x   1 root      root           1 Dec 06 11:15 cinema_backup
drwxr-xr-x   1 jnior     root           2 Dec 10 2015  generators
drwxr-xr-x   1 root      root           1 Jan 15 09:31 logs
drwxr-xr-x   1 root      root           2 Jan 15 09:32 public
drwxr-xr-x   1 root      root           2 Feb 06 2017  somepath
drwxr-xr-x   1 jnior     root          25 Jan 26 07:03 www
-rwxr-xr-x   1 jnior     root        1081 Jan 26 07:37 JTest.jar
-rw-r--r--   1 jnior     root       22434 Jan 25 14:53 manifest.json
-rw-r--r--   1 root      root        5449 Jan 23 08:33 jnior.ini
-rw-r--r--   1 jnior     root          13 Jan 11 15:16 gogo.dat
-rw-r--r--   1 jnior     root      183358 Jan 11 09:44
-rwxr-xr-x   1 jnior     root        3043 Jan 05 10:21 JTest2.jar
-rw-r--r--   1 jnior     root         278 Dec 12 13:28 pubkey.pem
-rw-r--r--   1 jnior     root        1092 Dec 08 12:48 honeypot.cer
-rw-r--r--   1 jnior     root         272 Dec 06 13:27
-rwxr-xr-x   1 jnior     root       20266 Dec 06 09:31 Cinekey.jar
-rwxr-xr-x   1 jnior     root      313835 Dec 04 13:44 Cinema.jar
-rwxr-xr-x   1 jnior     root        8329 Nov 21 12:04 Hmi.jar
-rwxr-xr-x   1 jnior     root        2189 Oct 04 14:24 JScan.jar
-rwxr-xr-x   1 jnior     root        3201 Sep 29 15:33 JUptime.jar
-rwxr-xr-x   1 jnior     root       58619 Aug 08 15:05 ModbusServer.jar
-rwxr-xr-x   1 jnior     root        4476 Jul 20 2017  Dmx.jar
-rw-r--r--   1 jnior     root         304 May 18 2017  test.txt
-rwxr-xr-x   1 jnior     root      169011 Apr 24 2017  snmp.jar
-rw-r--r--   1 jnior     root        1041 Feb 28 2017  key.pem
-rw-r--r--   1 jnior     root         902 Feb 15 2017  bruce_dev.cer
-rwxr-xr-x   1 root      root        4820 Jan 30 2017  jAccess.jar
-rwxr-xr-x   1 root      root        2174 Jan 23 2017  jPing.jar
-rwxr-xr-x   1 root      root        5651 Jan 23 2017  JManifest.jar
-rwxr-xr-x   1 root      root        1510 Dec 22 2016  ctrlc.jar
-rwxr-xr-x   1 jnior     root       74743 Oct 10 2016  Environ.jar
-rwxr-xr-x   1 jnior     root        9680 Oct 06 2016  ftp.jar
-rwxr-xr-x   1 jnior     root        4180 Aug 16 2016  TimeSearch.jar
-rwxr-xr-x   1 jnior     root        2616 Aug 03 2016  clktest.jar
-rwxr-xr-x   1 jnior     root       13079 Jul 27 2016  rz.jar
-rwxr-xr-x   1 jnior     root        2992 Jul 19 2016  Display.jar
-rwxr-xr-x   1 jnior     root       95325 Jun 30 2016  Buffer.jar
-rwxr-xr-x   1 jnior     root      112411 Jun 08 2016  slaveservice.jar
-rwxr-xr-x   1 jnior     root        5811 Jun 07 2016  UdpTest.jar
-rwxr-xr-x   1 jnior     root        5580 Jun 06 2016  jModule.jar
-rwxr-xr-x   1 jnior     root         969 Jun 02 2016  IntelliJ.jar
-rwxr-xr-x   1 jnior     root        1903 Jun 02 2016  Benchmark.jar
-rwxr-xr-x   1 jnior     root        4532 Mar 08 2016  SerialTest.jar
-rw-r--r--   1 root      root         898 Feb 10 2016  current.key
-rwxr-xr-x   1 jnior     root       32187 Dec 17 2015  serialcontrol.jar
-rwxr-xr-x   1 jnior     root      106794 Dec 10 2015  Utility.jar
-rwxr-xr-x   1 jnior     root      163902 Sep 04 2015  AnalogPresets.jar
-rwxr-xr-x   1 jnior     root        5053 Jul 28 2015  0-10vtest.jar
-rw-r--r--   1 jnior     root         898 Jul 24 2015  jnior1024.key
-rwxr-xr-x   1 jnior     root          56 Jul 10 2015  clean.bat
-rwxr-xr-x   1 jnior     root          17 Jun 30 2015  dirs.bat
-rwxr-xr-x   1 jnior     root        3862 Jun 18 2015  Test4to20.jar
-rwxr-xr-x   1 jnior     root       46590 Jun 18 2015  task.jar
-rwxr-xr-x   1 jnior     root        3601 Jun 18 2015  ThreadTest.jar
-rw-r--r--   1 jnior     root        4311 Jun 08 2015  task.ini
-rwxr-xr-x   1 jnior     root       25266 Jun 05 2015  serialethernet.jar
-rwxr-xr-x   1 jnior     root        2993 Jul 12 2013  4routtest.jar
-rwxr-xr-x   1 jnior     root        3142 Jan 17 2013  jPanel.jar
  26.85 MB flash available

bruce_dev />

Okay so my development unit is full of all kinds of stuff. Here you will notice that even so there is some 26 MB of file storage available. For the JNIOR that is a lot. You aren’t dealing with large graphics files and such on the JNIOR. But if you were to develop a really sophisticated website hosted by the JNIOR you might fill that. If that is the case you might want the new 412DMX.

412dmx_r00 /> dir -l flash
total 22
drwxr-xr-x   1 root      root          20 Jan 11 09:45 .
drwxrwxrwx   1 root      root          16 Jan 23 13:27 ..
drwxr-xr-x   1 jnior     root          13 Oct 17 14:06 www
-rw-r--r--   1 jnior     root      183358 Jan 11 09:45
-rw-r--r--   1 root      root        2055 Dec 12 15:16 jnior.ini
-rwxr-xr-x   1 jnior     root        4526 Dec 05 14:15 Dmx.jar
-rwxr-xr-x   1 jnior     root        1597 Nov 17 07:34 ident.jar
-rw-r--r--   1 jnior     root       15584 Nov 07 09:04 manifest.json
-rw-r--r--   1 jnior     root       46000 Oct 12 12:37 string-test.dat
-rw-r--r--   1 jnior     root       20000 Oct 12 12:37 four-byte-test.dat
-rwxr-xr-x   1 jnior     root       42138 Oct 12 12:36 Benchmark.jar
-rw-r--r--   1 jnior     root       65481 Oct 11 11:10 lorem-ipsum.txt
-rwxr-xr-x   1 jnior     root       37110 Oct 05 14:51 MidNiteSolar.jar
-rwxr-xr-x   1 jnior     root       98569 Oct 03 13:51 ModbusClasses.jar
-rwxr-xr-x   1 jnior     root       58620 Oct 03 13:45 ModbusServer.jar
-rwxr-xr-x   1 jnior     root        3971 Oct 03 13:45 Simulator.jar
-rwxr-xr-x   1 jnior     root       95488 May 08 2017  SNMP.jar
-rwxr-xr-x   1 jnior     root      115448 May 08 2017  task.jar
-rwxr-xr-x   1 jnior     root       54247 Feb 03 2017  SlaveService.jar
-rwxr-xr-x   1 jnior     root       87637 Feb 03 2017  serialethernet.jar
-rwxr-xr-x   1 jnior     root       31640 Feb 03 2017  serialcontrol.jar
-rwxr-xr-x   1 jnior     root        9563 Feb 03 2017  ftp.jar
  509.70 MB flash available

412dmx_r00 />

Here there is close to 1/2 GB of file space. Actually we will be shipping the 412DMX with 1/4 GB capacity.

The existing JNIOR line uses a 32 MB serial Flash component. Data is written to and read from this Flash device using a serial (SPI) channel. This memory is therefore slower. This is not an issue though as JANOS uses a sophisticated caching system to handle Flash I/O. And if power is lost in the midst of a lengthy Flash write the device’s integrity is not damaged. The JANOS Flash File System uses a fault tolerant form of transaction processing. In the event of power loss (or crash) the Flash File System rolls back to the last known good configuration. As a result data stored here is likely to remain until purposely deleted. You can reformat the Flash File System but generally there is hardly ever a need to do so.

The 412DMX introduces a different Flash technology to the line. Here we employ a parallel NAND Flash memory. In addition to greater capacity the read and write access timing has significantly improved. Files stored here are accessed with almost the same performance as SRAM. In fact, in the future we may move the File System root to Flash and eliminate the SRAM altogether. Potentially the NAND Flash can be implemented on the 410, 421 and 414 and it will be considered when PCB revisions occur on those models.

Temporary Storage

Files stored in the /temp folder are considered temporary. That folder is actually located in the Heap which as I mentioned is DRAM memory. That memory is reformatted on boot. So the /temp folder always comes up being empty.

bruce_dev /> dir -l /temp
total 2
drwxrwxrwx   1 root      root           0 Jan 25 15:13 .
drwxrwxrwx   1 root      root           8 Jan 26 08:22 ..
  62.87 MB available (temporary)

bruce_dev />

The JNIORs are shipping now with 64 MB of Heap memory. The system normally utilizes only about 3 or 4 MB of that. So the /temp folder has reasonable capacity. This is twice what is available in the standard JNIOR Flash but much less than will be available in the 412DMX Flash. This is a great place to create temporary files. This provides the best performance as well.

We recommend that you transfer UPD files for updates first to the /temp folder. The advantage being that the file disappears once the update has been completed. UPD files are quite large and generally don’t fit into the File System root. You certainly wouldn’t want to leave one in the root for very long. And placing the UPD in Flash is not necessary and slow to accomplish.

An application might first create a file here and should the procedure complete properly then move it to long term storage. This is also great for files that will be accessed randomly (using a lot of fseek). You might improve an application’s performance by copying a database to /tempfirst. It would remain until reboot. Of course that is heap memory and the same memory where a large byte buffer would be allocated. So to improve performance an application might read the entire file into a byte buffer and access that directly. The load on the heap would be the same and random access would be greatly simplified.

The /etc Folder

Lastly there is the /etc folder. This is not a writable area and it is actually built into JANOS. This is where JANOS provides system files as might be necessary for application execution. That is the case now for the JanosClasses.jar file.

bruce_dev /> dir -l /etc
total 3
dr-xr-xr-x   1 root      root           1 Dec 31 1999  .
drwxrwxrwx   1 root      root           8 Jan 26 08:22 ..
-r-----r--   1 root      root      266601 Jan 11 09:58 JanosClasses.jar
  0 KB available (read only)

bruce_dev />

So since this is read-only there is no space available. This is stored within the processor in its Program ROM. Access is very fast.

It is important though as you can download this JAR file and use it in compiling your applications for the JNIOR. I would recommend getting the JAR from us or this site that not only contains these classes but source stubs and JavaDoc as well. Clearly that would help you more in development.

JNIORs are shipped with a number of default files in /flash. Some of those should be updated when JANOS is updated. In the future there may be additional files included in /etc. So it is something to keep an eye on.

In Summary

The JANOS File System appears to be centrally located and of a single directory structure. Yet it covers storage in a variety of media. One needs to keep this in mind when deciding where to place files either for temporary use or long term availability. Files in different areas experience different performance levels and different risks. Keeping this in mind you can better manage your JNIOR controller and create great applications.

To demonstrate an outgoing HTTP request I am going to use the IP Address Location service that our HoneyPot unit uses. This creates the JSONdatabase used to generate the map at .

The JANOS Runtime Library does not provide classes to handle different web requests. Perhaps over time we will supply external libraries for that. But, you can easily do that directly. And, it is probably more educational to know how things work at the low level.

The procedure is straight forward.

  1. Establish an outgoing socket. (Lines 19-22)
  2. Issue a minimally formatted HTTP request. (Lines 25-27)
  3. Read the response. (Lines 45-50)
  4. Use the data. (Line 53)
package jtest;
public class Main {
    public static void main(String[] args) throws Exception {
        // IP Address query
        String ipaddr = "";
        // Location services
        String serverHostname = "";
        int port = 80;
        // Establish a Socket, get streams, and set a timeout
        Socket dataSocket = new Socket(serverHostname, port);
        DataOutputStream sockout = new DataOutputStream(dataSocket.getOutputStream());
        DataInputStream sockin = new DataInputStream(dataSocket.getInputStream());
        // Issue the HTTP request
        sockout.writeBytes("GET /json/" + ipaddr + " HTTP/1.1\r\n");
        sockout.writeBytes("Host: " + serverHostname + "\r\n");
        // Process the response header
        int length = 0;
        String response;
        while ((response = sockin.readLine()) != null) {
            // Header ends with blank line
            if (response.length() == 0)
            if (response.startsWith("Content-Length: ")) 
                length = Integer.parseInt(response.substring(16));
        // Obtain the entire response (if any)
        response = "";
        if (length > 2) {
            byte[] resp = new byte[length];
            response = new String(resp, "UTF8");
        // Data (should be JSON)
        // Close the Socket
bruce_dev /> jtest
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Fri, 08 Dec 2017 14:01:58 GMT
Content-Length: 321

{"as":"AS7922 Comcast Cable Communications, LLC","city":"Pittsburgh","country":"United States","countryCode":"US","isp":"Comcast Business","lat":40.4406,"lon":-79.9959,"org":"Comcast Business","query":"","region":"PA","regionName":"Pennsylvania","status":"success","timezone":"America/New_York","zip":"15282"}

bruce_dev />

So you can see that the response is JSON and can be easily used.

If you replace line 53 with Debug.dump(response.getBytes()); which is the new dump method in the library the data can be more easily reviewed.

bruce_dev /> jtest
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Fri, 08 Dec 2017 14:27:52 GMT
Content-Length: 321

 7b 22 61 73 22 3a 22 41-53 37 39 32 32 20 43 6f    {"as":"A S7922.Co
 6d 63 61 73 74 20 43 61-62 6c 65 20 43 6f 6d 6d    mcast.Ca ble.Comm
 75 6e 69 63 61 74 69 6f-6e 73 2c 20 4c 4c 43 22    unicatio ns,.LLC"
 2c 22 63 69 74 79 22 3a-22 50 69 74 74 73 62 75    ,"city": "Pittsbu
 72 67 68 22 2c 22 63 6f-75 6e 74 72 79 22 3a 22    rgh","co untry":"
 55 6e 69 74 65 64 20 53-74 61 74 65 73 22 2c 22    United.S tates","
 63 6f 75 6e 74 72 79 43-6f 64 65 22 3a 22 55 53    countryC ode":"US
 22 2c 22 69 73 70 22 3a-22 43 6f 6d 63 61 73 74    ","isp": "Comcast
 20 42 75 73 69 6e 65 73-73 22 2c 22 6c 61 74 22    .Busines s","lat"
 3a 34 30 2e 34 34 30 36-2c 22 6c 6f 6e 22 3a 2d    :40.4406 ,"lon":-
 37 39 2e 39 39 35 39 2c-22 6f 72 67 22 3a 22 43    79.9959, "org":"C
 6f 6d 63 61 73 74 20 42-75 73 69 6e 65 73 73 22    omcast.B usiness"
 2c 22 71 75 65 72 79 22-3a 22 35 30 2e 31 39 37    ,"query" :"50.197
 2e 33 34 2e 37 35 22 2c-22 72 65 67 69 6f 6e 22    .34.75", "region"
 3a 22 50 41 22 2c 22 72-65 67 69 6f 6e 4e 61 6d    :"PA","r egionNam
 65 22 3a 22 50 65 6e 6e-73 79 6c 76 61 6e 69 61    e":"Penn sylvania
 22 2c 22 73 74 61 74 75-73 22 3a 22 73 75 63 63    ","statu s":"succ
 65 73 73 22 2c 22 74 69-6d 65 7a 6f 6e 65 22 3a    ess","ti mezone":
 22 41 6d 65 72 69 63 61-2f 4e 65 77 5f 59 6f 72    "America /New_Yor
 6b 22 2c 22 7a 69 70 22-3a 22 31 35 32 38 32 22    k","zip" :"15282"
 7d                                                 }

bruce_dev />

By the way, the Lat and Lon returned by these sites varies in accuracy. We use the above as a free service. I believe that some services will provide more precise locations when used in a paid mode. The free data however is just fine when mapped on the globe (

Timeouts are often required. JANOS supports timeouts on most inputs. Sometimes though you just need to implement an overall timeout. For example, if you leave an UI unattended for some period of time you might want it to return to a default Splash Screen or something along those lines.

This is easily achieved and we usually use the uptime in milliseconds as a reference. The approach is to add the timeout period to the current uptime and when the uptime exceeds that perform the timeout action. In the meantime if events occur (such as UI leypad activity) you reset the tmeout by recalculating.

Here is example code:

public class Main {
    static final int TIMEOUT = 120000;
    public static void main(String[] args) throws Exception {
        // Print time
        System.out.println(new Date());
        // establish and initialize a timeout
        long timer = JANOS.uptimeMillis() + TIMEOUT;
        while (JANOS.uptimeMillis() < timer) {
            // some event would reset the timer
            // timer = JANOS.uptimeMillis() + TIMEOUT;
        System.out.println("Timeout expired.");
        System.out.println(new Date());
bruce_dev /> jtest
Wed Dec 06 09:16:31 EST 2017
Timeout expired.
Wed Dec 06 09:18:32 EST 2017

bruce_dev />

And there you go. Close enough to 2 minutes (120000 milliseconds). Typically such timeouts need not be precise. You do not want to load the CPU doing little else than checking for timeout. If you are trying to implement an accurate delay or scheduling an event at a precise time there are other approaches. This is your quick and dirty timeout.

Note that you do not want to use the RTC time of day for this kind of timeout. That can jump discontinuously when for instance the clock is adjusted manually or through the NTP protocol.

It seems that more often than not these days (at INTEG at least) when we need to store or transfer data we are using the JavaScript Object Notation (JSON). This is also known as ECMA-404 The JSON Data Interchange Standard. I have attached the document. If you are not at all interested in JSON you should at least visit if for no other reason but to see how amazingly clearly and impressively concisely the format is described in just a single page.

JANOS uses JSON in numerous ways. Firstly, it is the data format that we use for the built-in Websockets interface that replaces the original binary JNIOR Protocol. That interface provides remote monitoring and control of the JNIOR. It is the underlying connection that makes the DCP (Dynamic Configuration Pages) possible. Secondly, the MANIFEST command uses JSON as a database format for the manifest.json reference files. And also, the JSON functionality is exposed through the JANOS Runtime Environment where it has been employed by applications for communications, databases, and configuration. The CAT command even has an option (-J) that will format a JSON text (including manifest.json) file making it readable.

From the applications point of view, JSON is handled through the java.util.Json class supplied by the etc/JanosClasses.jar runtime library. The JANOS programming environment is not your standard Java environment. This is one of many classes that we have provided allowing you to benefit from the underlying operating system. I am going to dive into this JSON class to show you what can be achieved and some of the tricks.

ECMA-404.pdf - 1 MB - MD5: a2e87492ab7c03f557c98c8ecde9c79a

I have to admit that I have been recently developing applications that utilize JSON and this forced me to refresh my memory of the java.util.Json class. There are few enhancements to that class that I might implement. So I thought that I would do that here and out in the open. I will be clear though as to what is new for JANOS v1.6.3 and what you already have available in your JNIORs.

So to start I have attached the current JavaDoc for the class. In this there is one new method getBoolean() that I have just added. Before this you needed to use the get() method and cast the returned Object it to a boolean to retrieve the logical. That by itself is not a problem. But, it wouldn’t be clear to you that you could do that.

Ok, in the process I will give the JavaDoc some attention too. Please feel free to jump in and comment.

Json-JanosRuntime-JavaDOC.pdf - 190 KB - MD5: 7ad7bc53e195b896aba20960e0013d18

By the way, if you are programming and want access to this JavaDoc you need to get the runtime JAR from us. You can develop using the etc/JanosClasses.jar runtime but that does not contain the JavaDoc. Elsewhere I describe how to configure Netbeans to build your application specifically for our runtime. Here I have attached the enhanced Runtime JAR for JANOS v1.6.2. If you configure for it you can confirm that the Json getBoolean() method is absent from the class.

JanosRuntime_1.6.2.jar - 259 KB - MD5: fc229e178cd2c76cc0c3fdf0631a7ea2

To get started we could use some examples of JSON with which to work.

You can run the MANIFEST -U command and generate an updated manifest.json for your JNIOR. That file actually is stored in two places: /manifest.json and /flash/manifest.json. One is the backup for the other. Here is what it looks like. I have to apologize as my development JNIOR has a crap load (technical term) of files on it so its a long listing. We’ll use CAT -J to format it.


bruce_dev /> cat -j manifest.json
  "date":"12/01/17 13:04:04",
bruce_dev /> 

I can get some small ones say from the protocol we are defining to the Cinema UI project. Here’s the response to a GetInfo request. And, I’ll get the response to a MacroList in a bit.


bruce_dev /> cat -j getinfo.json                                                                
  "Information":"Cinema v2.4.0.473"
bruce_dev />

Okay so here is a response to a MacroListRequest that we are using in the Cinema UI implementation. It is just another JSON example that we can work with here.


bruce_dev /> cat inforesponse.json -j
    "Preshow Start",
    "Preshow End",
    "Flat Start Trailers",
    "Scope Start Trailers",
    "Feature Start",
    "Feature Credits",
    "Feature End",
    "Start Intermission",
    "Stop Intermission",
    "Extend Intermission 15 Seconds",
    "Shorten Intermission 15 Seconds",
    "Intermission End",
    "Fire Alarm",
    "Fire Alarm Clear",
    "Lights Dim",
    "Lights Half",
    "Lights Full",
    "ticket sold",
    "no ticket sold",
    "LED Off",
    "LED Green",
    "Core Command 1",
    "Core Command 2",
bruce_dev /> 

So the file actually contains one huge string. Here I will manually wrap it.

{"Message":"GetMacroListResponse","MacroList":["Preshow Start","Preshow End","Flat Start Trailers",
  "Scope Start Trailers","Feature Start","Feature Credits","Feature End","Start Intermission",
  "Stop Intermission","Extend Intermission 15 Seconds","Shorten Intermission 15 Seconds","Intermission End",
  "Fire Alarm","Fire Alarm Clear","Lights Dim","Lights Half","Lights Full","Multiple","Test","ticket sold",
  "no ticket sold","violet","LED Off","LED Green","Core Command 1","Core Command 2","RWB"]}

let’s access the MacroListResponse and fetch data from it. The following program creates a Jason object from the content of the specified File. We need to use a File object here since we can also instantiate a Json object directly from a string. So we can’t just directly specify the filename. Once we have the object we search for the “message” name-value pair and retrieve its String content.

package jtest;
import java.util.Json;
public class Main {
    public static void main(String[] args) throws Exception {
        // Obtain Json Object from a file
        Json jdb = new Json(new File("inforesponse.json"));
        // Fetch String content
        String msg = jdb.getString("Message");
bruce_dev /> jtest

bruce_dev />

In this JSON object we know that the MacroList is an array of Strings. So it is a simple matter to itemize or list them.

package jtest;
import java.util.Json;
public class Main {
    public static void main(String[] args) throws Exception {
        // Obtain Json Object from a file
        Json jdb = new Json(new File("inforesponse.json"));
        // List the macros
        String[] macros = (String[]) jdb.get("MacroList");
        for (int n = 0; n < macros.length; n++)
bruce_dev /> jtest

bruce_dev /> jtest
Preshow Start
Preshow End
Flat Start Trailers
Scope Start Trailers
Feature Start
Feature Credits
Feature End
Start Intermission
Stop Intermission
Extend Intermission 15 Seconds
Shorten Intermission 15 Seconds
Intermission End
Fire Alarm
Fire Alarm Clear
Lights Dim
Lights Half
Lights Full
ticket sold
no ticket sold
LED Green
Core Command 1
Core Command 2

bruce_dev />

But if we didn’t know it was an array could we figure it out?

package jtest;
import java.util.Json;
public class Main {
    public static void main(String[] args) throws Exception {
        // Obtain Json Object from a file
        Json jdb = new Json(new File("inforesponse.json"));
        // List the macros
        Object obj = jdb.get("MacroList");
        if (obj instanceof Object[]) {
            System.out.println("MacroList is an array.");
            // first few entries
            for (int n = 0; n < ((Object[]) obj).length && n < 4; n++)
                System.out.println( " " + (n + 1) + ". " + ((Object[]) obj)[n] );
bruce_dev /> jtest
MacroList is an array.
 1. Preshow Start
 2. Preshow End
 3. Flat Start Trailers
 4. Scope Start Trailers

bruce_dev />

It just seems that I can make this a little cleaner. You know, like by providing an isArray() method or something along those lines.

When you are confronted with some JSON and you don’t have an official schema how do you know what is there? The get() methods require that you supply the name (or key) for an object but you might not know what name:value pairs are present. You can enumerate the structure.

Every JSON object encloses 0 or more name:value or string:value pairs in curly braces {}.

The following can enumerate the keys which are guaranteed to be strings identifying each name:value pair. Let’s work now with the MANIFEST database file to decipher its structure.

    public static void main(String[] args) throws Exception {
        // Obtain Json Object from a file
        Json jdb = new Json(new File("manifest.json"));
        // List top level enties
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) 
bruce_dev /> jtest

bruce_dev />

We can expand this to show the values associated with these keys. Note that we generically fetch the value Object and explicitly convert it to a string for display.

    public static void main(String[] args) throws Exception {
        // Obtain Json Object from a file
        Json jdb = new Json(new File("manifest.json"));
        // List top level enties
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            System.out.printf("%s = %s\n", name, jdb.get(name).toString());
bruce_dev /> jtest
model = 410
serno = 614070500
vers = v1.6.3-rc4
date = 12/01/17 13:04:04
files = {"/etc/janosclasses.jar":{"length":243492,"date":1512145376,"md5":"ece8d0ebf9b6882e488d1f7c9e764ce0","crc":"bde463c8","sha":"373b88f011b49f65eafd8e293fc185cc2563892e"},"/flash/serialcontrol.jar":{"length":31344,"date":1450364184,"md5":"b349e02b7efc64c0dfe5eb74292a5ee6","crc":"3a005104"},"/flash/serialethernet.jar":{"length":25266,"date":1433505362,"md5":"ee5e266bb8418b4223a666bd046a8c56","crc":"c3961df2"},"/flash/modbusserver.jar":{"length":51907,"date":1502219129,"md5":"77c16d6134dbd7ec93313fbad2b00d93","crc":"b7456b42","sha":"fad4ecc3d1607aafe0a385a10fb5ee90eff521bd"},"/flash/snmp.jar":{"length":239949,"date":1493062048,"md5":"b77d35c322ef6645f1eca9d22b29400b","crc":"a4073dcb","sha":"44a3c2b41a2375ef603063cc9b04642903dad973"},"/flash/www/base64.js":{"length":3493,"date":1433505378,"md5":"1138db1b5a6e165beae3ed81739dd2ec","crc":"baceb6f6"},"/flash/www/configure/index.html":{"length":1349,"date":1433505382,"md5":"0454014aecfd0b7d9e4ce1efe0979139","crc":"11ba5486"},"/flash/www/jr310applet.jar":{"length":287159,"date":1441207703,"md5":"f9c4840e7244824b75858a1a40dfb163","crc":"3d1d0c72"},"/flash/www/jniorprotocol.jar":{"length":115148,"date":1441207710,"md5":"404b40c4293bf3c334e3b88e2fe0dd10","crc":"5143ec4f"},"/flash/www/jniorprotocolhelpers.jar":{"length":34991,"date":1433505394,"md5":"b08e33e0c21e6c075b9b242bf092b68e","crc":"48990308"},"/flash/www/task/index.html":{"length":1415,"date":1433505397,"md5":"bbdc32dce371881b3eebd15f5b3fce96","crc":"cdbe02e4"},"/flash/www/taskmanagerinterface.jar":{"length":123052,"date":1433505400,"md5":"077cddccee476fab552d52a5eefd26a7","crc":"647bb4b3"},"/flash/www/jquery/jquery-1.9.0.min.js":{"length":93071,"date":1433505404,"md5":"2b869ea9c8edd4c2243c5d44f665f632","crc":"6a2a8434"},"/flash/www/jquery/jquery-ui.css":{"length":33441,"date":1433505405,"md5":"c6bd2971b8e625f2ae43ede9f655a27b","crc":"0497b7a6"},"/flash/www/jquery/jquery-ui.min.js":{"length":96395,"date":1433505409,"md5":"8f636d4c90ea0abfcbb25528c635bf7d","crc":"820662f5"},"/flash/www/vendor/bowser/bowser_0.7.2.min.js":{"length":3359,"date":1433505412,"md5":"61a36d48aad1298b17284b53f6ce3fd1","crc":"22deb9e6"},"/flash/www/text":{"length":1336,"date":1434044220,"md5":"bab65804218b18b9e1a79f2d8e873259","crc":"dda17d61"},"/flash/www/cycle":{"length":419,"date":1434044214,"md5":"9eb9bbdae70c1f994ebb7f51b18783b8","crc":"9e496eb9"},"/flash/slaveservice.jar":{"length":73323,"date":1465435094,"md5":"cd6f5e177d75675607e9523d52e133f7","crc":"9a871cd7"},"/flash/ftp.jar":{"length":9563,"date":1475783634,"md5":"793e460054f07867685e87f98fd402e6","crc":"36fd641e"},"/flash/task.ini":{"length":4311,"date":1433782061,"md5":"b1f877ac198306b266311eab557ed1dd","crc":"36a57579"},"/flash/task.jar":{"length":102655,"date":1434645611,"md5":"1979b16970127f2c38912777cb105133","crc":"ed4d6ad7"},"/flash/jnior.ini":{"length":4874,"date":1512052838,"md5":"90740fe1ddcf0ddf0774c2574e234dfe","crc":"c78e61d7","sha":"76aa475db28479a22e748e6181cf11423988c266"},"/jniorsys.log":{"length":32844,"date":1512145587,"md5":"be4968cceb2fe0b2bebf50daac17d739","crc":"637fb821","sha":"2b6b56f5e3a731b933cf6e1594dfe1e003674d6b"},"/jniorboot.log.bak":{"length":1041,"date":1512074628,"md5":"8261c4f9cd12695626755ba6d1b0b9ad","crc":"03e23ea1","sha":"761a2b3fa74a921778d1c6fc438b5bfd0d51bc29"},"/jniorboot.log":{"length":995,"date":1512145452,"md5":"f053bbba44bea8f6333702fef922d950","crc":"fa976c1c","sha":"c2665669c49028a549a2e30e10b27e8f2aba5861"},"/flash/benchmark.jar":{"length":24351,"date":1464873509,"md5":"987f4044786771f31e0656cf91ed73f3","crc":"1eed095a"},"/flash/threadtest.jar":{"length":3601,"date":1434645124,"md5":"902ce61cbd2524ca9b83dea335c395d3","crc":"cd2479ff"},"/flash/test4to20.jar":{"length":3862,"date":1434659455,"md5":"a2e309c9d6dd112e5303aa76d2470740","crc":"976f8208"},"/flash/dirs.bat":{"length":87,"date":1435691869,"md5":"531d655733ee668d829f9b3bdad96038","crc":"6a11f77a"},"/flash/www/console/index.php":{"length":4347,"date":1438974987,"md5":"8728680bbc36d369429f7ca2c73cce7d","crc":"c939c423"},"/flash/clean.bat":{"length":56,"date":1436532855,"md5":"ac9ce6553e1629412fb426b342440493","crc":"3b661614"},"/flash/jnior1024.key":{"length":887,"date":1437746752,"md5":"b76b5351a92fdcc8d9b6b38ca62d8d71","crc":"7983e14c"},"/flash/www/config/md5.js":{"length":5693,"date":1433505379,"md5":"a60fec5a81f207ff99ec1b97e3ccad0e","crc":"e2a43d16"},"/flash/www/config/node.png":{"length":253,"date":1440435886,"md5":"1a8dbfaf1771a06e48dea0e3dc604392","crc":"799c6dfc"},"/flash/www/config/tabs-styles.css":{"length":970,"date":1477590404,"md5":"68bca7015f51e26ab42199b5eb17a356","crc":"f8870a33"},"/flash/www/config/tabs.js":{"length":3662,"date":1449678641,"md5":"ff728c86018341548ee70028062c89e0","crc":"1a813112"},"/flash/www/config/styles.css":{"length":4450,"date":1504814044,"md5":"9ad78cca1b794dbcf9db3c55f1be5f1b","crc":"acbd2e14","sha":"3cf0bbc864840994a49f62d0ae00df6d8eb47ef3"},"/flash/www/config/comm.js":{"length":3541,"date":1507912287,"md5":"e7d2e56a443176d6150bbcc8b56e1911","crc":"0ac0ed26","sha":"5e66b96227779c5ef3736a7ca891a43cacffbbf1"},"/flash/www/config/console.js":{"length":5137,"date":1504815652,"md5":"33289e4b09f462efdb50e8d30d22d791","crc":"b89fe380","sha":"c2f3ea4fc0344d43b0c30b7f60b2b6c79c1f4817"},"/flash/www/config/config.js":{"length":12639,"date":1507912576,"md5":"75bf22a88d8a23b17de267607b88a14c","crc":"d693e2f4","sha":"cf9e9bcf7cc7d79ae648b241af16ee194199d7b3"},"/flash/www/config/index.php":{"length":22103,"date":1510262716,"md5":"6fe98e5238c5834d55b0140a7172fec6","crc":"81f11698","sha":"b5b440d43bb19da0396e8ab615161be9200e6180"},"/flash/www/jnior.ico":{"length":3262,"date":1439548680,"md5":"1c3b3dda6b10c6259fcf7c068b760f09","crc":"051803eb"},"/flash/www/favicon.ico":{"length":156790,"date":1486410493,"md5":"07cb90c7f3573eff80222269625ed1dd","crc":"7e367afa","sha":"284add71fe3d3ba48fba059b88ff5143d3964b1d"},"/flash/analogpresets.jar":{"length":163902,"date":1441372806,"md5":"25eacc647412535e320302d3680ce327","crc":"e6b656fc"},"/flash/www/config/config.css.php":{"length":1045,"date":1475072901,"md5":"1692861e9abd7f8d81f5b7cf8a176046","crc":"4c386a21"},"/flash/www/config/inputs.png":{"length":18047,"date":1443116143,"md5":"e2151c93b6cdeaa154d15fab486ae61b","crc":"16290877"},"/flash/www/config/loading.gif":{"length":3236,"date":1264096270,"md5":"d96f6517e00399c37a9765e045eaaf22","crc":"16f442ed"},"/flash/jtest.jar":{"length":1832,"date":1511984925,"md5":"89f28d11945790915112f0a4880b6adc","crc":"cf00edbe","sha":"df53eab9f4eb1360c7ab48f30298ce7c48b0e440"},"/flash/www/vendor/angular_1.3.15/angular.min.js":{"length":125909,"date":1449498838,"md5":"ca1a58818682c3e858a585f283ab9beb","crc":"9d8147d7"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.css":{"length":21740,"date":1449498835,"md5":"c64043a3388612233d7eb947918a9bfc","crc":"638f58a3"},"/flash/www/vendor/bootstrap_3.3.0/css/":{"length":41933,"date":1449498838,"md5":"c5da8241305bfe7e19919e6e943739eb","crc":"11260772"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.min.css":{"length":19199,"date":1449498840,"md5":"374df0ad5809a5314b0577802430a272","crc":"8b3c47b7"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.css":{"length":137590,"date":1449498845,"md5":"ad6381ebfa541b55b0152349c6cabf76","crc":"371e67da"},"/flash/www/vendor/bootstrap_3.3.0/css/":{"length":366866,"date":1449498854,"md5":"4ba278e0c420d166e5a0eb71545f9509","crc":"b7c9868d"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.min.css":{"length":114011,"date":1449498852,"md5":"78e7f91c0c4cca415e0683626aa23925","crc":"34387388"},"/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.eot":{"length":20335,"date":1449498855,"md5":"7ad17c6085dee9a33787bac28fb23d46","crc":"f171b590"},"/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.svg":{"length":62926,"date":1449498857,"md5":"ff423a4251cf2986555523dfe315c42b","crc":"385cd4ad"},"/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.ttf":{"length":41280,"date":1449498858,"md5":"e49d52e74b7689a0727def99da31f3eb","crc":"0617f1ff"},"/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.woff":{"length":23320,"date":1449498858,"md5":"68ed1dac06bf0409c18ae7bc62889170","crc":"cec1a35c"},"/flash/www/vendor/bootstrap_3.3.0/js/bootstrap.min.js":{"length":34653,"date":1449498862,"md5":"281cd50dd9f58c5550620fc148a7bc39","crc":"32d6c689"},"/flash/www/vendor/bootstrap_3.3.0/js/bootstrap.js":{"length":65813,"date":1449498862,"md5":"d5a03d9cca57637f008124916b86b585","crc":"f504a7b3"},"/flash/www/vendor/bootstrap_3.3.0/js/npm.js":{"length":484,"date":1449498863,"md5":"ccb7f3909e30b1eb8f65a24393c6e12b","crc":"cc50e34d"},"/flash/www/vendor/jquery_1.11.1/":{"length":141680,"date":1449498870,"md5":"ffbeb16578d8cdf58104889baacbbef2","crc":"e4e92bfd"},"/flash/www/vendor/jquery_1.11.1/jquery-1.11.1.min.js":{"length":95786,"date":1449498869,"md5":"8101d596b2b8fa35fe3a634ea342d7c3","crc":"804ff984"},"/flash/www/config/integlogo.png":{"length":5773,"date":1449163436,"md5":"9111308273dadea73f5d09a5e02c7311","crc":"60c4e184"},"/flash/utility.jar":{"length":106794,"date":1449773066,"md5":"ac559b91b537dfa70720a416f32f2960","crc":"888936f1"},"/flash/generators/json/colour.js":{"length":4327,"date":1449774238,"md5":"c67e10d0e0e698fcdbbbadcaa55600d4","crc":"19e8a38f"},"/flash/generators/json/ethernet.js":{"length":1409,"date":1449774238,"md5":"1b6bae08feb93f6bd345a3780c3acb69","crc":"848097a7"},"/flash/generators/json/inputs.js":{"length":2825,"date":1449774239,"md5":"6959db5a769ff3ceea45bf606bda940a","crc":"c544d780"},"/flash/generators/json/lists.js":{"length":12006,"date":1449774239,"md5":"5cc489ac77db7a3369b2ffc30cbd3a86","crc":"ba761254"},"/flash/generators/json/logic.js":{"length":4404,"date":1449774239,"md5":"9cd1cf854976ebb69a6c20a7ac88d2f9","crc":"6c2189f9"},"/flash/generators/json/loops.js":{"length":6040,"date":1449774239,"md5":"e8e9021b5d4eb2e0cc43f11ad5b3bfd7","crc":"b30a758a"},"/flash/generators/json/math.js":{"length":14673,"date":1449774240,"md5":"fa22c29efc362e02d8f35838fcca46e5","crc":"8fc62e67"},"/flash/generators/json/other.js":{"length":983,"date":1449774240,"md5":"dd77f555bc9b50ed17a215d7935f10ab","crc":"3e07810d"},"/flash/generators/json/outputs.js":{"length":3861,"date":1449774240,"md5":"72a118cd7829b5a510e5a901d8863d6e","crc":"bdd5e320"},"/flash/generators/json/procedures.js":{"length":3945,"date":1449774240,"md5":"cb9fb880bebb3375273353fafc12dc9c","crc":"20d43aad"},"/flash/generators/json/text.js":{"length":1363,"date":1449774241,"md5":"a0bd39f638202a0800c100b4eac3cbc3","crc":"b17b24d6"},"/flash/generators/json/timing.js":{"length":2638,"date":1449774241,"md5":"b1ee803dd8e6e00de74e0a3269f0a2ff","crc":"489061b8"},"/flash/generators/json/variables.js":{"length":1500,"date":1449774241,"md5":"fecce79a400d5e4e1edbe521699fa604","crc":"cb724c91"},"/flash/generators/json.js":{"length":4115,"date":1449774238,"md5":"cc72f2468eb970110f3f6f0278f43467","crc":"25a98f30"},"/flash/www/config/link_to.png":{"length":259,"date":1450466976,"md5":"b1ed68183be4f97ce1793139496dbbb4","crc":"a067876a"},"/flash/www/config/collapsed.png":{"length":232,"date":1452087215,"md5":"ef7dd392142824ec54b7b7188717411c","crc":"c7bd8428"},"/flash/www/config/linked.png":{"length":174,"date":1452088114,"md5":"56d2755d08a0857ff6e7750c4b2822dd","crc":"ff59187e"},"/flash/www/config/expanded.png":{"length":238,"date":1452097812,"md5":"905b26e96849524dd6c37e1878f66779","crc":"68686921"},"/flash/www/config/registry.js":{"length":8276,"date":1452271284,"md5":"fc35855793b2bbfe577e420f34cb0dda","crc":"6c73e25a"},"/flash/www/config/deletex.png":{"length":240,"date":1452284181,"md5":"2750f1e60d0222d7f3c0752207fb41e7","crc":"386b823b"},"/flash/www/config/modules.js":{"length":13520,"date":1484149578,"md5":"5d79964a8ca70cc7dc0504c343be3e3c","crc":"3c09b9e2","sha":"d6f0b3ec60796662acd105694ef39543e3dc50a2"},"/flash/www/logging.php":{"length":4853,"date":1463582298,"md5":"170c17bd0962f434eebe699129491912","crc":"dce15f4e"},"/flash/www/":{"length":113815,"date":1465493787,"md5":"b3e85080154b5a7dc10078a6c6fe75c7","crc":"975c987e"},"/flash/0-10vtest.jar":{"length":5053,"date":1438104444,"md5":"3a7be82077e29c598bdd8694d47805f4","crc":"05e27897"},"/flash/4routtest.jar":{"length":2993,"date":1373644405,"md5":"14381605ec8f2f0d0dbe34843b7178b8","crc":"8240fc03"},"/flash/environ.jar":{"length":3881,"date":1476102546,"md5":"8d738f0145516d287174a00dda32dabc","crc":"ff1ecc8b"},"/flash/current.key":{"length":898,"date":1455116261,"md5":"035a0d79bd6c8258c12111479fe7353e","crc":"cbdd8ffe"},"/flash/serialtest.jar":{"length":4532,"date":1457448880,"md5":"48fc4bd9421a5cf275b42235d2f4e2cb","crc":"6d86943b"},"/flash/intellij.jar":{"length":969,"date":1464918560,"md5":"aea445862e32190fa61abc5d97e5b25f","crc":"959a1596"},"/flash/jmodule.jar":{"length":5580,"date":1465240063,"md5":"af7d42f427d0e711c4a79c8e1c1d341d","crc":"40058988"},"/flash/udptest.jar":{"length":5811,"date":1465328251,"md5":"5bbc399b4eb1f5ec427ccbf93c8b135d","crc":"3d976325"},"/flash/buffer.jar":{"length":95325,"date":1467321013,"md5":"0c66b2a130de483b64b91d87471eb952","crc":"5d0819e2"},"/flash/display.jar":{"length":2992,"date":1468953410,"md5":"efcfc78470e98842f52579c81c088a2d","crc":"5ec67fd0"},"/flash/rz.jar":{"length":13079,"date":1469638127,"md5":"c4b7e9f4072d64e3dde9fe5a62406a1e","crc":"20367148"},"/flash/www/config/folder.png":{"length":329,"date":1454662486,"md5":"316b7810fa502618b4e85788a82617a8","crc":"55f20187"},"/flash/www/config/file.png":{"length":286,"date":1454662486,"md5":"1b75c23448e9c6eed675404f6130491d","crc":"d327c449"},"/flash/www/config/warning.png":{"length":3068,"date":1332275646,"md5":"9c96d831cfc50fdedfdc980bc2abb2cf","crc":"e90bb05a"},"/flash/www/config/folders.js":{"length":19270,"date":1504815735,"md5":"c7a59ef1aea3aad95d3315627d3a3b29","crc":"6b1adf25","sha":"93d7e851c9a1a65ed45b7c1bbe4368d3d941b32f"},"/flash/clktest.jar":{"length":2616,"date":1470249535,"md5":"345b4a9a22ec05bc89bb291b7b047e0e","crc":"270f1d8b"},"/flash/timesearch.jar":{"length":4180,"date":1471371624,"md5":"bf719e65d8f4be9d7348a621ac69bc2b","crc":"25075aa7"},"/flash/janosruntime_1.5.1.jar":{"length":1621696,"date":1472744987,"md5":"b8beb71b94b36129534ef4d6ec13f5ab","crc":"abc7b327"},"/flash/www/config/relays.js":{"length":4189,"date":1484587793,"md5":"803af5c2431b8f58c110260b3f317838","crc":"ee9ab3af","sha":"21ec766fe220bd0618b43050851f9cd67dd1bf54"},"/flash/www/config/temperature.js":{"length":2870,"date":1475245816,"md5":"262c339513007cd746ee01da9a4a843f","crc":"d062a444"},"/flash/www/config/dimmer.js":{"length":8255,"date":1475265861,"md5":"e7213c6fb8c263ac71acb766e62dc4ce","crc":"b9edf051"},"/flash/www/config/range.css":{"length":2212,"date":1475499110,"md5":"6932c76ab79879ea4c5d826d9cb60db9","crc":"3334dfd1"},"/flash/www/config/analog.js":{"length":7267,"date":1484587793,"md5":"87abcaf68dea5e2e203326a55bc2bca5","crc":"9766b532","sha":"dd788111904d41826164ea151f78dd4b3e3b84e6"},"/flash/www/config/ledon.png":{"length":626,"date":1475506220,"md5":"6018d69896fcba49da54c39d8ee19803","crc":"32a65f15"},"/flash/www/config/panel.js":{"length":2038,"date":1475509052,"md5":"e0631cb06777f63f0a071f7aa5d198d0","crc":"a38a7db3"},"/flash/www/config/ledoff.png":{"length":757,"date":1475509575,"md5":"4bb71e412a20ae6f098a29b195b10e13","crc":"3fd16f7a"},"/flash/jpanel.jar":{"length":3142,"date":1358430294,"md5":"39825ccddf7b61c1ad41d261d84f4950","crc":"446bee7f"},"/flash/www/config/syslog.js":{"length":1929,"date":1496773328,"md5":"4e8ecca50284c2aeae8e8b90db27ded8","crc":"ac2a2541","sha":"e413d70cc2bb6717448bc84c2980abc764bc3dd6"},"/flash/www/config/peers.js":{"length":5885,"date":1505835290,"md5":"2536fc521f916341b98183f6ce0b2453","crc":"f2a44392","sha":"5d949b8daa8e5081f19c88e42af968b24955e02c"},"/flash/www/index.php":{"length":356,"date":1477657721,"md5":"3ba20cf61f44f9ace09104261acf2711","crc":"7f8eaed3"},"/flash/www/":{"length":85751,"date":1477663620,"md5":"296baa71d70bf40c1ad6ee0c71066c49","crc":"69922bd1"},"/flash/www/download1.php":{"length":465,"date":1480616431,"md5":"1f69c84031dbdbe9aeecd634c0ab9607","sha":"9770a8f6534f17f86eeb332309b7cbe07441022e","crc":"c7b59619"},"/flash/www/short.php":{"length":273,"date":1481120537,"md5":"2fb318c42bd07c0ec34551502bc20c73","sha":"9b9831ca6abda2a14a922e058430fe114b8b34e0","crc":"fbca8ae2"},"/flash/ctrlc.jar":{"length":1510,"date":1482421756,"md5":"b7ce2da5b761674e626ae62c4b9edbcc","sha":"51a17a3f092333a0a48aa8e6dcebe0ce99cef3de","crc":"bd2a0810"},"/flash/":{"length":87642,"date":1510262835,"md5":"b2cb6f23c2fc91d8f5d79a6e62c5ee10","sha":"a24717087011d3b87b1135ad27556c2337598d98","crc":"df0db0a9"},"/flash/www/config/favicon.ico":{"length":766,"date":1486410493,"md5":"07cb90c7f3573eff80222269625ed1dd","sha":"284add71fe3d3ba48fba059b88ff5143d3964b1d","crc":"7e367afa"},"/flash/www/map.html":{"length":1170,"date":1485380108,"md5":"901c9971c3c591b3d736cd91516960de","sha":"5ded94156ca71884af1afae0fcaf1e78d3bac23d","crc":"71f8c837"},"/flash/jmanifest.jar":{"length":5651,"date":1485192866,"md5":"dfb84226c647a42295d9f671cfb99fa5","sha":"a7331cca377c1f96e400ddd5044c01a175ee230f","crc":"1a64c6d6"},"/flash/jping.jar":{"length":2174,"date":1485201152,"md5":"0d533008847888e0dfcf497c0cff1a96","sha":"75fbff5a973b8dac3408fdda46e47e708b585e58","crc":"f1203f43"},"/flash/jaccess.jar":{"length":4820,"date":1485805203,"md5":"29ce866873686dd133a724e4db29c690","sha":"239bf75c1597a25fdbbbb78798fe72971ca15f63","crc":"e5ae0d1c"},"/flash/somepath/path2/testx.php":{"length":5282,"date":1486397961,"md5":"ce1a071b258c936c65679d6bb67db198","sha":"30342828ebaeb69cd8ecefd75f2dd01e80c6388b","crc":"ecd9251a"},"/flash/bruce_dev.cer":{"length":902,"date":1487172768,"md5":"e9917f27384ddee36817c04c8cde9199","sha":"4b2b82a042a0019679c1b071956278f6ddd1f27b","crc":"115ed2ae"},"/flash/www/config/registrydoc.css":{"length":21460,"date":1504201641,"md5":"15423ca727b03e6b1581910c6ca2eab5","sha":"f521b53a4518e7490768d2a8ae0e707c1dfb943b","crc":"0d5fd8c9"},"/flash/www/config/registrydoc.html":{"length":169108,"date":1509114127,"md5":"e30fe001dfab22c848d1d440f79c96db","sha":"a6edec26f5cbfd249e9f1b3947e92a4766d3bacb","crc":"25c25ccc"},"/flash/www/panel/comm.js":{"length":4715,"date":1498074333,"md5":"44aa80868230fbfeee0a3c48c390896d","sha":"37b479f65e7e8221d6fd9349439a8193cc645ba7","crc":"0d5e92bd"},"/flash/www/panel/index.php":{"length":2648,"date":1501526934,"md5":"923ce6739971521191f9000662f38323","sha":"a35d1d5f24da487be376595b46598e162e0f5310","crc":"ffd86d7b"},"/flash/www/panel/panel.js":{"length":993,"date":1501527049,"md5":"9d9a2cbb435ffe8af5bd9d8c0598dccd","sha":"2ef881dc8d90b4b0fb80a59d717c7125ca23fb04","crc":"4fcd0f37"},"/flash/www/panel/panel.css":{"length":2586,"date":1501527291,"md5":"2a3a66d14d7bc6d4b01dfbd745205c7d","sha":"886770297a07a594b88430d5db4ae9e23738d118","crc":"2dd8a81d"},"/flash/www/":{"length":556637,"date":1506536442,"md5":"891b1dfa8d774b85aefcbd8791abe11f","sha":"e5d204333658bd5c2f7c5b5ff682911124a10766","crc":"62d153fb"},"/flash/public/":{"length":181914,"date":1504795829,"md5":"655e8587293f35f11c5c24fc38201d2f","sha":"5fcfd8e38826e648f98f8d50f3613deb0d6312b6","crc":"da99b7d0"},"/flash/test.txt":{"length":304,"date":1495131459,"md5":"fc9f1f5e67928ccb9be3aeaa66cd9e52","sha":"6100d999f484f98ab476408c801dd000e579a62c","crc":"765047c5"},"/flash/dmx.jar":{"length":4476,"date":1500567859,"md5":"3fd35bbe6bbf53a32aecf273275d1839","sha":"4f702a87adb060294b553e6bd212672727d5d25f","crc":"e81db9aa"},"/flash/juptime.jar":{"length":3201,"date":1506713589,"md5":"d4c2482fae18482727c1b2afabcf94b4","sha":"86268b720b99760a4ebdb803db53f3f7fd18fd18","crc":"44b0878c"},"/flash/jscan.jar":{"length":2189,"date":1507141493,"md5":"a0a42e17f003cedcac9c8e662ada6b36","sha":"f1cafb56fdae33b66fff9b20cd2ff2705d96da9e","crc":"60f00fe2"},"/access.log":{"length":177,"date":1510081848,"md5":"914113dd52c4e74d2675eb1094ba10c6","sha":"0212252f4f04ab136ce74ab0425cd7fce26b7c47","crc":"e9a7f8d8"},"/auxio.log":{"length":1589,"date":1511288557,"md5":"a52713575d5c449ff8e8cdbeb7e10ba6","sha":"22106e83ff429cc08fe16f21dc32623850f5673c","crc":"a29ad191"},"/jniorio.log":{"length":3332,"date":1511289076,"md5":"d3c685fde34b343f2ba53dd60e4bf11d","sha":"dd001970b69d61ab619745853addaf2910aabb31","crc":"1bbc78de"},"/flash/hmi.jar":{"length":8329,"date":1511283865,"md5":"1a1b247ccb5e3eb9623d12578c1ba833","sha":"7a1f5868817e8a3e60fe8fb2c4d9ed168e53d141","crc":"fb2a0367"},"/flash/ckeypad.jar":{"length":11194,"date":1512145569,"md5":"71288ea4ffa40e936dbecfd010fff785","sha":"23f944b627705716697ece761c6c95f8c1f873bb","crc":"3d9fc092"}}

bruce_dev />

So beyond identification header information such as model, serial number, JANOS version and timestamp the last entry files appears to be another JSON Object, That seems to be the database content.

In manifest.json the files element is another JSON Object. So let’s load that and enumerate the keys it contains.

    public static void main(String[] args) throws Exception {
        // Obtain Json Object from a file
        Json j = new Json(new File("manifest.json"));
        Json jdb = (Json) j.get("files");
        // List top level enties
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();


bruce_dev /> jtest

bruce_dev />

So here we see that there is basically an entry for every file on the JNIOR. The files are defined by their absolute path from the root.

Let’s enumerate the content of the first file entry. I’ll just break in the loop to do one.

    public static void main(String[] args) throws Exception {
        // Obtain Json Object from a file
        Json j = new Json(new File("manifest.json"));
        Json jdb = (Json) j.get("files");
        // List top level enties
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            System.out.printf("%s = %s\n", name, jdb.get(name).toString());
bruce_dev /> jtest
/etc/janosclasses.jar = {"length":243492,"date":1512145376,"md5":"ece8d0ebf9b6882e488d1f7c9e764ce0","crc":"bde463c8","sha":"373b88f011b49f65eafd8e293fc185cc2563892e"}

bruce_dev />

So the file entry is yet another JSON Object/ It looks to contain file information.

Okay. Let’s see what it has to say about the first file.

    public static void main(String[] args) throws Exception {
        // Obtain Json Object from a file
        Json j = new Json(new File("manifest.json"));
        Json jdb = (Json) j.get("files");
        // Get first entry whatever it is and enumerate it
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            Json jfile = (Json) jdb.get(name);
            Enumeration efile = jfile.keys();
            while (efile.hasMoreElements()) {
                String name2 = (String) efile.nextElement();
                System.out.printf("   %s = %s\n", name2, jfile.get(name2));

We see the file size in bytes, some kind of encoded date, and three difference checksums or digests (MD5, CRC, and SHA). The CRC is CRC32 by teh way and SHA is SHA1.

The date is in Unix format GMT timezone.

So that pretty much is the structure of the MANIFEST database. That is a good example of using the JSON format for database storage.

By the way, the JanosClasses.jar file was just changed. The database has an earlier reference. So the date and checksum don’t match. This is how MANIFEST knows to indicate that the file has been “Modified”.

bruce_dev /> manifest etc
JNIOR Manifest      Tue Dec 05 15:26:12 EST 2017
  Size                  MD5                  File Specification
 265756   f26d0f63dd5cc055dad699f117bb4f17  [Modified] /etc/JanosClasses.jar
End of Manifest (1 files listed)

bruce_dev />

We could update our database with a MANIFEST -U command and examine it again. If we did you would see that the MD5 then matches.


Applications receive command line arguments just as any standard Java program would. You can use these to establish new default configuration settings. For example we are developing a UI for our Cinema application. The UI application (called “Cinekey” right now) when run makes a TCP/IP connection to a host running the Cinema application. By default localhost is used and the default port is 9610.

The command line syntax is:

cineky [Ip_address [port]]

You can even include these parameters in a Run key. If the optional host Ip_address is specified it will be recorded as the new default. If you specify the host you can also optionally specify the port. That will also be save as default. That means that if you do that once then you can just use the program name from that point forward to run it and it will use the last specified socket default.

Here is the code for that. You can see how it can be adapted perhaps to your configuration needs.

    public static void main(String[] args) throws Throwable {
        String host = "";
        int port;
        // obtain port
        if (args.length > 1) {
            port = Integer.parseInt(args[1]);
            JANOS.setRegistryString("Cinekey/Port", Integer.toString(port));
            port = JANOS.getRegistryInt("Cinekey/Port", 9610);
        // Obtain host
        if (args.length > 0) {
            host = args[0];
            JANOS.setRegistryString("Cinekey/Host", host);
            host = JANOS.getRegistryString("Cinekey/Host", "localhost");
        // Establish connection
        conn = new CineConnect(host, port);
        new Thread(conn).start();

Make sure that the Serial Input Buffer Size is adequate for your application. It is 128 bytes by default. If a greater number of bytes that the buffer size are sent and your application does not read them in time then the buffer can fill and data will be lost.

        // display the current buffer size
        System.out.println("auxSerialPort.getInputBufferSize(): " + auxSerialPort.getInputBufferSize());
        // set the new buffer size
        // display the new buffer size
        System.out.println("auxSerialPort.getInputBufferSize(): " + auxSerialPort.getInputBufferSize());

The output should look as follows.

auxSerialPort.getInputBufferSize(): 128
auxSerialPort.getInputBufferSize(): 256

Your application will start executing before the network is ready. Add this simple check before you perform any critical network tasks.

            if (!Network.isActive()) {
                System.out.println("Waiting for network");
                while (!Network.isActive()) {
                    try {
                    } catch (InterruptedException ex) {
            System.out.println("Network Ready");