From Serious Documentation
Jump to: navigation, search

Communications Overview

GUIs developed in SHIPTide and running in SHIPEngine need to communicate with the outside world. Typically, your GUI needs to turn things on/off, find the status of things in the outside world, and generally exchange information.

There are numerous elements in SHIP communications:

We'll discuss all these elements in detail below.

Protocols and Physical Layers

For more information, see Protocols.

You first have to decide which physical network your SIM is going to communicate through; all SIMs have at least one UART available for this purpose and many newer SIMs also support SPI. The USB device port present on some SIMs may also be used in some cases. A Protocol describes the packetization and method for moving data back and forth across that physical layer. SHIP supports three protocols, though not all protocols are supported across all available physical layers on a SIM:

The Shared Variable Concept and Data Communications Models

For more information, see Data Communications Models.

SHIP communications, in general, embody the concept of shared variables between the GUI and the remote system(s). A set of shared variables, or "linkvar" nodes, are kept in sync by the communications subsystem and made available to both the remote/attached system as well as the GUI. There are two very different models for GUI-to-system data communications:

  • the tightly coupled model, in which the back-end embedded system code is in control of, and highly aware of the front end GUI -- the back-end directs which screens are displayed and much of the look-and-feel of the front-end GUI
  • the loosely coupled or decoupled model, where the front-end GUI works independently from the back-end, presenting and manipulating data exchanged with the back-end.

The SHIP environment is most useful and effective in the decoupled model, however the tightly coupled model can be also used. However the advantages of a loosely coupled/decoupled model are so overwhelming you should think twice (no, three and four times) before choosing a tightly coupled architecture. Like all objects in SHIP, changes in any input linkvar can cause events causing any interested listener nodes to awake and run their associated script event handlers. Changing an output linkvar makes its new value available to the attached system either immediately (if marked for push) or on request (i.e. polled by the remote system).

Describing a Communications Link in SHIPTide


Communications links are described by a set of tree-structured nodes in the Resources area under link node(s).

A link node binds a Protocol to a physical layer. You can only use one protocol per physical layer. When the GUI launches and the protocol is enabled, it seizes the physical layer (i.e. UART or SPI channel) exclusively. For example, to use the Raw protocol over UART0 (in SHIPTide under the Links area) create the link:

Creating a Link

On some SIMs there is only a single UART available, for example the SIM225 has a single UART on the JST7 wire-harness connector. On 3rd generation SIMs (e.g. SIM115, SIM231, SIM535) there is one UART plus a SPI port on the wire harness, however on the FCI60 board-to-board connector there are those two ports plus an additional second UART. Each SIM's unique GUI Reference Manual describes the communications ports available.

For most systems, one port (e.g. the UART) will be used with a protocol to communicate to attached equipment.

More complex scenarios can be implemented on SIMs with more than one port. You can define more than one link and have concurrent independent data exchange with more than one attached device. For example, with a SCM117 communications module docked into a SIM231 display module the UART and SPI ports are connected between the SIM's MCU and the SCM117's RX111 MCU. Each can have a different protocol, so, for example, the UART could be bound in a Link to the Modbus Master RTU protocol and the SPI port could be bound to the SHIPBridge protocol. In this example, the Modbus protocol over UART could be exchanging data with and controlling the SCM117's RX111 MCU and the SHIPBridge protocol over SPI could be being tunneled by software on the RX111 to provide end-to-end connectivity with a remote PC to the SIM.


Some Protocols are point-to-point, such as the Raw protocol, where only the SIM and the connected target can be part of the conversation. Other Protocols, such as Modbus protocol and SHIPBridge protocol support multiple physical or virtual endpoints (i.e. a physical or virtual multi-drop network).

For example, if the GUI is configured to communicate as a Modbus Master, it is possible to have 2 or more Modbus slave devices on the network the GUI wishes to communicate with. For example, there maybe a Modbus slave sensor at Modbus slave ID 0x01 and a PLC acting in slave mode at Modbus slave ID 0x05. In this example, there is one network (i.e. link) which binds the Modbus Master protocol to the physical layer (i.e. a UART), but there are multiple endpoints (or linksets) on the network, each with its own unique network (i.e. Modbus slave) id and each with its own set of unique communications variables (i.e. linkvars:

Modbus Master Link with Two Linksets

The GUI may also operate as multiple virtual devices on the same link. For example, if you configure your a link as a Modbus Slave, you can set up multiple linkset nodes with different slave IDs. In this fashion, the SIM will act as multiple virtual devices, responding to all the specified slave IDs as if it were multiple different physical devices:

Modbus Slave Link with Two Slave Linksets

This may be useful to separate and prioritize traffic, where one linkset is polled by the master frequently and another linkset may (for example) contain configuration data that is only polled once at startup.

The SHIPBridge protocol supports the concept of virtual sessions, so each link bound to Bridge can have a number of linkset virtual endpoints within the link, although this is not common since Bridge supports more sophisticated polling priorities and optional push linkvars which normally obviates the need for separated virtual endpoints.


The SHIP Data Communications Model is centered around the concept of a common set of shared variables that are synchronized across a communications link between two endpoints (i.e. in a linkset).

Within the context of a linkset, a unique set of linkvar nodes can be created that describe the shared variables. Generally speaking, each linkvar has these properties:

linkvar Properties
Property Data Type Description
name** String The name used to identify this node in SHIPTide.
address Short Most Protocols require each variable to have a unique address/location/id number assigned
datatype** DataType linkvar's must have specific data types (e.g. Boolean); allowable types are Protocol dependent.
direction** LINKDIR Most Protocols need to understand if this is an input or output variable
value see datatype The value of the link variable.
enabled* Boolean If true (default), polling or output messages when changed are enabled.
priority Short

Only for SHIPBridge protocol

  • , a SHIPTide visible name used for referencing the linkvar in scripts
  • , a 16-bit number which uniquely identifies the variable between the two endpoints
  • which defines the type of data represented at this address
  • which says, if true, the linkvar is an output from the GUI to the attached device
  • , only valid on input linkvars, which determines the transport priority form 1 (low) to 15 (high) of the variable on the link; 0 means polled

A linkvar marked as an input (i.e. the output property false) is an input into the SHIPEngine GUI environment, and is typically used to receive commands and status from a remote device.

A linkvar marked as an output (i.e. the output property true) is an output from the SHIPEngine GUI environment to the attached device, and is typically used to control the remote device.

When the GUI is a Master in master/slave Protocols, a remote slave must be polled to get/read the value.

When the GUI is a Slave in master/slave Protocols, the remote master can write/put/set values into input linkvar values, and must poll the GUI's output linkvars in order to get/read their values.

In Protocols with push capability, both mechanisms may be available.

A listener be attached to a linkvar so that when it changes an action can be taken.

Initializing and Starting Communications

We'll use an example throughout this section to explain how to configure, initialize, and start a communications link. Our example is a GUI controlling a pump where a script in the GUI needs to turn on the pump, set its RPM, and monitor its on/off state and actual RPM.

The pump has a simple 8-bit MCU controlling the motor and monitoring pressure and RPM. It also has a UART driver with a simple Modbus ASCII Slave protocol algorithm. The MCU code has the RS232 port fixed at 9600 baud, 8 bits 1 stop bit, and a hard-coded Modbus slave id of 1.

The GUI is running on a SIM110 with a simple power supply/RS232 driver circuit attached to its 7-pin JST connector that has the SIM110 UART0 port and 5V input power connections.

Here is the complete example as configured in SHIPTide:

Sample Pump Controller Configuration

Starting the Link

Normally, your GUI will have a listener that wakes up on the shiplaunch transition that happens when the GUI first starts. The listener then invokes a script that performs three basic steps:

  1. set up and enable the UART
  2. enable the link
  3. enable the linkset(s)

In our example:

Sample Pump Controller Start Script

Our example GUI is acting as a Modbus Master attached to UART0, potentially one of many on the communications channel. This physical channel could be, for instance, a multi-drop RS485 network with many slaves our SIM could address.

Our example here is, perhaps, a hypothetical GUI controlling a pump. Our GUI (in a Sail script) could turn on the pump by setting the pumpOnRequest output Boolean linkvar to "true". Since Modbus masters poll their slaves, the next time the master polls slave #1 address 0x4000 ("pumpOnRequest", a Boolean), it will read a "true" at that shared variable location, indicating to the master (the pump) to turn on. It may also poll slave #1 address 0x2000 ("pumpRPMRequest", a 16-bit Short) to determine the requested RPM before turning the pump on. It may continue to poll these two locations to watch for a request to stop the pump or change the RPM. Also, as the pump turns on and off, and its actual RPM changes, it may send those values to slave#1 address 0x4001 ("pumpOn", a Boolean) and 0x2002 ("pumpRPM", a 16-bit Short) respectively.

Note that just because the GUI "requests" that a remote device performs some action does not mean the remote device actually does it. The GUI (in a Sail script) might request the pump turn on, but it may not happen for whatever reason (the pump is overheated, for example). Timeouts and other mechanisms can be done in the GUI to watch for these conditions.

A good practice is to have visual indicators on the GUI reflect the actual remote state, rather than the requested state. For example, an RPM reading in the GUI should reflect the value of "pumpRPM", not "pumpRPMRequest".


Changes to any output linkvar, in this example, will cause a corresponding Modbus packet to automatically be sent to the Modbus slave. The function code will be "set Boolean" or "set Short" (see Modbus for details about function codes).

For example, the script:

pumpOnRequest = true;

will cause the following Modbus Master ASCII packet to be sent:

Modbus ASCII Packet (PumpOnRequest)
Name Bytes Description
Start 1 ":" (ASCII 0x3A) start-of-packet character
Slave ID 2 "01" for slave id 0x01
Function Code 2 "05" (function code 05, Set Single Coil )
Address 4 "4000" (address of pumpOnRequest)
Data 4 "FF00" ("0000" is false, "FF00" is true)
Checksum 2 "XX" Simple 8-bit checksum
End 2 CR-LF sequence terminating packet

Note the value of an output linkvar may not immediately (or ever) equal the value set by the script. The value of output linkvars is set by the protocol getting the slave's understanding of the value. In the Modbus protocol, the FC01 (Get status of Boolean output) command will be sent (as the link is polled) and the value returned will update the linkvar. As a result, if the pump does not start because of some error condition in the pump or an error in the transmission of the message, the pumpOn linkvar will not go true.

Similarly, in our example,

pumpRPMRequest = 2200;

will send an FC06 (Set 16 bit output) packet to the slave to the address 0x2000 with the 2200 value of the RPM request. The pump would then change its RPM to 2200 if possible. Subsequent polling of the address 0x2000 (with FC03) could track the changes to the RPM.

Not all Modbus slave devices operate with outputs that reflect the current state as our prior example assumed. We set pumpOnRequest and pumpRPMRequest and expected subsequent polling of their state from the slave to reflect their actual state. Some slaves only report what these outputs were set to, not the actual value of the device. For example, the pumpOnRequest in the slave may reflect that the pump, indeed, did get the on request. But that address may not reflect the actual state of the pump. Similarly, the pumpRPMRequest may hold the desired RPM as we asked of 2200, but the actual RPM may be different.

This latter behavior is fairly common in Modbus slave devices. The solution to tracking the difference between the output request and the actual values is to add a corresponding pair of inputs that reflect the actual state of the target device. Our example has the pumpOnRequest output paired with a pumpOn input status, as well as a pumpRPMRequest paired with an input pumpRPM which indicates the actual pump RPM.

Polling and Pushing Data


A linkvar marked as an input is an input into the SHIPEngine GUI environment, and is typically used to receive commands and status from a remote device.

In a master/slave protocols link, inputs (linkvars set with direction "input") must be periodically updated from the remote end.

A slave will only have its inputs updated when the master writes/sets them. There is no way for a slave to spontaneously request an update in a master/slave topology: the master controls if/when these are updated.

A master, on the other hand, is completely responsible for determining if/when slave devices are read and written. The master is also completely responsible for if/when the various variables within the slave devices are read. A master may choose to never read some variables and/or slaves at all, or some more frequently than others.

To poll a single linkvar, SHIPEngine

A linkvar poll can be initiated by setting the linkvar's refresh property. This property is only available at run time and will not be shown in the SHIPTide property lists.

To our example project from above, we've:

  • moved the project to a SIM205 which has two UARTs (UART0 and UART1)
  • added a new link named thermoNet attached to UART1 with using the Modbus Master ASCII protocol.
  • added a new slave device via a linkset called thermoSlave at slave id 0x23
  • added a new input linkvar called temperature (address 0x6000 and data type Boolean)
Adding a new Master to UART1 with a Temp Sensor Slave

Now, for example, if we have Sail script such as this:

thermoNet.thermoSlave.temperature.refresh = true;

will will cause the following Modbus Master ASCII packet to be sent:

Modbus ASCII Packet (polling of input linkvar)
Name Bytes Description
Start 1 ":" (ASCII 0x3A) start-of-packet character
Slave ID 2 "23" for slave id 0x23
Function Code 2 "02" (function code 02, Read Input Status )
Address 4 "6000" (address of myInputLinkVar)
Count 4 "0001" (to read a single value)
Checksum 2 "XX" Simple 8-bit checksum
End 2 CR-LF sequence terminating packet

When the polling is complete and the slave has responded, the linkvar refresh property will automatically be reset to false and the value property of the linkvar will be updated (if it changed).

A listener can be attached to the linkvar refresh property with a listener condition property set to filter for a "going false" event, and that listener will awake only when the poll has completed (regardless of a change to the value or not). Another listener can be attached to the value property which will awake only when the value property of the linkvar changes.

This is demonstrated in these two listeners:

Listening to an input linkvar

The myTempPollDone listener could even run a script to start another refresh, like this:

thermoNet.thermoSlave.temperature.refresh = true;

However, this would drive a fast and continuous polling of the slave, driving continuous network activity as well as SIM processing resources. This is rarely a desirable behavior -- generally the polling is a more scheduled and periodic event driven by a timer.

Periodic Polling of a Single linkvar

Generally you will want to poll an input linkvar periodically. The timer node is designed to drive periodic events that, when paired with a listener can drive polling at a fixed rate.

Here is an example of this structure:

Timer-driven Refresh of a Single linkvar

In this example, the timer node named pollTimer contains two listeners and associated scripts.

The second listener, named startup, is only activated once when the GUI launches (shiplaunch goes true). It then runs its attached script which initializes the UART, the link, linkset, and starts the timer.

The first listener (doRefresh) is woken when either the linkvar's refresh property changes or the timer's alarm property changes. The listener's condition property filters this event so that both the alarm must go off and the refresh must be complete. This ensures that no more than one refresh per timer period happens, and that even if the timer expires the prior refresh must also be complete. In this structure, the later of the two events causes the listener's condition property to invoke the attached script. This script, when run, clears the timer alarm property, restarts the polling of the linkvar, and re-enables the timer.

Polling a Complete linkset

The linkset node also has the linkset refresh property. When this property is set to true, all linkvars within the linkset are polled. Setting this property to true causes the refresh property within every child linkvar to be set true immediately. As each, in turn, is polled the individual linkvar refresh property will go false, and when the full cycle is complete the linkset refresh property will go false.

The timer driven polling example above could be changed to set and listen for the thermoSlave's linkset refresh property instead of the individual thermometer's linkvar refresh property. Since there is only one linkvar in this linkset, there is little practical difference in this example.

Here is the example above reworked to refresh at the linkset level:

Timer-driven Refresh of a linkset

Polling a Complete link

The link node also has the link refresh property. When this property is set to true, all linksets within the link are polled. Setting this property to true causes the linkset refresh property within every child linkset to be set true immediately. As each, in turn, is polled the individual linkset refresh property will go false, and when the full cycle is complete the link refresh property will go false.

The timer driven polling example above could be changed to set and listen for the thermoNet's link refresh property instead of the individual thermoSlave's linkset refresh property. Since there is only one linkset in this link, there is little practical difference in this example.

Polling and Output Messages

For output linkvars, when the linkvar is changed, SHIPEngine automatically sends the set/write message to the slave immediately.

If any current message is currently in progress on the link

  • the specific single transaction (for example, a get/read message) will complete,
  • the output message will go out, and,
  • polling (if active) will resume.


Consistent with the philosophy of SHIP, all changes to properties can cause events. Adding a listener to any linkvar value will cause that listener to awake when that value changes.

This makes GUI display, for example, of the a remote device's status very simple and requiring little coding. The following sample listener with associated Sail script sets the containing box's background color to red when the remote temperature sensor is at-or-below 32 degrees and green otherwise.

A Simple Action from a linkvar Change