Implementation Specification for BeckhoffCom Device¶
Authors: | A. Beckmann and A. Parenti, for the Control and Data Analysis Software Group |
---|---|
Version: | 3.1, October 2016 |
Revisions¶
Version | Date | Description |
---|---|---|
1.0 | 30 Nov 2015 | Initial version |
1.1 | 15 Feb 2016 | Update regarding generic devices |
1.2 | 18 Apr 2016 | Updated FSM and message rate calculation |
2.0 | 9 May 2016 | Change to synchronous services |
3.0 | 25 Jul 2016 | Changed FSM state names, added some more sections |
3.1 | 7 Oct 2016 | Migrated to Karabo consolidated version |
3.3 | 4 Apr 2018 | Asynchronous implementation of PLC interactions |
Preface¶
This document provides details on the implementation of the BeckhoffCom Karabo device, which is the gateway between Karabo and Beckhoff PLC.
This specification covers software release 3.1.
Introduction¶
The photon beamlines and experiments use hardware devices, such as motors, valves, pumps, which are connected via field bus to a Programmable Logic Controller (PLC). The Human-Machine Interface (HMI) is a set of Karabo devices, which allow users to individually control the hardware devices.
The BeckhoffCom device acts as a transparent gateway between Karabo devices and PLC hardware. The main tasks are:
- accept read requests for PLC properties from Karabo devices
- accept write requests for PLC properties from Karabo devices
- accept call requests for PLC commands from Karabo devices
- forward PLC property updates to Karabo devices
The Karabo devices and BeckhoffCom run on Linux platforms, whereas the PLC runs on Windows platforms. To cross the different platforms, BeckhoffCom communicates via local area network (LAN) to a TCP server on the PLC host. The protocol for the TCP connection is a proprietary protocol described in more detail in [1].
System Context¶
The BeckhoffCom device is operated in the context as shown in Fig. 1. It has an interface to the Karabo framework for user control as well as to the PLC for hardware control.
![_images/system_context.png](_images/system_context.png)
Fig. 1 System context.
Information Model¶
The information on the PLC is modelled as nodes of different classes. Node classes can be one of softdevices, properties or commands. Softdevices are modules that combine properties and commands for a specific type of hardware, such as a motor. Properties represent a value of different types that users can read or write, and commands represent an action that can be executed by users.
Each node has a unique node ID. The node ID is used to address information on the PLC. Two node IDs are required for each access: the device ID to address the softdevice, and the key ID to address the property or command within the softdevice.
On HMI level softdevices, properties and commands are specified as strings, such as property ‘AValue’ on softdevice ‘analogIn1’ to read out the actual value of an analog input. The mapping between strings and node IDs is handled inside BeckhoffCom.
Status Codes¶
The status codes describes the result from processing the request for a node. They are described in Table 1. Some codes are deduced from error codes, as provided from the PLC. In that case the PLC error code is also mentioned.
Status | PLC Error | Description |
---|---|---|
0 | request has been processed successfully | |
1 | PLC is not connected | |
2 | request timed out | |
3 | missing value | |
4 | property is not readable | |
5 | property is not writable | |
6 | access to property is denied | |
6001 | 6001 | serial initialization failed |
36865 | 0x9001 | unknown property name |
36866 | 0x9002 | unknown device name |
36867 | 0x9003 | multiple devices with same name found |
36868 | 0x9004 | COE initialization failed |
36869 | 0x9005 | inconsistent interlock condition |
36870 | 0x9006 | device did not respond (timeout inside PLC) |
36871 | 0x9007 | unexpected device |
65535 | unknown error |
Architecture¶
BeckhoffCom is a C++ Karabo device. The architecture on top level is depicted in Fig. 2. The top level BeckhoffCom class is a rather thin layer that passes all method calls down to a core, which implements the actual application logic. The event driven nature of the device requires to also provide methods inside BeckhoffCom that can be called by the core to interact with the Karabo framework. These methods are defined as an interface IFramework, thus improving testability of the core by allowing to mock this interface in unit tests.
![_images/top_level_architecture.png](_images/top_level_architecture.png)
Fig. 2 Top level architecture.
The core provides methods to interact with the PLC, such as connecting to the TCP server, or to exchange data with the PLC. The framework interface provides methods, such as sending value updates from the PLC to the associated Karabo device.
Core¶
The design of the BeckhoffCom core is based on the Model-View-Presenter (MVP) pattern, as described in [2]. Fig. 3 shows the architecture of the core. The model implements the application logic, the view manages the communication with the PLC, and the presenter implements the behavior according to the functional requirements. Communication between these blocks is abstracted into interfaces, which define events and methods.
![_images/core_architecture.png](_images/core_architecture.png)
Fig. 3 Core architecture.
The view interface is defined in a generic way based on ideas from OPC UA [3] to enable a possible change of the view to OPC UA in the future. The current implementation however uses a proprietary TCP protocol, therefore the view is further divided into a view adapter, a view model, and the TCP view. The view adapter converts from the generic view interface into the concrete TCP view interface using a view model for data conversion, and the TCP view finally talks to the TCP server of the PLC.
State machine¶
The state machine of the BeckhoffCom device is depicted in Fig. 4. The FSM starts in the INIT state, and changes into the ON state, once the connection to the TCP server has been established. In the ON state, BeckhoffCom accepts requests from Karabo devices to interact with the PLC and also sends PLC value updates to the associated Karabo devices. This state is never exited except in case of errors.
![_images/state_machine_com.png](_images/state_machine_com.png)
Fig. 4 State machine of BeckhoffCom device.
BeckhoffCom¶
The BeckhoffCom class is the top level class. It is a thin layer on top of the core logic.
Construction and Destruction¶
When BeckhoffCom is constructed, the core classes are created and all slots and signals are registered. In addition, if configured, the Model is instructed to instantiate generic Beckhoff devices.
When BeckhoffCom is destroyed, the model is called to disconnect from all Beckhoff devices, and all threads are stopped. Then all objects created in the constructor are destroyed.
FSM Methods¶
Behavior is implemented in FSM entry and exit methods, which are explained in more detail in this section. If methods are time consuming, i.e. they communicate with the hardware, they are implemented as background worker in order to allow the FSM to finish the transition.
INIT State Entry¶
When entering the INIT state, the model is called to connect to the specified TCP server. If errors occurred during the connection attempt, then the errorFound event is triggered and the FSM transits into the UNKNOWN state.
ON State Entry¶
When entering the ON state, the list of soft devices is requested from the model and the associated expected parameter is updated. Then, the monitoring thread is started to calculate message rates.
ON State Exit¶
The monitoring thread is stopped, and the list of soft devices is cleared.
UNKNOWN State Entry¶
When entering the UNKNOWN state, the model is called to disconnect from the TCP server. Then, the autoreset thread is started to automatically try to reconnect after a configured time.
UNKNOWN State Exit¶
When exiting the UNKNOWN state, any suspended autoreset thread is terminated.
Threads¶
BeckhoffCom starts threads to automatically reset a connection in case of errors, and to calculate message rates.
Autoreset¶
The autoreset thread is started, when entering the UNKNOWN state. It simply waits for the configured autoreset time and then triggers the reset event. This will trigger the FSM to transit into the INIT state.
If the autoreset time is set to 0, then this thread terminates immediately, and no reset event is triggered.
Monitoring¶
The monitoring thread resets the message counters in the model, waits for one second, and then asks the model for the count of incoming and outgoing messages since the last reset. Finally, it calculates the rate per second and sets the associated exp. parameters.
Note
The byte count is not considered, since this information is not available within the model.
Slots¶
BeckhoffCom defines slots to provide the following services:
- read service to read values of a PLC property
- write service to write values to a PLC property
- call service to execute commands on the PLC
- browse service to return device and property names
- push service to start a scheduled push of a specific PLC property
- unpush service to stop a scheduled push of a specific PLC property
Services are implemented as synchronous request and reply messages, so that replies are delivered without being queued on the requester.
A service request contains a request ID, the name of the device, a hash with the properties or commands as keys, and in case of the write service also the write values.
The reply contains the associated request ID, a copy of the hash from the request together with a status code, and in case of the read service also the read values. The status code is attached as an attribute named ‘status’ to each key.
For all services, a timeout is used to unblock the request, if no response has been received from the PLC within a certain amount of time. In that case, the reply is returned with status code 2, according to Table 1.The default timeout is 1.0 s.
Framework Interface¶
The BeckhoffCom class implements the framework interface, allowing the model to exchange data with the Karabo framework. The methods are listed in Table 2.
Method | Description |
---|---|
connectionEstablished() | notifies the framework that a server connection has been established |
connectionError(message) | notifies the framework that a connection error occurred |
hello(device) | registers with the named Karabo device |
bye(device) | deregisters with the named Karabo device |
update(device, values) | sends PLC value updates to the named Karabo device |
heartbeat(uptime) | notifies the framework that a heartbeat was received with the specified PLC uptime |
connectionEstablished()¶
The connectionEstablished() method is called by the model, when the TCP connection was established and the complete self description was received. It simply triggers the connected event, so that the FSM transits into the ON state.
connectionError()¶
The connectionError() method is called by the model, when an error occurred while listening on the TCP connection. It simply triggers the errorFound event, so that the FSM transits into the UNKNOWN state.
hello()¶
The hello() method is called by the model for all devices from the self description, after the TCP connection was established and the complete self description was received. It registers the BeckhoffCom instance with a Beckhoff device by calling its ‘registerComDevice’ slot.
bye()¶
The bye() method is called by the model, when a disconnect was requested (usually only in case of errors, see also Section UNKNOWN State Entry). It deregisters the BeckhoffCom instance from a Beckhoff device by calling its ‘deregisterComDevice’ slot.
update()¶
The update() method is called by the model, when value updates have been received from the PLC, which were not requested. It forwards the updated values to the specified Beckhoff device by calling its ‘plcUpdate’ slot.
Updated values always have status code 0.
heartbeat()¶
The heartbeat() method is called by the model, when the heartbeat message was received from the PLC. It extracts the PLC uptime and sets the associated exp. parameter.
Model¶
The model provides methods to connect and disconnect to the server, and to handle services called from BeckhoffDevice. When a connection is set up, the model registers itself with Beckhoff devices, and when a connection is shut down, the model deregisters itself from Beckhoff devices. Value updates from the PLC are passed through by the model to associated Beckhoff devices. Finally, it runs a watchdog to monitor the TCP connection.
The model is connected to the presenter via the model interface. It defines methods that the presenter can call to either subscribe to model events, or to pass data to the model for further processing.
Server Connection¶
The methods to handle the server connection are listed in Table 3.
Method | Description |
---|---|
connect(server, timeout) | connects to the specified server and defines a time out for services |
disconnect() | disconnects from the server |
The server is specified using the generic URI syntax
scheme:hierarchical_part
. The only supported scheme is tcp, which is
also the default value, if no scheme is specified. The hierarchical
part contains a host name or address and a port in the form
host:port
. If no port is specified, 1234 is used.
A timeout in seconds can be specified, which is applied to all services to detect timeouts.
Establishment of the connection is performed asynchronously, so that the connect() methods returns immediately. If the connection has been established, the associated method from the framework interface is called to trigger a ‘connected’ event in the FSM.
Service Methods¶
The service methods that can be called by BeckhoffCom are listed in Table 4.
Method | Description |
---|---|
read(device, values) | read values from a property of the specified PLC softdevice |
write(device, values) | write values to a property of the specified PLC softdevice |
call(device, commands) | execute PLC commands on the specified PLC softdevice |
Schema browse(root) | browses the hierarchical information model starting at the specified root and returns the Schema (e.g. list of devices or list of properties for a device) |
setPush( device, property, interval triggerId | creates a scheduled push for the named property on a device with the specified period to the internal triggerId |
If arguments are passed in by reference as Karabo hashes, they are converted into internal data structures that are then passed to the presenter for further processing. All service methods result in the raise of an event, which is handled by the presenter to forward the event to the view. Data is attached as event arguments.
The read, write, call and setPush methods will subscribe a callback function to be invoked asynchronously at reply time.
read()¶
The read() method converts the names from the values Hash into IDs using the internally stored information from the self description. If device or property names are unknown, the status is set accordingly. Otherwise, the IDs are added to the read event argument.
write()¶
The write() method converts the names and write values from the values Hash into IDs using the internally stored information from the self description. If device or property names are unknown, the status is set accordingly. Otherwise, the IDs and write values are added to the write event argument.
call()¶
The call() method converts the command names from the commands Hash into IDs using the internally stored information from the self description. If device or property names are unknown, the status is set accordingly. Otherwise, the IDs are added to the call event argument.
setPush()¶
The setPush() method converts one device name, one property name, interval and trigger Id using the information stored in the self description. If device or property names are unknown, the status is set accordingly; in the the correct case, the IDs are added to the setPush event argument.
browse()¶
The browse() method stores the specified root as the starting node into the browse event argument.
After triggering the browse event, the returned references are parsed to create a schema based on the reference type and data type. References can be of type Object, Variable, or Method. Objects are for example instances of a soft device, Variables are for example the properties of a soft device, and Methods are the commands that can be executed on a soft device. It is expected, that the browse service is only called for devices (i.e. starting node is a soft device instance), so that only references of types Variable and Method are returned.
Model Interface¶
The Model interface IModel defines a set of methods that can be called from the presenter.
Subscriptions¶
A set of subscription methods allow the presenter to subscribe for the various events from the Model. The events are:
- connect event
- disconnect event
- read event
- write event
- call event
- browse event
- setPush event
connectionEstablished()¶
The connectionEstablished() method is called by the presenter, if the view raised the connected event, which means that a TCP connection was established. The Model then uses the browse event using the root ID as starting node, which returns a list of all device instances. This request blocks until the complete self description was received from the PLC.
Then, the Model checks, whether a Karabo device with the same name is already existent, and if not optionally instantiates the BeckhoffGeneric device.
Finally, the connectionEstablished() method from the framework interface is called (see Section connectionEstablished()), and the threads described in Section Threads are started. deleteMonitoredItem event
connectionError()¶
The connectionError() method is called, when a TCP connection error was indicated by the view. It first instructs the threads to be stopped and then calls the connectionError() method from the framework interface (see Section connectionError()).
setUpdateValues()¶
The setUpdateValues() method is called to forward PLC value updates from the PLC to the Model.
If the value update is a heartbeat, then the PLC uptime is extracted from the value and the heartbeat() method from the framework interface is called with the PLC uptime (see Section heartbeat()).
In all other cases, the updates are sorted by device name, and for each found device name, the update() method from the framework interface is called with the device name and a Hash containing the value updates for that device.
Threads¶
When a connection has been established, the Model starts threads to monitor the TCP connection and to regularly register with Beckhoff devices.
Watchdog¶
The watchdog thread monitors the TCP connection. It has a counter, which is decremented from its initial value 60 each 500 ms. The counter is reset to 60, when an update has been received from the TCP server, e.g. the heartbeat.
If no message is received, then the watchdog thread triggers a connection error via framework interface after 30 s.
The watchdog thread is terminated, when the Model is destroyed, or if a connection error occurred.
Registration¶
The registration thread registers BeckhoffCom with all Beckhoff devices each 5 s, so that if Beckhoff devices have been restarted after the last registration, they will get a new one after at least 5s.
The registration thread is terminated, when the Model is destroyed, or if a connection error occurred.
Message Count¶
Inbound (received from PLC) and outbound (sent to PLC) messages are counted. Since the byte size of messages is not available at this level, it is not possible to create a count based on bytes sent over the network. BeckhoffCom can reset the counters using the resetMessageCounts() method, and get the counts using either getInboundMessageCount() or getOutboundMessageCount().
TcpAdapter¶
The TcpAdapter class implements the view interface. With the help of the TcpModel class, it converts between higher level data structures, as passed with events from the model, into TCP messages and vice versa. It then calls methods from the TcpView to actually interact with the TCP server running on the PLC. The TcpView can itself generate events, e.g. for incoming data, which are then processed by the TcpAdapter, ususally by forwarding the event to the presenter after converting the TCP message into higher layer data structures.
View Interface¶
The View interface IView defines a set of methods that can be called from the presenter.
Subscriptions¶
A set of subscription methods allow the presenter to subscribe for the various events from the TcpAdapter. The events are:
- connected event
- error event
- update event
connect()¶
The connect() method stores the specified timeout locally, extracts the host and port from the server URI, and calls the connect() method of the TcpView.
The connection is started asynchronously, so that the connect() method of the TcpView returns immediately.
disconnect()¶
The disconnect() method calls the disconnect() methods from the TcpView, which shuts down the TCP connection. It also clears all information from a previously received self description.
browse()¶
The browse() method blocks until the complete self description has been received. The self description is assumed to be complete, if the EndOfSelfDescription message has been received (see [1] for details).
It then creates the browse result by adding references as found in the self description.
read()¶
The read() method saves all requests into a list of open requests, so that any responses can be associated correctly. The request is then converted into a TCP message using the TcpModel and sent by calling the send() method of the TcpView.
Afterwards, it runs a loop to wait until there are no more open requests and returns the read values. If there are open requests after the timeout specified with the connect() method, then the loop is terminated and the status code of the open read requests is set accordingly.
write()¶
The write() method saves all requests into a list of open requests, so that any responses can be associated correctly. The request is then converted into a TCP message using the TcpModel and sent by calling the send() method of the TcpView.
Afterwards, it runs a loop to wait until there are no more open requests and returns the status codes of each request. If there are open requests after the timeout specified with the connect() method, then the loop is terminated and the status code of the open write requests is set accordingly.
call()¶
The call() method saves all requests into a list of open requests, so that any responses can be associated correctly. The request is then converted into a TCP message using the TcpModel and sent by calling the send() method of the TcpView.
Afterwards, it runs a loop to wait until there are no more open requests and returns the status codes of each request. If there are open requests after the timeout specified with the connect() method, then the loop is terminated and the status code of the open call requests is set accordingly.
createSubscription()¶
The createSubscription() method generates a unique subscription ID and creates an instance of the Subscription class. The pointer is stored into a map with the subscription ID as a key.
deleteSubscription()¶
The deleteSubscription() method destroys the Subscription instance and removes it from the map.
createMonitoredItems()¶
The createMonitoredItem() method first searches for the associated subscription. It then gets the trigger number based on the device and property ID. The trigger number is maintained in a separate map of Trigger class instances with the device name used as a key. The Trigger class makes sure, that only valid trigger numbers between 1 and 10 are generated. The property is then stored as monitored item with the subscription, and finally, a write request for the ‘ATrigger’ property is generated, to configure the trigger on the PLC.
deleteMonitoredItems()¶
The deleteMonitoredItem() method essentially works the same as createMonitoredItem(), but instead generates a write request for the ‘ATrigger’ property to clear the trigger on the PLC (key ID equals 0). It also removes the monitored item from the associated subscription.
Abbreviations and acronyms¶
Core | Main logic part of the BeckhoffCom device |
MVP | Model-View-Presenter design pattern |
OPC UA | Open Platform Communications Unified Architecture, a standard software interface for data exchange in automation |
References¶
[1] | (1, 2)
|
[2] |
|
[3] |
|