Merge branch 'add_fake_library' into 'stable-1.6'

Add fake library

See merge request etherlab.org/ethercat!136
This commit is contained in:
Florian Pose
2024-07-26 11:18:49 +00:00
16 changed files with 3189 additions and 987 deletions
+1
View File
@@ -33,6 +33,7 @@ ethercat.spec
examples/dc_user/ec_dc_user_example
examples/user/ec_user_example
examples/user/build/
fake_lib/libfakeethercat.la
lib/*.cmake
lib/libethercat.la
lib/libethercat.pc
+7 -4
View File
@@ -1,5 +1,5 @@
image:
registry.gitlab.com/etherlab.org/build-container-factory/leap-15.3:linux-syms
registry.gitlab.com/etherlab.org/build-container-factory/leap-15.4:linux-syms
stages:
- build
@@ -60,14 +60,14 @@ build:
script:
- ./bootstrap
- ./configure --with-linux-dir=/usr/src/linux-obj/$(uname -i)/default --enable-tty --with-devices=2 --enable-ccat
- ./configure --with-linux-dir=/usr/src/linux-obj/$(uname -i)/default --enable-tty --with-devices=2 --enable-ccat --enable-fakeuserlib
- make -j8 all modules
- make -C lib symbol-version-check
- make DISTCHECK_CONFIGURE_FLAGS="--with-linux-dir=/usr/src/linux-obj/$(uname -i)/default" distcheck
- make dist
- mkdir test_dist && cd test_dist && tar xzf ../ethercat-*.tar.gz && cd ethercat-*/
- mkdir build && cd build
- ../configure --with-linux-dir=/usr/src/linux-obj/$(uname -i)/default --disable-8139too --enable-tty --with-devices=2 --enable-ccat
- ../configure --with-linux-dir=/usr/src/linux-obj/$(uname -i)/default --disable-8139too --enable-tty --with-devices=2 --enable-ccat --enable-fakeuserlib
- make -j8 all modules
artifacts:
@@ -124,8 +124,11 @@ doxygen:
# It must be named 'pdf' and must produce a 'pdf' directory as an artifact.
# All PDF files in this directory will be collected.
pdf:
needs:
- job: commands
artifacts: true
stage: doc
image: registry.gitlab.com/etherlab.org/build-container-factory/leap-15.3:texlive
image: registry.gitlab.com/etherlab.org/build-container-factory/leap-15.4:texlive
script:
- cd documentation
- git show -s --format="\def\revision{%h}\def\gitversion{%(describe)}\def\gittag{%(describe:abbrev=0)}\def\gitauthor{%an}\def\isodate#1-#2-#3x{\day=#3 \month=#2 \year=#1}\isodate %csx" HEAD > git.tex
+1977 -970
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -47,6 +47,11 @@ SUBDIRS += \
examples
endif
if ENABLE_FAKEUSERLIB
SUBDIRS += \
fake_lib
endif
if ENABLE_TTY
SUBDIRS += tty
endif
+4
View File
@@ -4,6 +4,10 @@ vim: spelllang=en spell tw=78
-------------------------------------------------------------------------------
Changes in 1.6.1:
* Added libfakeethercat to simulate Process Data of EtherCAT Slaves.
Changes in 1.6.0:
* Added all native Ethernet drivers for kernels 5.14 and 6.1.
+11 -4
View File
@@ -15,7 +15,7 @@ Contents:
This is an open-source EtherCAT master implementation for Linux 2.6 or newer.
See the [features file](FEATURES.md) for a list of features. For more
information, see http://etherlab.org/en/ethercat.
information, see https://etherlab.org/ethercat.
or contact
@@ -54,7 +54,7 @@ make doc
```
An up-to-date Doxygen output can be found on
[docs.etherlab.org](https://docs.etherlab.org/ethercat/1.5/doxygen/index.html).
[docs.etherlab.org](https://docs.etherlab.org/ethercat/1.6/doxygen/index.html).
# Requirements
@@ -65,13 +65,20 @@ the EtherCAT master.
## Hardware requirements
A table of supported hardware can be found at
http://etherlab.org/en/ethercat/hardware.php.
A table of supported hardware can be found at:
https://docs.etherlab.org/ethercat/1.6/doxygen/devicedrivers.html
# Building and installing
See the [install file](INSTALL.md).
# Dry-run and Field Simulation
A limited set of the userspace API is available in `libfakeethercat`,
a library which can be used to run an userspace application
without an EtherCAT master or with emulated EtherCAT slaves.
Please find some details [here](fake_lib/README.md).
# Realtime and Tuning
Realtime patches for the Linux kernel are supported, but not required. The
+33 -1
View File
@@ -31,7 +31,7 @@ AC_PREREQ(2.59)
# - Update version number below
# - make dist-bzip2
#
AC_INIT([ethercat],[1.6.0],[fp@igh.de])
AC_INIT([ethercat],[1.6.1],[fp@igh.de])
AC_CONFIG_AUX_DIR([autoconf])
AM_INIT_AUTOMAKE([-Wall -Wno-override -Werror dist-bzip2 subdir-objects foreign])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -1168,6 +1168,37 @@ fi
AM_CONDITIONAL(ENABLE_USERLIB, test "x$userlib" = "x1")
#-----------------------------------------------------------------------------
# Fake Userspace library generation
#-----------------------------------------------------------------------------
AC_MSG_CHECKING([whether to build the fake userspace library])
AC_ARG_ENABLE([fakeuserlib],
AS_HELP_STRING([--enable-fakeuserlib],
[Generation of the userspace library (default: no)]),
[
case "${enableval}" in
yes) fakeuserlib=1
;;
no) fakeuserlib=0
;;
*) AC_MSG_ERROR([Invalid value for --enable-fakeuserlib])
;;
esac
],
[fakeuserlib=0]
)
if test "x${fakeuserlib}" = "x1"; then
AC_MSG_RESULT([yes])
PKG_CHECK_MODULES([RTIPC], [librtipc])
else
AC_MSG_RESULT([no])
fi
AM_CONDITIONAL(ENABLE_FAKEUSERLIB, test "x$fakeuserlib" = "x1")
#-----------------------------------------------------------------------------
# TTY driver
#-----------------------------------------------------------------------------
@@ -1389,6 +1420,7 @@ AC_CONFIG_FILES([
examples/user/Makefile
examples/xenomai/Makefile
examples/xenomai_posix/Makefile
fake_lib/Makefile
include/Makefile
lib/Makefile
lib/libethercat.pc
+40 -3
View File
@@ -351,7 +351,7 @@ Public License (GPL \cite{gpl})\index{GPL}, version 2. Other developers, that
want to use EtherCAT with Linux systems, are invited to use the master code or
even participate on development.
To allow static linking of userspace application against the master's
To allow dynamic linking of userspace application against the master's
application interface (see \autoref{chap:api}), the userspace library (see
\autoref{sec:userlib}) is licensed under the terms and conditions of the GNU
Lesser General Public License (LGPL \cite{lgpl})\index{LGPL}, version 2.1.
@@ -962,8 +962,8 @@ be found.
The application interface of the EtherCAT master is defined in the header file
\textit{include/ecrt.h} (acronym for ``EtherCAT Real-Time'') which is listed
in this section. The calling conventions of all methods are documented in the
comments of this header. There is also a Doxygen-generated online version at
\url{https://docs.etherlab.org}.
comments of this header. There is also a Doxygen-generated \cite{doxygen}
online version at \url{https://docs.etherlab.org}.
\lstinputlisting[
basicstyle=\ttfamily\scriptsize,
@@ -2709,6 +2709,10 @@ installation prefix as \textit{libethercat.a} (for static linking),
\textit{libethercat.la} (for the use with \textit{libtool}) and
\textit{libethercat.so} (for dynamic linking).
For running an application without actual EtherCAT hardware or for simulation
purposes, there is a special library called \textit{libfakeethercat} (see
\autoref{sec:fakelib}).
\subsection{Using the Library}
The application interface header \textit{ecrt.h} (see \autoref{sec:ecrt}) can
@@ -2750,6 +2754,9 @@ gcc -static ectest.c -o ectest -I/opt/etherlab/include \
/opt/etherlab/lib/libethercat.a
\end{lstlisting}
Please keep in mind, that your application has to be licensed under GPLv2
then, because the LGPL does only allow dynamic linking.
\subsection{Implementation}
\label{sec:userimp}
@@ -2836,6 +2843,33 @@ The test results show, that for this configuration, the userspace API causes
about \unit{1}{\micro\second} additional delay for each function, compared to
the kernel API.
\subsection{Simulation / Fake Library}
\label{sec:fakelib}
Sometimes is is handy to run your EtherCAT realtime application without an
actual EtherCAT network connected, for example for test purposes.
Though it is possible to spin up an EtherCAT master and to connect it to a
loopback device, this step is not always wanted.
The EtherCAT master (since version 1.6.1) comes with a library
\textit{libfakeethercat} that comes with a reasonable subset of the EtherCAT
application interface (see \autoref{chap:api}).
The \texttt{ecrt} method implementation in the fake library will just accept
your input and behave as if everything would be fine. Without further steps,
the process data will be all-zero then.
As a special feature, the \textit{libfakeethercat} will create RtIPC
\cite{rtipc} endpoints for registered PDO entries to enable a simulation
interface. Another application that either uses RtIPC directly or another
(inverted) instance of \textit{libfakeethercat} will then connect to these
endpoints and thus create the possibility to provide simulated values to your
pristine application.
The fake library functions an usage is documented in Doxygen~\cite{doxygen}
and the most recent version can be found online:
\url{https://docs.etherlab.org/ethercat/1.6/doxygen/libfakeethercat.html}
%------------------------------------------------------------------------------
\section{RTDM Interface}
@@ -3547,6 +3581,9 @@ Applications.
\url{http://svn.gna.org/svn/xenomai/tags/v2.4.0/doc/nodist/pdf/RTDM-and-Applications.pdf},
2013.
\bibitem{rtipc} Real-Time Inter-Process-Communication library. Part of the
EtherLab toolkit. \url{https://gitlab.com/etherlab.org/rtipc}, 2024.
\end{thebibliography}
\printnomenclature
+2 -2
View File
@@ -3440,7 +3440,7 @@ Il y a plusieurs mani\`eres d'obtenir le logiciel du ma\^itre:
\item Une version officielle (par exemple \masterversion) peut \^etre
t\'el\'echarg\'ee depuis le site web du
ma\^itre\footnote{\url{http://etherlab.org/en/ethercat/index.php}}
ma\^itre\footnote{\url{https://etherlab.org/ethercat}}
dans le projet EtherLab~\cite{etherlab} sous forme d'archive tar.
\item La r\'evision de d\'eveloppement la plus r\'ecente (mais aussi
@@ -3793,7 +3793,7 @@ KERNEL=="EtherCAT[0-9]*", MODE="0664", GROUP="users"
\bibitem{etherlab} Ingenieurgemeinschaft IgH: EtherLab -- Open Source Toolkit
for rapid realtime code generation under Linux with Simulink/RTW and EtherCAT
technology. \url{http://etherlab.org/en}, 2008.
technology. \url{https://etherlab.org}, 2024.
\bibitem{dlspec} IEC 61158-4-12: Data-link Protocol Specification.
International Electrotechnical Commission (IEC), 2005.
+3 -3
View File
@@ -26,7 +26,7 @@ Version: @VERSION@
Release: 1
License: GPL
URL: http://etherlab.org/en/ethercat
URL: https://etherlab.org/ethercat
Provides: @PACKAGE@
Source: %{name}-%{version}.tar.bz2
@@ -44,7 +44,7 @@ Group: EtherLab
%description
This is an open-source EtherCAT master implementation for Linux 2.6. See the
FEATURES file for a list of features. For more information, see
http://etherlab.org/en/ethercat.
https://etherlab.org/ethercat.
%kernel_module_package
@@ -60,7 +60,7 @@ Group: EtherLab
%description devel
This is an open-source EtherCAT master implementation for Linux 2.6. See the
FEATURES file for a list of features. For more information, see
http://etherlab.org/en/ethercat.
https://etherlab.org/ethercat.
#-----------------------------------------------------------------------------
+46
View File
@@ -0,0 +1,46 @@
#------------------------------------------------------------------------------
#
# Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT master userspace library.
#
# The IgH EtherCAT master userspace library is free software; you can
# redistribute it and/or modify it under the terms of the GNU Lesser General
# Public License as published by the Free Software Foundation; version 2.1 of
# the License.
#
# The IgH EtherCAT master userspace library is distributed in the hope that
# it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with the IgH EtherCAT master userspace library. If not, see
# <http://www.gnu.org/licenses/>.
#
#------------------------------------------------------------------------------
lib_LTLIBRARIES = libfakeethercat.la
#------------------------------------------------------------------------------
libfakeethercat_la_SOURCES = \
fakeethercat.cpp
noinst_HEADERS = \
fakeethercat.h
libfakeethercat_la_CXXFLAGS = \
-fno-strict-aliasing \
-Wall \
-I$(top_srcdir)/include \
-Dethercat_EXPORTS \
-fvisibility=hidden \
$(RTIPC_CFLAGS)
libfakeethercat_la_LDFLAGS = -version-info 3:0:2 \
$(RTIPC_LIBS) \
-Wl,--version-script=$(srcdir)/../lib/libethercat.map \
-fvisibility=hidden
libfakeethercat_la_DEPENDENCIES = ../lib/libethercat.map
+133
View File
@@ -0,0 +1,133 @@
FakeEtherCAT Library {#libfakeethercat}
====================
Libfakeethercat is a userspace library which has the same API as
the EtherCAT master interface library libethercat.
Libfakeethercat can be used to spin up your RT application in a dry-run mode,
without any master configured or slaves attached.
Furthermore, it is possible to emulate EtherCAT slaves on process data level
by running two applications back to back.
## Supported features
Currently, only a very limited subset of libethercat functionality is supported:
- Creating master and domain instances
- Activating master, `send`/`receive`.
- Processing and queuing domains
- Configuring PDOs
- Configuring SDOs using `ecrt_slave_config_sdo*`
The SDO config does not do anything,
but when activating the master the SDO config will
be dumped into a JSON file.
ecrt_master_state() and ecrt_domain_state() both return states as if
the bus works without errors.
So currenty, a bus error cannot be simulated.
## How to build
[RtIPC](https://gitlab.com/etherlab.org/rtipc) is needed.
Simply pass `--enable-fakeuserlib` to your `./configure` call
and the library will be built for you.
## How to set up dry run mode
### Redirect library loading
To avoid recompiling your application,
we will use `LD_LIBRARY_PATH` to load `libfakeethercat` instead of `libethercat`.
```sh
# pick a location for an empty directory
export MY_LIB_LOCATION=$HOME/fake_lib64
# create that directory
mkdir -p $MY_LIB_LOCATION
# create a symlink to libfakeethercat
# assuming SOVERSION is 1
# debian users, please use /usr/lib/x86_64-linux-gnu/libfakeethercat.so.1
ln -s /usr/lib64/libfakeethercat.so.1 $MY_LIB_LOCATION/libethercat.so.1
# use MY_LIB_LOCATION to load libraries first
export LD_LIBRARY_PATH=$MY_LIB_LOCATION
# check whether everything is done right
ldd my_application | grep ethercat
libethercat.so.1 => /home/vh/fake_lib64/libethercat.so.1 (0x00007fa5a5c59000)
```
### Set up FakeEtherCAT Home
RtIPC needs a place to store its configuration.
Set `FAKE_EC_HOMEDIR` environment variabe to a path to an empty directory,
for instance `/tmp/FakeEtherCAT`.
`FAKE_EC_NAME` can be set to a useful name of your application,
default is `FakeEtherCAT`.
```sh
export FAKE_EC_HOMEDIR=/tmp/FakeEtherCAT
rm -rf $FAKE_EC_HOMEDIR
mkdir -p $FAKE_EC_HOMEDIR
```
### Spin up your application
Now it's time to simply launch your application.
You will notice that the PDO configuration will be dumped at stderr.
The path displayed is the path of the RtIPC variable in the following format:
`$FAKE_EC_PREFIX/$MASTER_ID/$DOMAIN_ID/$ALIAS$POSITION/$PDO`.
## How to emulate EtherCAT slaves
Let's say you'd like to build virtual EtherCAT slaves to emulate your field.
Libfakeethercat makes that possible with the help of RtIPC.
### Building a simulator
Your field emulator simply has to swap the sync manager direction setting
(EC_DIR_INPUT and EC_DIR_OUTPUT) in ec_sync_info_t.
Libfakeethercat instances use shared memory, provided by RtIPC,
to exchange process data.
The direction setting decides which instance writes and which reads from
shared memory.
For instance, emulating a digial output works in the following way:
Create another real time application with the same slave information
as your control application.
Then, replace all EC_DIR_INPUT with EC_DIR_OUTPUT and vice versa.
Now, remember to read process data instead of writing it, and vice versa.
So, your EL2004 digital out will be read by your simulating application
and has PDO object 0x1600 ff. configured with Sync Manager 2 as EC_DIR_INPUT.
[EtherLab](https://gitlab.com/etherlab.org/etherlab) provides
a convenient way to build an entire simulator using SIMULINK since
Version 2.4.0.
Run `web(etherlab_help_path('swap_io.html'), '-helpbrowser')`
in your MATLAB shell to read more about how to set up a
Process Data simulator.
### Start your application
First, do all the steps explained above to run your
control application in dry run mode.
Then, in another shell, do the same thing with your simulator,
but do not remove the `FAKE_EC_HOMEDIR` directory and
pick another `FAKE_EC_NAME`.
Carefully watch the PDO configuration on stderr and compare them.
All paths configured as Output on the control application have to
be configured as Input on your simulator and vice versa.
If you use multiple domains and there is a mismatch of the domain IDs,
set `FAKE_EC_DOMAIN_PERMUTATION` to a space-separated list of integers to
permutate the domain IDs of one application.
`FAKE_EC_DOMAIN_PERMUTATION="0 1"` swaps domains 0 and 1, for instance.
Finally, your control application needs to be restarted
so it can find the RtIPC variables which contains the process data of the
simulator.
## Environment variables
- FAKE_EC_DOMAIN_PERMUTATION: Permutate the domain IDs, useful to match control and simulation applications.
- FAKE_EC_HOMEDIR: Directory for RtIPC builletin board and SDO json files
- FAKE_EC_NAME: Will be used for naming RtIPC config and SDO json file
- FAKE_EC_PREFIX: Prefix for RtIPC variables, useful to run multiple simulators side by side.
File diff suppressed because it is too large Load Diff
+228
View File
@@ -0,0 +1,228 @@
/*****************************************************************************
*
* Copyright (C) 2024 Bjarne von Horn, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT master userspace library.
*
* The IgH EtherCAT master userspace library is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
* of the License.
*
* The IgH EtherCAT master userspace library is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
****************************************************************************/
#pragma once
#include <ecrt.h>
#include <rtipc.h>
#include <iostream>
#include <iomanip>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>
struct Offset
{
int bytes;
int bits;
constexpr Offset(int bytes,
int bits) : bytes(bytes), bits(bits) {}
constexpr bool operator!=(const Offset &other) const noexcept
{
return bytes != other.bytes || bits != other.bits;
}
};
constexpr Offset NotFound(-1, -1);
struct pdo
{
std::vector<ec_pdo_entry_info_t> entries;
size_t sizeInBytes() const;
Offset findEntry(uint16_t idx, uint8_t subindex) const;
};
struct syncManager
{
ec_direction_t dir;
std::map<uint16_t /* address */, pdo> pdos;
};
class ec_address
{
uint32_t value;
public:
ec_address(uint16_t alias, /**< Slave alias. */
uint16_t position /**< Slave position. */)
: value(static_cast<uint32_t>(alias) << 16 | position)
{
}
uint16_t getAlias() const { return value >> 16; }
uint16_t getPosition() const { return value & 0xFFFF; }
uint32_t getCombined() const { return value; }
bool operator<(const ec_address &other) const noexcept
{
return value < other.value;
}
bool operator==(const ec_address &other) const noexcept
{
return value == other.value;
}
};
class sdo_address
{
uint32_t value;
public:
sdo_address(uint16_t index, /**< Slave alias. */
uint8_t subindex /**< Slave position. */)
: value(static_cast<uint32_t>(index) << 8 | subindex)
{
}
uint16_t getIndex() const { return value >> 8; }
uint8_t getSubIndex() const { return value & 0xFF; }
uint32_t getCombined() const { return value; }
bool operator<(const sdo_address &other) const noexcept
{
return value < other.value;
}
bool operator==(const sdo_address &other) const noexcept
{
return value == other.value;
}
};
struct ec_slave_config
{
ec_address address;
uint32_t vendor_id; /**< Expected vendor ID. */
uint32_t product_code; /**< Expected product code. */
std::map<unsigned int, syncManager> sync_managers;
std::map<sdo_address, std::basic_string<uint8_t>> sdos;
ec_slave_config(
ec_address address,
uint32_t vendor_id, /**< Expected vendor ID. */
uint32_t product_code /**< Expected product code. */)
: address(address), vendor_id(vendor_id), product_code(product_code)
{
}
void dumpJson(std::ostream &out, int indent) const;
};
struct ec_domain
{
private:
struct PdoMap
{
size_t offset;
size_t size_bytes;
ec_address slave_address;
unsigned int syncManager;
uint16_t pdo_index;
ec_direction_t dir;
PdoMap(
size_t offset,
size_t size_bytes,
ec_address slave_address,
unsigned int syncManager,
uint16_t pdo_index,
ec_direction_t dir)
: offset(offset), size_bytes(size_bytes), slave_address(slave_address), syncManager(syncManager), pdo_index(pdo_index), dir(dir)
{
}
};
std::vector<uint8_t> data;
std::vector<unsigned char> connected;
std::vector<PdoMap> mapped_pdos;
rtipc_group *rt_group;
const char *prefix;
ec_master_t *master;
bool activated_ = false;
size_t numSlaves = 0;
public:
explicit ec_domain(struct rtipc *rtipc, const char *prefix, ec_master_t *master);
uint8_t *getData() const
{
if (!activated_)
return nullptr;
return const_cast<uint8_t *>(data.data());
}
int activate(int domain_id);
int process();
int queue();
size_t getNumSlaves() const { return numSlaves; }
ssize_t map(ec_slave_config const &config, unsigned int syncManager,
uint16_t pdo_index);
ec_master_t *getMaster() const { return master; }
};
struct ec_master
{
private:
struct RtIpcDeleter
{
void operator()(struct rtipc *r) const
{
rtipc_exit(r);
}
};
std::string rt_ipc_dir;
std::string rt_ipc_name;
std::list<ec_domain> domains;
std::map<ec_address, ec_slave_config> slaves;
std::unique_ptr<struct rtipc, RtIpcDeleter> rt_ipc;
int id_;
public:
explicit ec_master(int id);
int activate();
ec_domain *createDomain();
int getNoSlaves() const { return slaves.size(); }
int getId() const { return id_; }
ec_slave_config_t *slave_config(
uint16_t alias, /**< Slave alias. */
uint16_t position, /**< Slave position. */
uint32_t vendor_id, /**< Expected vendor ID. */
uint32_t product_code /**< Expected product code. */
);
};
+3
View File
@@ -82,6 +82,9 @@ LIBETHERCAT_1.5.2 {
ecrt_voe_handler_received_header;
ecrt_voe_handler_send_header;
ecrt_voe_handler_write;
local:
# Hide all C++ symbols in libfakeethercat
_Z*;
};
LIBETHERCAT_1.5.3 {
+3
View File
@@ -40,6 +40,9 @@
A list of all native network card drivers can be found
<a href="devicedrivers.html">here</a>.
A <a href="libfakeethercat.html">second userspace library</a> can be used for a dry-run mode
or simulating Process Data.
For information how to build and install, see the INSTALL file in the source
root.