Implementation Specification for TimeServer Device¶
Authors: | A. Beckmann and A. Parenti, for the Control and Data Analysis Software Group |
---|---|
Version: | 2.0a, July 2016 |
Revisions¶
Version | Date | Description |
---|---|---|
1.0 | 20 Apr 2015 | Initial version |
1.0a | 04 Jul 2016 | Fixed broken cross reference, added section on Karabo interface, added appendix for Karabo device integration and TCP protocol |
2.0 | 20 Jul 2016 | Fixed FSM state names |
2.0a | 25 Jul 2016 | Refined class descriptions |
Preface¶
This document provides details on the implementation of the Karabo device for providing trigger ID and time stamp information to other devices.
This specification covers software release 2.0.
Introduction¶
The TimeServer device provides trigger ID and time stamp for other Karabo devices, which are not capable of retrieving this information directly from hardware. The information is sent out for each trigger via message broker.
The trigger ID is either read out from the XFEL timing system, generated internally, or received as a simple message over TCP from another server.
Architecture¶
The TimeServer device is divided into several classes to improve testability, as explained in the following section. Behavior is controlled by a finite state machine (FSM), which provides a set of methods to implement the desired logic.
Class Diagram¶
Fig. 3 shows the top level class diagram of the TimeServer device. The main class is karabo::TimeServer, which is derived from karabo::core::Device with the FSM template parameter bound to the karabo::core::BaseFsm state machine class. It has an association with class xfel::timer::Timer, which implements the core logic [*].
State Machine¶
The state machine of the TimeServer device is depicted in Fig. 4.
The initial state is the INIT state, in which the TimeServer device either starts a thread to generate internal time ticks, or connects to XFEL timing system, or connects to a remote TCP server. Afterwards, the FSM changes into the ON state, if there was no error during initialization.
In case of errors during initialization or at run time in ON state, the errorFound event is triggered and the FSM changes into the UNKNOWN state. Triggering the reset event changes the FSM back into INIT state.
TimeServer Class¶
The class karabo::TimeServer is a thin layer on top of the xfel::timer::Timer class. It defines the methods that are called from the Karabo framework, while it executes the FSM. These methods call methods from the Timer class for further processing, and optionally convert data between the karabo::util::Hash representation, which is used inside Karabo framework, and basic data types, which are used inside xfel::timer::Timer.
The TimeServer class also implements the ITimer interface, which is used by xfel::timer::Timer to provide the time ticks.
Construction and Destruction¶
When the TimeServer device is created, it registers all slots and signals, and sets up the internal logging.
FSM Methods¶
For time consuming tasks, the FSM entry exit and action methods usually start worker threads to do the job in the background. This enables the FSM to finish state transitions, so that the state is displayed correctly within the GUI.
INIT State Entry¶
When entering the INIT state, the time source and period is set, and the TimerServer class sets itself as the class implementing the ITimer interface. Finally, it initializes the Timer. Then the on event is triggered, so that the FSM transits into the ON state.
In case of errors, the errorFound event is triggered to transit the FSM into the UNKNOWN state.
UNKNOWN State Entry¶
When entering the UNKNOWN state, the Timer is shut down.
Signals¶
The TimeServer device provides information by emitting the following signal
- signalTimeTick
It is described in the following section in more detail
signalTimeTick¶
The signal signalTimeTick is emitted each time, the trigger ID changes. It provides the following values:
- trigger ID,
- timestamp in seconds
- timestamp fraction in attoseconds
- average period in microseconds
All values are 64 bit integers. The timestamp is the time of the change of trigger ID in seconds since epoch (1.1.1970). The fractional part is provided in attoseconds, the effective resolution is however depending on the selected ID source, as described in Section xfel::timer::ITimer interface. The average period is the time difference between consecutive ID changes, averaged over the last 100 changes.
Expected Parameters¶
The TimeServer device has a set of expected parameters, which are explained in more detail in the following sections.
source¶
The expected parameter with key ‘source’ defines the source for the trigger ID and timestamp. It is specified as a string in URI syntax, as explained in Section Initialization. This parameter can only be set before initialization.
id¶
The expected parameter with key ‘id’ is set with each change of the trigger ID, so that it always contains the latest valid ID. This parameter is read only.
periodActual¶
The expected parameter with key ‘periodActual’ contains the actual average period. The period is calculated as the difference of timestamps of two consecutive ID changes, and is displayed in milliseconds. The period is averaged over the last 100 ID changes. This parameter is read only.
periodSet¶
The expected parameter with key ‘periodSet’ defines the setpoint for the period of the internal timing information generation. It is a floating point number in milliseconds. A change of this value has immediate effect. However, due to some filtering of the average (simple P type control loop), it takes some time to get to the new period.
Timer Class¶
The class xfel::timer::Timer is the top level class of the core logic, which is explained in more detail int the following section. Main purpose of the Timer class is to send time ticks over the xfel::timer::ITimer interface.
Class Diagram¶
The class diagram of the core logic is depicted in Fig. 5. Application logic is contained in the xfel::timer::Model class. The connection to remote TCP servers is implemented in class xfel::timer::TcpView according to the Model-View-Presenter pattern, as described in [1]. Access to the XFEL timing system is provided by the interface [†] xfel::timer::ISystem together with the implementation xfel::timer::System. ID and timing information is provided via the interface xfel::timer::ITimer, which is implemented by karabo::TimeServer (the top level Karabo device class).
xfel::timer::Model¶
The class xfel::timer::Model implements the application logic of the time server. It configures the timing information source, handles trigger ID and timestamp updates and provides the ID and timestamps via time ticks.
The xfel::timer::Timer class interacts with the core logic only by calling public methods of the model.
xfel::timer::Presenter¶
The class xfel::timer::Presenter implements the behavior on the interface to remote TCP servers, such as opening and closing a connection and acting on received data.
xfel::timer::TcpView¶
The class xfel::timer::TcpView interacts with the TCP stack to connect to remote TCP servers and to receive data. It uses events towards the presenter to indicate the reception of new data and to indicate possible errors during listening.
xfel::timer::System¶
The xfel::timer::System class implements the interface xfel::timer::ISystem to give access to the XFEL timing system.
In order to get timing information from the XFEL timing system, the
board need to be configured to raise an interrupt SIGUSR1 on a train
ID change. This is done using the ioctl()
system call on the
device file of the timing board, which is usually /dev/x2timersn
,
where n is the slot number of the board.
Warning
The ioctl()
related structures and macros are defined by 2
files pciedev_io.h
and x1timer_io.h
. which are part of the
Linux kernel driver for the timing board. These files always need
to match the ones from the driver installed on the μTCA crate,
where the TimeServer device is run.
Initialization¶
The steps performed during initialization depends on the selected
timing source. The source is specified using the generic URI syntax
scheme:hierarchical_part
. The following values are supported:
local:internal
for internally generated timing information,local:x2timer
for XFEL timing, using a μTCA x2timer boardtcp://<host:port>
for timing from remote TCP servers.
If no scheme is specified, local
is assumed.
For internally generated timing, a thread is created that simply
counts upwards with the specified period. For XFEL timing, an
interrupt handler for SIGUSR1
is registered to read out timing
information from the hardware. For timing from remote TCP servers, a
TCP channel is opened to the specified host.
After the device is initialized, it is no longer possible to switch the timing source.
The methods to initialize the core are listed in Table 1. Before starting operation, the methods setIdSource(), setTimer(), and setPeriod() need to be called to inject the necessary run time parameters. Then initialize() is called to actually start operation.
Method | Description |
---|---|
setIdSource(sourceUri) | sets the source of timing information (in URI form scheme:hierarchical_part) |
setPeriod(period) | sets the time period for internal timing |
setTimer(timer) | sets the receiver of the time tick (a class implementing the xfel::timer::ITimer interface) |
initialize() | starts operation according to specified source |
Operation¶
Once the core is initialized, it automatically starts generating time ticks, which are provided over the xfel::timer::ITimer interface. For the TimeServer device, the karabo::TimeServer class itself implements this interface, so that the ticks are available on Karabo level, where a tick is converted into a Karabo signal emitted to the message broker.
xfel::timer::ITimer interface¶
The xfel::timer::ITimer interface defines one method tick(), with the trigger ID, timestamp as seconds and fractional seconds, and period as parameters.
The timestamp is the number of seconds since UNIX epoch, which is 1.1.1970 UTC. The fractional part of the timestamp is specified in attoseconds, however the resolution is depending on the selected ID source. If the ID is generated by the XFEL timing system, then the associated timestamp is provided only with microseconds resolution. For all other ID sources, the system call clock_gettime() is used, which returns a time with nanosecond resolution.
The period is specified in microseconds, and is the averaged time difference between consecutive trigger timestamps
Shutdown¶
The steps performed during shutdown depends on the specified timing source. For internal timing, the thread is terminated. For XFEL timing, the signal handler for SIGUSR1 is unregistered. For timing from remote TCP servers, the TCP connection is closed.
The method to shut down the core is listed in Table 2.
Method | Description |
---|---|
shutdown() | stops operation according to specified source |
Logging¶
Logging for other classes than those derived from the karabo::core::Device base class is provided by the Log class. Macros simplify the process of creating log messages, and a handler needs to be installed, which will process the log message
Macros¶
The Log class has an internal output stream, which can be filled using the macros
- LOG_ERROR
- LOG_WARN
- LOG_INFO
- LOG_DEBUG
as in the following example:
LOG_DEBUG << "some debug message";
The macro instantiates the Log class, fills the internal output stream, and finally destructs the Log class, which results in calling the handler, if any was installed, with the string representation of the output stream.
Handler¶
In order to forward a log message from the Log class to the Karabo framework, the TimeServer installs a handler. The handler is defined as:
void TimeServer::logEvent(int level, const char* message);
The handler is registered with the static method karabo::Log::setHandler(). Since it is a class method of the TimeServer, the function pointer needs to be created using the templated method CreateMessageHandler():
xfel::timer::Log::setHandler(
xfel::timer::CreateMessageHandler<TimeServer>(
this, &TimeServer::logEvent
)
);
Integration into Karabo Devices¶
The Karabo base device has been extended in order to make use of a TimeServer. It also requires a specific instance name for the TimeServer device.
TimeServer Instantiation¶
If the TimeServer device is required as a source for train ID and timestamp, it needs to be initialized with a fixed instance name Karabo_TimeServer.
Karabo Device Configuration¶
If a Karabo device is configured to use the TimeServer device, then it subscribes to the signal ‘signalTimeTick’ of the device named ‘Karabo_TimeServer’. The associated slot saves this data locally and also calls a hook onTimeUpdate(), which a derived Karabo device can override.
Calculating ID and Timestamp¶
When an expected parameter is set without using the timestamp argument, then the missing timestamp and train ID is calculated based on the values provided from the last TimeServer update (see karabo::core::Device::getActualTimestamp()). First, the difference between the current time and the time of the last train ID change is calculated. Then, the difference is compared with the period, and if the difference is larger (due to missing TimeServer updates), then the train ID is interpolated based on the given average period.
TCP Server Protocol¶
The TCP server protocol uses simple ASCII string messages [‡]. The
only information contained in a message is an integer number
specifying the trigger ID. On the TimeServer side, the function
strtoull()
is used to convert the ASCII string into an integer for
further processing.
Warning
The time stamp that is associated with the received train ID is the time, when the message was received. This results in a slight inaccuracy, which depends on network latency.
Abbreviations and acronyms¶
Core | Main logic part of the TimeServer device |
MVP | Model-View-Presenter design pattern |
Timing System | Delivers reference clock, trigger synchronous to a train of XFEL pulses, and ID of pulse train. |
Trigger ID | The ID of the event that triggers activity. For XFEL, this ID is called Train ID, other facilities may call this macro pulse or bunch ID. |
References¶
[1] |
|
[*] | Classes used inside the TimeServer device are defined in namespace karabo, if they depend on resources from the Karabo framework, otherwise they are defined in namespace xfel::timer. |
[†] | In C++, interfaces are abstract classes that contain only pure virtual methods. |
[‡] | It was used in a setup at Trieste Synchroton, where an AdqDigitizer and TimeServer device were run together. The TimeServer device received bunch ID from the TANGO domain via a TCP server using this protocol. |