Merge branch '179-add-missing-functions-to-fake-library' into 'stable-1.6'
Add missing functions to fake library Closes #179 See merge request etherlab.org/ethercat!175
This commit is contained in:
commit
101aa52032
|
|
@ -1,6 +1,7 @@
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 Bjarne von Horn, Ingenieurgemeinschaft IgH
|
* Copyright (C) 2024 Bjarne von Horn, Ingenieurgemeinschaft IgH
|
||||||
|
* 2025 Florian Pose <fp@igh.de>
|
||||||
*
|
*
|
||||||
* This file is part of the IgH EtherCAT master userspace library.
|
* This file is part of the IgH EtherCAT master userspace library.
|
||||||
*
|
*
|
||||||
|
|
@ -32,11 +33,14 @@
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
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();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::ostream &operator<<(std::ostream &os, const ec_address &a)
|
static std::ostream &operator<<(std::ostream &os, const ec_address &a)
|
||||||
{
|
{
|
||||||
os << std::setfill('0') << std::hex << std::setw(8) << a.getCombined();
|
os << std::setfill('0') << std::hex << std::setw(8) << a.getCombined();
|
||||||
|
|
@ -104,124 +108,9 @@ Offset pdo::findEntry(uint16_t idx, uint8_t subindex) const
|
||||||
return NotFound;
|
return NotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
ec_domain::ec_domain(rtipc *rtipc, const char *prefix, ec_master_t *master):
|
/*****************************************************************************
|
||||||
rt_group(rtipc_create_group(rtipc, 1.0)), prefix(prefix), master(master)
|
* Master
|
||||||
{
|
****************************************************************************/
|
||||||
}
|
|
||||||
|
|
||||||
int ec_domain::activate()
|
|
||||||
{
|
|
||||||
std::unordered_set<uint32_t> slaves;
|
|
||||||
|
|
||||||
connected.resize(mapped_pdos.size());
|
|
||||||
size_t idx = 0;
|
|
||||||
for (const auto &pdo : mapped_pdos)
|
|
||||||
{
|
|
||||||
slaves.insert(pdo.slave_address.getCombined());
|
|
||||||
void *rt_pdo = nullptr;
|
|
||||||
char buf[512];
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
return -ENOBUFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (pdo.dir)
|
|
||||||
{
|
|
||||||
case EC_DIR_OUTPUT:
|
|
||||||
rt_pdo = rtipc_txpdo(rt_group, buf, rtipc_uint8_T,
|
|
||||||
data.data() + pdo.offset, pdo.size_bytes);
|
|
||||||
std::cerr << "Registering " << buf << " as Output\n";
|
|
||||||
break;
|
|
||||||
case EC_DIR_INPUT:
|
|
||||||
rt_pdo = rtipc_rxpdo(rt_group, buf, rtipc_uint8_T,
|
|
||||||
data.data() + pdo.offset, pdo.size_bytes,
|
|
||||||
connected.data() + idx);
|
|
||||||
std::cerr << "Registering " << buf << " as Input\n";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
std::cerr << "Unknown direction " << pdo.dir << '\n';
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!rt_pdo)
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to register RtIPC PDO\n";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
activated_ = true;
|
|
||||||
numSlaves = slaves.size();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ec_domain::process()
|
|
||||||
{
|
|
||||||
rtipc_rx(rt_group);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ec_domain::queue()
|
|
||||||
{
|
|
||||||
rtipc_tx(rt_group);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t ec_domain::map(ec_slave_config const &config,
|
|
||||||
unsigned int syncManager, uint16_t pdo_index)
|
|
||||||
{
|
|
||||||
if (activated_)
|
|
||||||
return -1;
|
|
||||||
for (const auto &pdo : mapped_pdos)
|
|
||||||
{
|
|
||||||
if (pdo.slave_address == config.address
|
|
||||||
&& syncManager == pdo.syncManager
|
|
||||||
&& pdo_index == pdo.pdo_index)
|
|
||||||
{
|
|
||||||
// already mapped;
|
|
||||||
return pdo.offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto ans = data.size();
|
|
||||||
const auto size =
|
|
||||||
config.sync_managers.at(syncManager).pdos.at(pdo_index).sizeInBytes();
|
|
||||||
mapped_pdos.emplace_back(ans, size, config.address, syncManager,
|
|
||||||
pdo_index, config.sync_managers.at(syncManager).dir);
|
|
||||||
data.resize(ans + size);
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *ecrt_domain_data(
|
|
||||||
const ec_domain_t *domain)
|
|
||||||
{
|
|
||||||
return domain->getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ecrt_domain_process(
|
|
||||||
ec_domain_t *domain)
|
|
||||||
{
|
|
||||||
return domain->process();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ecrt_domain_queue(
|
|
||||||
ec_domain_t *domain)
|
|
||||||
{
|
|
||||||
return domain->queue();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ecrt_domain_state(
|
|
||||||
const ec_domain_t *domain, /**< Domain. */
|
|
||||||
ec_domain_state_t *state /**< Pointer to a state object to store the
|
|
||||||
information. */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
state->working_counter = domain->getNumSlaves();
|
|
||||||
state->redundancy_active = 0;
|
|
||||||
state->wc_state = EC_WC_COMPLETE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ec_master::activate()
|
int ec_master::activate()
|
||||||
{
|
{
|
||||||
|
|
@ -492,6 +381,10 @@ ec_master::ec_master(int id):
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Slave Configuration
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
int ecrt_slave_config_complete_sdo(
|
int ecrt_slave_config_complete_sdo(
|
||||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||||
uint16_t index, /**< Index of the SDO to configure. */
|
uint16_t index, /**< Index of the SDO to configure. */
|
||||||
|
|
@ -553,8 +446,8 @@ int ecrt_slave_config_pdos(
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
auto &manager = sc->sync_managers[syncs[sync_idx].index];
|
auto &syncManager = sc->sync_managers[syncs[sync_idx].index];
|
||||||
manager.dir = syncs[sync_idx].dir;
|
syncManager.dir = syncs[sync_idx].dir;
|
||||||
for (unsigned int i = 0; i < syncs[sync_idx].n_pdos; ++i)
|
for (unsigned int i = 0; i < syncs[sync_idx].n_pdos; ++i)
|
||||||
{
|
{
|
||||||
const auto &in_pdo = syncs[sync_idx].pdos[i];
|
const auto &in_pdo = syncs[sync_idx].pdos[i];
|
||||||
|
|
@ -563,7 +456,7 @@ int ecrt_slave_config_pdos(
|
||||||
std::cerr << "Default mapping not supported.";
|
std::cerr << "Default mapping not supported.";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
auto &out_pdo = manager.pdos[in_pdo.index];
|
auto &out_pdo = syncManager.pdos[in_pdo.index];
|
||||||
for (unsigned int pdo_entry_idx = 0;
|
for (unsigned int pdo_entry_idx = 0;
|
||||||
pdo_entry_idx < in_pdo.n_entries; ++pdo_entry_idx)
|
pdo_entry_idx < in_pdo.n_entries; ++pdo_entry_idx)
|
||||||
{
|
{
|
||||||
|
|
@ -575,32 +468,108 @@ int ecrt_slave_config_pdos(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ecrt_domain_reg_pdo_entry_list(
|
int ecrt_slave_config_sync_manager(
|
||||||
ec_domain_t *domain, /**< Domain. */
|
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||||
const ec_pdo_entry_reg_t *pdo_entry_regs /**< Array of PDO
|
uint8_t sync_index, /**< Sync manager index. Must be less
|
||||||
registrations. */
|
than #EC_MAX_SYNC_MANAGERS. */
|
||||||
)
|
ec_direction_t direction, /**< Input/Output. */
|
||||||
|
ec_watchdog_mode_t watchdog_mode /** Watchdog mode. */
|
||||||
|
)
|
||||||
{
|
{
|
||||||
const ec_pdo_entry_reg_t *reg;
|
return 0;
|
||||||
ec_slave_config_t *sc;
|
}
|
||||||
int ret;
|
|
||||||
|
|
||||||
for (reg = pdo_entry_regs; reg->index; reg++)
|
int ecrt_slave_config_watchdog(
|
||||||
{
|
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||||
if (!(sc = ecrt_master_slave_config(
|
uint16_t watchdog_divider, /**< Number of 40 ns intervals (register
|
||||||
domain->getMaster(), reg->alias,
|
0x0400). Used as a base unit for all
|
||||||
reg->position, reg->vendor_id, reg->product_code)))
|
slave watchdogs^. If set to zero, the
|
||||||
return -ENOENT;
|
value is not written, so the default is
|
||||||
|
used. */
|
||||||
|
uint16_t watchdog_intervals /**< Number of base intervals for sync
|
||||||
|
manager watchdog (register 0x0420). If
|
||||||
|
set to zero, the value is not written,
|
||||||
|
so the default is used. */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((ret = ecrt_slave_config_reg_pdo_entry(
|
int ecrt_slave_config_pdo_assign_add(
|
||||||
sc, reg->index, reg->subindex, domain,
|
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||||
reg->bit_position)) < 0)
|
uint8_t sync_index, /**< Sync manager index. Must be less
|
||||||
return ret;
|
than #EC_MAX_SYNC_MANAGERS. */
|
||||||
|
uint16_t index /**< Index of the PDO to assign. */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto &syncManager = sc->sync_managers[sync_index];
|
||||||
|
syncManager.pdos[index];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
*reg->offset = ret;
|
int ecrt_slave_config_pdo_assign_clear(
|
||||||
|
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||||
|
uint8_t sync_index /**< Sync manager index. Must be less
|
||||||
|
than #EC_MAX_SYNC_MANAGERS. */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto &syncManager = sc->sync_managers[sync_index];
|
||||||
|
syncManager.pdos.clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecrt_slave_config_pdo_mapping_add(
|
||||||
|
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||||
|
uint16_t pdo_index, /**< Index of the PDO. */
|
||||||
|
uint16_t entry_index, /**< Index of the PDO entry to add to the PDO's
|
||||||
|
mapping. */
|
||||||
|
uint8_t entry_subindex, /**< Subindex of the PDO entry to add to the
|
||||||
|
PDO's mapping. */
|
||||||
|
uint8_t entry_bit_length /**< Size of the PDO entry in bit. */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto smIt = sc->sync_managers.begin();
|
||||||
|
smIt != sc->sync_managers.end();
|
||||||
|
++smIt) {
|
||||||
|
|
||||||
|
auto pdoIt = smIt->second.pdos.find(pdo_index);
|
||||||
|
if (pdoIt == smIt->second.pdos.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec_pdo_entry_info_t entry_info;
|
||||||
|
entry_info.index = entry_index;
|
||||||
|
entry_info.subindex = entry_subindex;
|
||||||
|
entry_info.bit_length = entry_bit_length;
|
||||||
|
pdoIt->second.entries.push_back(entry_info);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
std::cerr << __func__ << "(): PDO " << std::hex << pdo_index
|
||||||
|
<< " not found." << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecrt_slave_config_pdo_mapping_clear(
|
||||||
|
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||||
|
uint16_t pdo_index /**< Index of the PDO. */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto smIt = sc->sync_managers.begin();
|
||||||
|
smIt != sc->sync_managers.end();
|
||||||
|
++smIt) {
|
||||||
|
auto pdoIt = smIt->second.pdos.find(pdo_index);
|
||||||
|
if (pdoIt == smIt->second.pdos.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdoIt->second.entries.clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << __func__ << "(): PDO " << std::hex << pdo_index
|
||||||
|
<< " not found." << std::endl;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ecrt_slave_config_reg_pdo_entry(
|
int ecrt_slave_config_reg_pdo_entry(
|
||||||
|
|
@ -693,6 +662,161 @@ int ecrt_slave_config_sdo(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Domain
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int ecrt_domain_reg_pdo_entry_list(
|
||||||
|
ec_domain_t *domain, /**< Domain. */
|
||||||
|
const ec_pdo_entry_reg_t *pdo_entry_regs /**< Array of PDO
|
||||||
|
registrations. */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const ec_pdo_entry_reg_t *reg;
|
||||||
|
ec_slave_config_t *sc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (reg = pdo_entry_regs; reg->index; reg++)
|
||||||
|
{
|
||||||
|
if (!(sc = ecrt_master_slave_config(
|
||||||
|
domain->getMaster(), reg->alias,
|
||||||
|
reg->position, reg->vendor_id, reg->product_code)))
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if ((ret = ecrt_slave_config_reg_pdo_entry(
|
||||||
|
sc, reg->index, reg->subindex, domain,
|
||||||
|
reg->bit_position)) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*reg->offset = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *ecrt_domain_data(
|
||||||
|
const ec_domain_t *domain)
|
||||||
|
{
|
||||||
|
return domain->getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecrt_domain_process(
|
||||||
|
ec_domain_t *domain)
|
||||||
|
{
|
||||||
|
return domain->process();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecrt_domain_queue(
|
||||||
|
ec_domain_t *domain)
|
||||||
|
{
|
||||||
|
return domain->queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecrt_domain_state(
|
||||||
|
const ec_domain_t *domain, /**< Domain. */
|
||||||
|
ec_domain_state_t *state /**< Pointer to a state object to store the
|
||||||
|
information. */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
state->working_counter = domain->getNumSlaves();
|
||||||
|
state->redundancy_active = 0;
|
||||||
|
state->wc_state = EC_WC_COMPLETE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec_domain::ec_domain(rtipc *rtipc, const char *prefix, ec_master_t *master):
|
||||||
|
rt_group(rtipc_create_group(rtipc, 1.0)), prefix(prefix), master(master)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int ec_domain::activate()
|
||||||
|
{
|
||||||
|
std::unordered_set<uint32_t> slaves;
|
||||||
|
|
||||||
|
connected.resize(mapped_pdos.size());
|
||||||
|
size_t idx = 0;
|
||||||
|
for (const auto &pdo : mapped_pdos)
|
||||||
|
{
|
||||||
|
slaves.insert(pdo.slave_address.getCombined());
|
||||||
|
void *rt_pdo = nullptr;
|
||||||
|
char buf[512];
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pdo.dir)
|
||||||
|
{
|
||||||
|
case EC_DIR_OUTPUT:
|
||||||
|
rt_pdo = rtipc_txpdo(rt_group, buf, rtipc_uint8_T,
|
||||||
|
data.data() + pdo.offset, pdo.size_bytes);
|
||||||
|
std::cerr << "Registering " << buf << " as Output\n";
|
||||||
|
break;
|
||||||
|
case EC_DIR_INPUT:
|
||||||
|
rt_pdo = rtipc_rxpdo(rt_group, buf, rtipc_uint8_T,
|
||||||
|
data.data() + pdo.offset, pdo.size_bytes,
|
||||||
|
connected.data() + idx);
|
||||||
|
std::cerr << "Registering " << buf << " as Input\n";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cerr << "Unknown direction " << pdo.dir << '\n';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!rt_pdo)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to register RtIPC PDO\n";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
activated_ = true;
|
||||||
|
numSlaves = slaves.size();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ec_domain::process()
|
||||||
|
{
|
||||||
|
rtipc_rx(rt_group);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ec_domain::queue()
|
||||||
|
{
|
||||||
|
rtipc_tx(rt_group);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t ec_domain::map(ec_slave_config const &config,
|
||||||
|
unsigned int syncManager, uint16_t pdo_index)
|
||||||
|
{
|
||||||
|
if (activated_)
|
||||||
|
return -1;
|
||||||
|
for (const auto &pdo : mapped_pdos)
|
||||||
|
{
|
||||||
|
if (pdo.slave_address == config.address
|
||||||
|
&& syncManager == pdo.syncManager
|
||||||
|
&& pdo_index == pdo.pdo_index)
|
||||||
|
{
|
||||||
|
// already mapped;
|
||||||
|
return pdo.offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto ans = data.size();
|
||||||
|
const auto size =
|
||||||
|
config.sync_managers.at(syncManager).pdos.at(pdo_index).sizeInBytes();
|
||||||
|
mapped_pdos.emplace_back(ans, size, config.address, syncManager,
|
||||||
|
pdo_index, config.sync_managers.at(syncManager).dir);
|
||||||
|
data.resize(ans + size);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Helpers
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
void ecrt_write_lreal(void *data, double const value)
|
void ecrt_write_lreal(void *data, double const value)
|
||||||
{
|
{
|
||||||
memcpy(data, &value, sizeof(value));
|
memcpy(data, &value, sizeof(value));
|
||||||
|
|
@ -717,6 +841,8 @@ double ecrt_read_lreal(const void *data)
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
void ec_slave_config::dumpJson(std::ostream &out, int indent) const
|
void ec_slave_config::dumpJson(std::ostream &out, int indent) const
|
||||||
{
|
{
|
||||||
out << "{\n";
|
out << "{\n";
|
||||||
|
|
@ -741,3 +867,5 @@ void ec_slave_config::dumpJson(std::ostream &out, int indent) const
|
||||||
add_spaces(out, indent - 4);
|
add_spaces(out, indent - 4);
|
||||||
out << "}";
|
out << "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ struct pdo
|
||||||
struct syncManager
|
struct syncManager
|
||||||
{
|
{
|
||||||
ec_direction_t dir;
|
ec_direction_t dir;
|
||||||
std::map<uint16_t /* address */, pdo> pdos;
|
std::map<uint16_t /* index */, pdo> pdos;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ec_address
|
class ec_address
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue