EIA-709 Network Variable Programming with JControl

Lorenz Witte


1 Introduction
1.1 EIA-709.1 (ANSI/CEA-709.1)
1.2 Network Variables
2 JControl API
2.1 Overview
2.2 Example LampControllet
2.3 Class Eia709Node
2.4 Class Eia709NetworkVariable
2.5 Class Eia709Address
2.6 Interface Eia709Controllet
3 Programming Examples
3.1 Implementing Specific Network Variable Types
3.2 Accessing Values Using Data Streams

1 Introduction

In this tutorial you will be introduced to the EIA-709 extensions for JControl. The first section will provide a brief overview of the EIA-709 standard and the functionality of network variables. Section 2 will introduce the JControl EIA-709 API by means of a sample program. The tutorial will conclude with more programming examples illustrating more advanced techniques.

1.1 EIA-709.1 (ANSI/CEA-709.1)

The communication protocol EIA-709.1 is a flexible field bus protocol. It was developed and commercialized by Echelon under the name LonTalk and later turned into an EIA standard. After some reorganization within the Electronic Industries Association, the standard has been renamed to ANSI/CEA-709.1. However, the term EIA-709.1 is still widely used as of today and often even shortened to EIA-709 when referring to the protocol. As you will notice, this is what we are going to do as well throughout this tutorial.

The EIA-709 protocol offers a lot of benefits compared to similar protocols, one of the key aspects is the sophisticated configuration options of EIA-709 networks. However, for this tutorial it is not required to know extensive details on these protocol. Instead we will focus on a more palpable innovation of the protocol: the network variables.

1.2 Network Variables

The network variables follow a very simple concept. They add what variables are in normal programming to field bus communication. It is possible to read and write network variables not only locally, but also remotely over the network. The logic behind this is that each node in the network defines a set of variables it would like to share with other devices. A network variable in EIA-709 can either be incoming or outgoing. In the first case, the node expects this variable to be changed by remote nodes. An example for this would be a lamp switch, that allows for turning the lamp on/off remotely. The second class of variables define outgoing variables. Outgoing variables are used to report something to other nodes. For instance, a weather station would use outgoing variables to provide the current temperature, air pressure or humidity for other devices.

EIA-709 allows two different methods of transferring network variables. An outgoing variable that uses the sync method will submit changes to the network immediately, giving it an event-like character, which is useful to react to button presses or similar situations. The polled method will not propagate new values automatically. Instead, such network variables must be polled by the external nodes. The fictive weather station would possibly use this mode for its network variables, so that remote stations can poll the current values whenever needed.

In the following section, we will look at the example of a simple network lamp. It will provide an incoming and an outgoing network variable. The incoming variable will be used to turn the lamp on or off, the outgoing variable serves as a status report. Accompanying we will examine the implementation of such a lamp for the JControl EIA-709 framework.

2 JControl API

In this section you will learn how to implement EIA-709 enabled applications using the JControl API. In Section 2.2 you will get an insight into the API structure, Section 2.1 will present you an example application and the following sections will discuss the different sections of the example program and introduce the different API functions in more detail.

2.1 Overview

The JControl API for EIA-709 features a comfortable network variable layer that abstracts away the protocol details. The components an application programmer is being exposed to are:

  • Nodes,

  • Controllets,

  • Network Variables, and

  • Addresses.

In order for an application to take part in network communication, it must first create one or more nodes. A node represents an autonomous communication partner in a network, for other communication partners in the network each node will appear as an individual device with its own address configuration as shown in Figure 1. Virtual EIA-709 nodes are represented by class Eia709Node (see Section 2.3).

Note

The demo version of the JControl EIA-709 implementation supports only one node.

Simulation of multiple nodes

Figure 1. Simulation of multiple nodes


Each virtual node can run one controllet. Controllets are mini applications that act in a network by communicating with other nodes and by controlling local functions. The controllets are represented by interface Eia709Controllet. A very basic controllet could implement the behaviour of a lamp. It would wait for incoming messages and turn on/off a light bulb accordingly. Additionally it could report its status to other nodes. As illustrated previously, such a communication is established through network variables, which are represented by the class Eia709NetworkVariable. Each controllet has to create all the network variables it wants to use. The lamp controllet would define an incoming network variable the allows to turn on/off the light remotely and an outgoing network variable to report status information.

Figure 2 shows the basic setup of the class LampDemo. The two discussed network variables are nvi_Switch and nvo_State.

LampControllet: Network Variables

Figure 2. LampControllet: Network Variables


By creating network variables, we have defined the interface for communication with other nodes in the network. What is still missing is the binding to such other nodes. Therefore we have to assign an address (class Eia709Address) to each outgoing network variable. Whenever the network variable should be propagated, it will send its value to the specified address.

Important

To summarize, in order to create a JControl application to work in an EIA-709 network, we have to

  1. Create and configure an Eia709Node instance,

  2. supply a controllet to the node,

  3. create network variables,

  4. and assign addresses and selectors to network variables.

Steps 3 and 4 have to be implemented inside the controllet.

2.2 Example LampControllet

In the previous section, we introduced the LampDemo, but until now we haven't written a single line of program code. We are going to make up for this now by having a look at the entire program. In the following sections we will go into the details of the various parts of the program.

1    package jcontrol.demos.eia709.lampdemo;
2    
3    import java.io.IOException;
4    import jcontrol.comm.eia709.Eia709Address;
5    import jcontrol.comm.eia709.Eia709Controllet;
6    import jcontrol.comm.eia709.Eia709NetworkVariable;
7    import jcontrol.comm.eia709.Eia709Node;
8    import jcontrol.comm.nv.NetworkVariableEvent;
9    import jcontrol.comm.nv.NetworkVariableListener;
10    import jcontrol.demos.eia709.common.Eia709NetworkVariableSwitch;
11    import jcontrol.io.Console;
12    
13    /**
14     * The TestControllet can be used to toggle the Mini-Gizmo's LEDs.
15     *
16     * @author Lorenz Witte
17     */
18    public class LampDemo implements Eia709Controllet, NetworkVariableListener {
19    
20      /**
21       * node this program runs on
22       */
23      private Eia709Node m_node;
24    
25      /**
26       * Toggling this variable causes the lamp to be turned
27       * on/off.
28       */
29      private Eia709NetworkVariableSwitch m_nviSwitch;
30    
31      /**
32       * This network variable reports the lamp state.
33       */
34      private Eia709NetworkVariableSwitch m_nvoState;
35    
36      /** Supplies static binding information. */
37      public void bind() {
38        // set nviSwitch selector
39        m_nviSwitch.setSelector( 1000);
40    
41        // set nvoState selector
42        m_nvoState.setSelector( 1001);
43    
44        // set address for nvo_State (domain broadcast, subnet: 20)
45        Eia709Address addr = Eia709Address.createAddressType0( m_node, 20);
46        m_nvoState.setAddress(addr);
47      }
48    
49      /** Creates network variables */
50      public void configure(Eia709Node node) {
51        m_node = node;
52    
53        // create nviSwitch and attach listener
54        m_nviSwitch = new Eia709NetworkVariableSwitch( m_node, "nviSwitch",
55            Eia709NetworkVariable.MOD_DIR_INCOMING);
56        m_nviSwitch.setListener( this);
57    
58        // create nvoState
59        m_nvoState = new Eia709NetworkVariableSwitch( m_node, "nvoState",
60            Eia709NetworkVariable.MOD_DIR_OUTGOING | Eia709NetworkVariable.MOD_SYNC);
61      }
62    
63      /** Returns program name (8 bytes). */
64      public byte[] getProgramName() {
65        return new byte[] { 'L', 'A', 'M', 'P', 'D', 'E', 'M', 'O'};
66      }
67    
68      /** Starts the program. */
69      public void start() {}
70    
71      /** Stops the program. */
72      public void stop() {}
73    
74      /** Is called when the switch is toggled. */
75      public void networkVariableChanged(NetworkVariableEvent event) {
76        try {
77          Console.out.println("setState to: "+m_nviSwitch.getState());
78          m_nvoState.setState( m_nviSwitch.getState(), m_nviSwitch.getIntensity());
79        } catch (IOException e) {
80          Console.out.println( "something odd happened!");
81        }
82      }
83    
84      public static void main(String[] args) {
85        // create node
86        Eia709Node node = new Eia709Node( new byte[] { 'N', 'O', 'D', 'E', 'I', 'D'});
87    
88        // set node address (domain: "JCNTRL", subnet: 20, node: 1)
89        node.setNodeAddress( new byte[] { 'J', 'C', 'N', 'T', 'R', 'L'}, 20, 1);
90    
91        // install controllet
92        node.setControllet( new LampDemo());
93    
94        // start node
95        node.start();
96      }
97    }

The LampDemo simply waits for external accesses to the nviSwitch variable. Whenever it is accessed, the lamp updates its nvo_State variable accordingly. Since the latter uses the sync propagation mode, changes will be propagated to the network immediately.

2.3 Class Eia709Node

The class Eia709Node appears in the LampDemo at several parts, most notably in the main() method. Let's have a closer look:

83      public static void main(String[] args) {
84        // create node
85        Eia709Node node = new Eia709Node( new byte[] { 'N', 'O', 'D', 'E', 'I', 'D'});
86    
87        // set node address (domain: "JCNTRL", subnet: 20, node: 1)
88        node.setNodeAddress( new byte[] { 'J', 'C', 'N', 'T', 'R', 'L'}, 20, 1);
89    
90        // install controllet
91        node.setControllet( new LampDemo());
92    
93        // start node
94        node.start();
95      }

The first thing that happens in the program is that an Eia709Node instance is created. The constructor expects the called to supply a unique node ID or neuron ID. The unique node ID must be - as the name suggests - globally unique, that means that it may not be assigned to two different nodes in the entire network. You can see that the unique node ID of this example is not very well thought-out. IDs like this should be avoided in real-world applications.

The next step is that we assign an address to the node. In this case we choose "JCNTRL" as domain name, 20 as subnet and 1 as node address. Following, the controllet is instantiated and installed. The last step is to start the node. At this point the node takes control of the application. The node instance is passed over to the Controllet via the configure(Eia709Node node) method and is used subsequently for the creation of network variables and addresses.

Table 2 shows the methods provided by Eia709Node. For in-depth information, please refer to the JControl API documentation.

Table 1. Class Eia709Node

MethodDescription
Eia709Node( byte[] neuronId);Creates a new node with the given neuron ID.
void setNodeAddress( byte[] domain, int subnet, int node )Configures the node address consisting of a domain name, a subnet and a node address.
void setControllet( Eia709Controllet program)Installs the controllet.
void start()Starts node and controllet operation.
void stop()Stops node and controllet operation.
void addGroupMembership( int groupId, int groupSize, int memberId)Adds a group membership to this node.

2.4 Class Eia709NetworkVariable

As already discussed in the previous sections, the network variables provide the main application interface. It is possible to change network variables as well as to react to network variable changes made by other parts of the program or by remote nodes.

Of course, we first have to create network variables. Network variables logically belong to the controllet, so this is where we have to create them. The interface Eia709Controllet therefore defines the method configure( Eia709Node node). Let's have a look at the implementation in the LampDemo:

50      public void configure(Eia709Node node) {
51        m_node = node;
52    
53        // create nviSwitch and attach listener
54        m_nviSwitch = new Eia709NetworkVariableSwitch( m_node, "nviSwitch",
55            Eia709NetworkVariable.MOD_DIR_INCOMING);
56        m_nviSwitch.setListener( this);
57    
58        // create nvoState
59        m_nvoState = new Eia709NetworkVariableSwitch( m_node, "nvoState",
60            Eia709NetworkVariable.MOD_DIR_OUTGOING | Eia709NetworkVariable.MOD_SYNC);
61      }

We can see that two network variables are created: nviSwitch and nvoState, each having different properties or "modifiers". The modifiers define the behaviour of a network variable. In this case, nviSwitch is declared as incoming (MOD_DIR_INCOMING), nvo_State is declared as outgoing (MOD_DIR_OUTGOING), using the sync propagation mode (MOD_SYNC). Several other modifiers exists, but for simplicity avoided in the LampDemo. Most notably, it is possible to choose the transport service used for the propagation of network variable values. For a full list of possible modifiers, please refer to the JControl API docs.

You probably have noticed, that the Eia709Node object is required. How does that relate to the proposition that network variables are logically parts of a controllet? Well, this is no contradiction. While a network variable represents a part of the function interface of a controllet, it can only operate on a node in order to transmit or receive variable updates. Without a node, a network variable cannot provide any meaningful functionality.

Likewise, a network variable must have a selector and - in case of an outgoing network variable - an address. These attributes are part of the binding information - they describe the linkage with other nodes -, therefore they are supplied in the bind() method:

37      public void bind() {
38        // set nviSwitch selector
39        m_nviSwitch.setSelector( 1000);
40    
41        // set nvoState selector
42        m_nvoState.setSelector( 1001);
43    
44        // set address for nvo_State (domain broadcast, subnet: 20)
45        Eia709Address addr = Eia709Address.createAddressType0( m_node, 20);
46        m_nvoState.setAddress(addr);
47      }

As we can see, the LampDemo assigns the selectors 1000 and 1001 to its two network variables. The address for the outgoing network variable nvoState is a type 0 (broadcast) address targeting at subnet 20.

Note

Network variables require a selector and a node assignment to operate.

In order to stay updated on changes of nviSwitch, the LampDemo installs itself as listener to this variable. Following, whenever the nviSwitch variable receives a write access, the listener will be informed via the method networkVariableChanged( NetworkVariableEvent event). In the implementation of this method, the LampDemo simply copies the value from nviSwitch to nvoState:

75      public void networkVariableChanged(NetworkVariableEvent event) {
76        try {
77          Console.out.println("setState to: "+m_nviSwitch.getState());
78          m_nvoState.setState( m_nviSwitch.getState(), m_nviSwitch.getIntensity());
79        } catch (IOException e) {
80          Console.out.println( "something odd happened!");
81        }
82      }

As we remember, the network variable nvoState was configured using the sync modifier. This means that the value will automatically propagated on the network. You will have noticed the usage of methods getState(), getIntensity() and setState(). These are not part of the standard Eia709NetworkVariable, but are additional methods provided by the Eia709NetworkVariableSwitch included in the LampDemo project. This demonstrates how specific network variable types like SNVTs or user defined types should be implemented. Please refer to Section 3.1 for a detailed look at the implementation of the Eia709NetworkVariableSwitch.

Note

The recommended way to specialize the network variable type is to extend the class Eia709NetworkVariable by methods for setting and reading special data types. The LampDemo does this by implementing the class Eia709NetworkVariableSwitch, which provides the additional methods getState(), getIntensity() and setState().

Table 2 contains an incomplete list of methods provided by the Eia709NetworkVariable. For details - as always - refer to the JControl API docs.

Table 2. Class Eia709NetworkVariable

MethodDescription
Eia709NetworkVariable( Eia709Node node, String identifier, int type, int size, int modifier)Creates a new Eia709NetworkVariable for the given node.
void setValue( byte[] value)Sets the raw value of the network variable. In case of an outgoing network variable defined with the sync modifier, the value is instantly propagated to the network.
byte[] value getValue()Returns the raw value of the network variable.
void setListener( NetworkVariableListener listener)Attaches a listener.
void setSelector( int selector)Sets the selector. This function may only be called from within the bind() method of a controllet.
void setAddress( Eia709Address address)Sets the remote address. This function may only be called from within the bind() method of a controllet.
DataOutputStream getDataOutputStream()Returns a DataOutputStream to write JAVA basic types directly to the network variable value. After modifying the value, the network variable must be updated via the propagate() method.
DataInputStream getDataInputStream()Returns a DataInputStream which allows to read JAVA basic types from the network variable value.
void poll()Polls an incoming network variable. The JControl board will issue a request to the remote station and wait for a response containing the current variable state.
void propagate()Propagates outgoing network variables. This method has to be called after modifying the variable value with the DataOutputStream method.

2.5 Class Eia709Address

The class Eia709Address represents an address of a remote node. Addresses must be assigned to outgoing network variables in order to propagate its value to the network. Three different type of addresses are supported in the network variable API, as show in Table 3.

Table 3. EIA-709 Address Types

TypeDescription
0 (Broadcast)Messages are propagated to all nodes of a specified subnet or even the entire domain (subnet 0).
1 (Multicast)Messages are propagated to all members of a group.
2a (Singlecast)Messages are propagated to a single node represented by a subnet and a node address.

The API provides three different static methods for the creation of the different address types, listed in Table 2.

Note

The rule that a network variable cannot exist without a node applies here as well. An address only makes sense in the context of a node.

Table 4. Class Eia709Address

MethodDescription
static Eia709Address createAddressType0( Eia709Node node, int dstSubnet)Creates a type 0 address.
static Eia709Address createAddressType1( Eia709Node node, int dstGroup)Creates a type 1 address.
static Eia709Address createAddressType2a( Eia709Node node, int dstSubnet, int dstNode)Creates a type 2a address.

As we can see, the LampDemo creates a type 0 target address for the variable nvoState with a subnet of 20:

45        Eia709Address addr = Eia709Address.createAddressType0( m_node, 20);

2.6 Interface Eia709Controllet

The interface Eia709Controllet defines the methods and EIA-709 application must support. We have already been exposed to the methods bind() and configure() in the previous sections. We remember that configure() was used to create the network variables the program requires and bind() to supply the so-called binding information: target addresses and selectors.

To understand this separation better, we have to realize the different nature of these two actions. By creating network variables, we are defining a remote interface for the application and thus are a crucial part of it. We know what types of network variables we need, and we assign prominent names to them. Once the network variables are created, they provide an abstraction layer for the main program, which remains free from specific addresses or selectors.

However, as we've learnt before, network variables cannot be used without addresses and selectors. The method bind() is included to fill this gap. By assigning the missing selectors and addresses it exposes the otherwise lifeless network variables to the network.

Caution

While it is technically possible to declare and/or configure network variables in other parts of the program, this would break the programming concept and is highly discouraged.

Apart from these two methods, the interface defines a few other methods to control the behaviour.

Table 5. Interface Eia709Controllet

MethodDescription
byte[] getProgramName()Must return the program name consisting of 8 bytes.
void configure( Eia709Node node)Must create the required network variables.
void bind()Must provide the binding information consisting of network variable selectors and addresses.
void start()Is called when starting a node. A controllet may start addition threads for control functions here.
void stop()Is called when stopping a node. A controllet should stop or pause all of its threads.

3 Programming Examples

In this section we will have a closer look on the implementation of controllets, specific network variable types, and on the usage of DataInputStream and DataOutputStream for accessing variable values.

3.1 Implementing Specific Network Variable Types

The LampDemo from Section 2 used a special network variable class. Eia709NetworkVariableSwitch provides an implementation of the network variable type SNVT_switch. The following listing shows a simplified version of this class:

    package jcontrol.demos.eia709.common;
    
    import java.io.IOException;
    import jcontrol.comm.eia709.Eia709NetworkVariable;
    import jcontrol.comm.eia709.Eia709Node;
    
    public class Eia709NetworkVariableSwitch extends Eia709NetworkVariable {
    
      /** Minimum intensity: 0% */
      public static final float MIN_INTENSITY    = 0f;
    
      /** Maximum intensity: 100% */
      public static final float MAX_INTENSITY    = 100f;
    
      /** Switch state "off" */
      public static final int STATE_OFF          = 0;
    
      /** Switch state "on" */
      public static final int STATE_ON           = 1;
    
      /** Switch state "invalid" */
      public static final int STATE_INVALID      = -1;
    
      /** Network variable value size in bytes.*/
      public static final int SIZE               = 2;
    
      /**
       * Creates a new SNVT_switch network variable.
       *
       * @param node node the network variable should be registered to
       * @param identifier identifier
       * @param modifier modifier
       */
      public Eia709NetworkVariableSwitch(Eia709Node node, String identifier, int modifier) {
        super(node, identifier, Eia709NetworkVariable.TYPE_SNVT_SWITCH, SIZE, modifier);
      }
    
      /**
       * Creates a new SNVT_switch network variable.
       *
       * @param node node the network variable should be registered to
       * @param identifier identifier
       * @param modifier modifier
       * @param selfDescription self description
       */
      public Eia709NetworkVariableSwitch(Eia709Node node, String identifier, int modifier, String selfDescription) {
        super(node, identifier, Eia709NetworkVariable.TYPE_SNVT_SWITCH, SIZE, modifier, selfDescription);
      }
    
      /**
       * Returns the current intensity.
       *
       * @return intensity in percent
       */
      public float getIntensity() {
        byte[] value = getValue();
        return (float)((int)value[INTENSITY_OFFSET] & 0xff) / 2;
      }
    
      /**
       * Returns the current state.
       *
       * @return STATE_ON, STATE_OFF, STATE_INVALID
       */
      public int getState() {
        byte[] value = getValue();
        switch (value[1]) {
        case STATE_OFF:
          return STATE_OFF;
        case STATE_ON:
          return STATE_ON;
        default:
          return STATE_INVALID;
        }
      }
    
      /**
       * Sets the state without changing the intensity.
       *
       * @param state new state (STATE_ON or STATE_OFF)
       *
       * @throws IOException in case of transfer errors
       */
      public void setState( int state) throws IOException {
        byte[] value = getValue();
        value[1] = (byte)state;
        setValue( value);
      }
    
      /**
       * Sets state and intensity.
       *
       * @param state new state (STATE_ON or STATE_OFF)
       * @param intensity new intensity in percent
       *
       * @throws IOException in case of transfer errors
       */
      public void setState( int state, float intensity) throws IOException {
        byte[] value = new byte[2];
        value[1] = (byte)state;
        value[0] = (byte)(int)(intensity*2);
        setValue( value);
      }
    }

A look on the constructor reveals that the Eia709NetworkVariableSwitch is nothing but a plain network variable with a 2-byte value. To understand the implementation of the setters and getters, we have to know the structure behind this two byte value. The SNVT specification defines the value as follows:

Table 6. SNVT_switch: Structure

OffsetTypeDescription
0byteContains an intensity value between 0 and 200. This is meant to be used for light dimming and similar applications. The value reflects a percentage in 0.5% steps.
1byteContains the state. A value of 0 means "off", a value of 1 means "on". Other values are undefined.

With this knowledge we can implement the specific getters and setters. The getters are trivial, while the getters require more thought, since the setting of a network variable consists of two steps: Firstly, the value has to be changed in the local copy of the network variable, secondly, the new value has to be propagated. The means if we would use two separate setters for state and intensity, two subsequent calls to these functions would propagate the network variable twice. To avoid this, we simply provide an additional function allowing simultaneous changes of state and intensity.

For more transparency, we choose that the intensity is provided as float containing a percentage by the application instead of an integer range from 0 to 200.

3.2 Accessing Values Using Data Streams

So far we have seen in the Eia709NetworkVariableSwitch that we can modify the value of a network variable by calling the setValue() method. We can perform a read-modify-write cycle by combining setValue() with getValue(). However, this can turn quite tedious when it comes to more complex structures than the ones we've seen so far.

Let's assume we create our own network variable type. It should contain a float value, an int, and a string of 8 bytes, all of which can be modified individually. Of course we can still use the get/set approach, but this would mean we have to convert the values manually and split them up into separate bytes and then deserialize them again, when we want to read the values. Using the data streams makes this a very simple job.

Let's have a look at the setValues() of our imaginary network variable:

    public class MyEia709NetworkVariable extends Eia709NetworkVariable {
    
      // --- snip ---
     
      public void setValues( float f, int i, String s) throws IOException {
        byte[] bytes = s.getBytes();
        if ( bytes.length < 8) throw new IllegalArgumentException( "string must consist of 8 bytes");
        DataOutputStream out = this.getDataOutputStream();
        out.writeFloat( f);
        out.writeInt( i);
        out.write( bytes, 0, 8);
        this.propagate();
      }
     
      // --- snip ---
    }

First the code turns the string into a byte array and checks its length, then it creates a DataOutputStream for its own value by calling the method getDataOutputStream(). After writing out the values, the network variable has not generated a message on the network. This only happens after calling the propagate() method.

Reading a network variable is equally simple. Exemplary we'll have a look at method getFloat():

      public float getFloat() {
        float f = 0.0;
        try {
          DataInputStream in = this.getDataInputStream();
          f = in.readFloat();
        } catch (IOException e) {
        }
        return f;
      }