Merge branch 'fake_without_domain' into 'stable-1.6'
Remove domain information from RtIPC path. See merge request etherlab.org/ethercat!149
This commit is contained in:
commit
5b3663e15b
|
|
@ -1,16 +1,16 @@
|
||||||
FakeEtherCAT Library {#libfakeethercat}
|
FakeEtherCAT Library {#libfakeethercat}
|
||||||
====================
|
====================
|
||||||
|
|
||||||
Libfakeethercat is a userspace library which has the same API as
|
Libfakeethercat is a userspace library which has the same API as the EtherCAT
|
||||||
the EtherCAT master interface library libethercat.
|
master interface library libethercat. Libfakeethercat can be used to spin up
|
||||||
Libfakeethercat can be used to spin up your RT application in a dry-run mode,
|
your RT application in a dry-run mode, without any master configured or slaves
|
||||||
without any master configured or slaves attached.
|
attached. Furthermore, it is possible to emulate EtherCAT slaves on process
|
||||||
Furthermore, it is possible to emulate EtherCAT slaves on process data level
|
data level by running two applications back to back.
|
||||||
by running two applications back to back.
|
|
||||||
|
|
||||||
## Supported features
|
## Supported features
|
||||||
|
|
||||||
Currently, only a very limited subset of libethercat functionality is supported:
|
Currently, only a very limited subset of libethercat functionality is
|
||||||
|
supported:
|
||||||
|
|
||||||
- Creating master and domain instances
|
- Creating master and domain instances
|
||||||
- Activating master, `send`/`receive`.
|
- Activating master, `send`/`receive`.
|
||||||
|
|
@ -18,26 +18,24 @@ Currently, only a very limited subset of libethercat functionality is supported:
|
||||||
- Configuring PDOs
|
- Configuring PDOs
|
||||||
- Configuring SDOs using `ecrt_slave_config_sdo*`
|
- Configuring SDOs using `ecrt_slave_config_sdo*`
|
||||||
|
|
||||||
The SDO config does not do anything,
|
The SDO config does not do anything, but when activating the master the SDO
|
||||||
but when activating the master the SDO config will
|
config will be dumped into a JSON file.
|
||||||
be dumped into a JSON file.
|
|
||||||
|
|
||||||
ecrt_master_state() and ecrt_domain_state() both return states as if
|
`ecrt_master_state()` and `ecrt_domain_state()` both return states as if the
|
||||||
the bus works without errors.
|
bus works without errors. So currently, a bus error cannot be simulated.
|
||||||
So currenty, a bus error cannot be simulated.
|
|
||||||
|
|
||||||
## How to build
|
## How to build
|
||||||
|
|
||||||
[RtIPC](https://gitlab.com/etherlab.org/rtipc) is needed.
|
[RtIPC](https://gitlab.com/etherlab.org/rtipc) is needed. Simply pass
|
||||||
Simply pass `--enable-fakeuserlib` to your `./configure` call
|
`--enable-fakeuserlib` to your `./configure` call and the library will be
|
||||||
and the library will be built for you.
|
built for you.
|
||||||
|
|
||||||
## How to set up dry run mode
|
## How to set up dry run mode
|
||||||
|
|
||||||
### Redirect library loading
|
### Redirect library loading
|
||||||
|
|
||||||
To avoid recompiling your application,
|
To avoid recompiling your application, we will use `LD_LIBRARY_PATH` to load
|
||||||
we will use `LD_LIBRARY_PATH` to load `libfakeethercat` instead of `libethercat`.
|
`libfakeethercat` instead of `libethercat`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# pick a location for an empty directory
|
# pick a location for an empty directory
|
||||||
|
|
@ -52,16 +50,15 @@ ln -s /usr/lib64/libfakeethercat.so.1 $MY_LIB_LOCATION/libethercat.so.1
|
||||||
export LD_LIBRARY_PATH=$MY_LIB_LOCATION
|
export LD_LIBRARY_PATH=$MY_LIB_LOCATION
|
||||||
# check whether everything is done right
|
# check whether everything is done right
|
||||||
ldd my_application | grep ethercat
|
ldd my_application | grep ethercat
|
||||||
libethercat.so.1 => /home/vh/fake_lib64/libethercat.so.1 (0x00007fa5a5c59000)
|
libethercat.so.1 => /home/vh/fake_lib64/libethercat.so.1 (0x7fa5c590)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set up FakeEtherCAT Home
|
### Set up FakeEtherCAT Home
|
||||||
|
|
||||||
RtIPC needs a place to store its configuration.
|
RtIPC needs a place to store its configuration. Set `FAKE_EC_HOMEDIR`
|
||||||
Set `FAKE_EC_HOMEDIR` environment variabe to a path to an empty directory,
|
environment variable to a path to an empty directory, for instance
|
||||||
for instance `/tmp/FakeEtherCAT`.
|
`/tmp/FakeEtherCAT`. `FAKE_EC_NAME` can be set to a useful name of your
|
||||||
`FAKE_EC_NAME` can be set to a useful name of your application,
|
application, default is `FakeEtherCAT`.
|
||||||
default is `FakeEtherCAT`.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export FAKE_EC_HOMEDIR=/tmp/FakeEtherCAT
|
export FAKE_EC_HOMEDIR=/tmp/FakeEtherCAT
|
||||||
|
|
@ -113,13 +110,9 @@ Then, in another shell, do the same thing with your simulator,
|
||||||
but do not remove the `FAKE_EC_HOMEDIR` directory and
|
but do not remove the `FAKE_EC_HOMEDIR` directory and
|
||||||
pick another `FAKE_EC_NAME`.
|
pick another `FAKE_EC_NAME`.
|
||||||
|
|
||||||
Carefully watch the PDO configuration on stderr and compare them.
|
Carefully watch the PDO configuration on stderr and compare them. All paths
|
||||||
All paths configured as Output on the control application have to
|
configured as output on the control application have to be configured as input
|
||||||
be configured as Input on your simulator and vice versa.
|
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
|
Finally, your control application needs to be restarted
|
||||||
so it can find the RtIPC variables which contains the process data of the
|
so it can find the RtIPC variables which contains the process data of the
|
||||||
|
|
@ -127,7 +120,7 @@ simulator.
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
- FAKE_EC_DOMAIN_PERMUTATION: Permutate the domain IDs, useful to match control and simulation applications.
|
- FAKE_EC_HOMEDIR: Directory for RtIPC bulletin board and SDO json files
|
||||||
- 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_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.
|
- FAKE_EC_PREFIX: Prefix for RtIPC variables, useful to run multiple
|
||||||
|
simulators side by side.
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,6 @@
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
|
|
||||||
static std::vector<size_t> getPermutationVector(size_t count);
|
|
||||||
|
|
||||||
static std::ostream &operator<<(std::ostream &os, const sdo_address &a)
|
static std::ostream &operator<<(std::ostream &os, const sdo_address &a)
|
||||||
{
|
{
|
||||||
os << std::setfill('0') << std::hex << std::setw(6) << a.getCombined();
|
os << std::setfill('0') << std::hex << std::setw(6) << a.getCombined();
|
||||||
|
|
@ -118,7 +116,7 @@ int ec_domain::activate(int domain_id)
|
||||||
slaves.insert(pdo.slave_address.getCombined());
|
slaves.insert(pdo.slave_address.getCombined());
|
||||||
void *rt_pdo = nullptr;
|
void *rt_pdo = nullptr;
|
||||||
char buf[512];
|
char buf[512];
|
||||||
const auto fmt = snprintf(buf, sizeof(buf), "%s/%d/%d/%08X/%04X", prefix, master->getId(), domain_id, pdo.slave_address.getCombined(), pdo.pdo_index);
|
const auto fmt = snprintf(buf, sizeof(buf), "%s/%d/%08X/%04X", prefix, master->getId(), pdo.slave_address.getCombined(), pdo.pdo_index);
|
||||||
if (fmt < 0 || fmt >= (int)sizeof(buf))
|
if (fmt < 0 || fmt >= (int)sizeof(buf))
|
||||||
{
|
{
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
|
@ -213,14 +211,6 @@ int ecrt_domain_state(
|
||||||
|
|
||||||
int ec_master::activate()
|
int ec_master::activate()
|
||||||
{
|
{
|
||||||
const auto permutate = getPermutationVector(domains.size());
|
|
||||||
int i = 0;
|
|
||||||
for (auto &domain : domains)
|
|
||||||
{
|
|
||||||
if (domain.activate(permutate[i]))
|
|
||||||
return -1;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
std::ofstream out(rt_ipc_dir + "/" + rt_ipc_name + "_slaves.json");
|
std::ofstream out(rt_ipc_dir + "/" + rt_ipc_name + "_slaves.json");
|
||||||
if (!out.is_open())
|
if (!out.is_open())
|
||||||
|
|
@ -433,30 +423,6 @@ static const char *getRtIpcDir()
|
||||||
return "/tmp/FakeEtherCAT";
|
return "/tmp/FakeEtherCAT";
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<size_t> getPermutationVector(size_t count)
|
|
||||||
{
|
|
||||||
std::vector<size_t> ans;
|
|
||||||
for (size_t i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
ans.push_back(i);
|
|
||||||
}
|
|
||||||
const auto spec = getenv("FAKE_EC_DOMAIN_PERMUTATION");
|
|
||||||
if (!spec)
|
|
||||||
return ans;
|
|
||||||
std::istringstream is(spec);
|
|
||||||
std::istream_iterator<int> begin(is), end;
|
|
||||||
std::vector<int> values(begin, end);
|
|
||||||
if (values.size() % 2)
|
|
||||||
{
|
|
||||||
throw std::invalid_argument("Specify an even number of indices to permutate.\n");
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < values.size() / 2; ++i)
|
|
||||||
{
|
|
||||||
std::swap(ans.at(values[2 * i]), ans.at(values[2 * i + 1]));
|
|
||||||
}
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
|
|
||||||
ec_master::ec_master(int id) : rt_ipc_dir(getRtIpcDir()), rt_ipc_name(getName()), rt_ipc(rtipc_create(rt_ipc_name.c_str(), rt_ipc_dir.c_str())), id_(id)
|
ec_master::ec_master(int id) : rt_ipc_dir(getRtIpcDir()), rt_ipc_name(getName()), rt_ipc(rtipc_create(rt_ipc_name.c_str(), rt_ipc_dir.c_str())), id_(id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue