Inplace I/O: let input Pdos use the same bus space as Output Pdos
This commit is contained in:
parent
82ea99132c
commit
196bc7db4d
|
|
@ -78,6 +78,9 @@
|
|||
* - Added ecrt_slave_config_idn() method for storing SoE IDN configurations,
|
||||
* and ecrt_master_read_idn() and ecrt_master_write_idn() to read/write IDNs
|
||||
* ad-hoc via the user-space library.
|
||||
* - Added support for overlapping PDOs which allows inputs to use the same
|
||||
* space as outputs on the frame. This reduces the frame length.
|
||||
*
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
|
@ -891,6 +894,17 @@ void ecrt_slave_config_watchdog(
|
|||
*/
|
||||
);
|
||||
|
||||
/** Configure wether a slave allows overlapping PDOs.
|
||||
*
|
||||
* Overlapping PDOs allows inputs to use the same space as outputs on the frame.
|
||||
* This reduces the frame length.
|
||||
*/
|
||||
void ecrt_slave_config_overlapping_pdos(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
uint8_t allow_overlapping_pdos /**< Allow overlapping PDOs */
|
||||
);
|
||||
|
||||
|
||||
/** Add a PDO to a sync manager's PDO assignment.
|
||||
*
|
||||
* \see ecrt_slave_config_pdos()
|
||||
|
|
|
|||
|
|
@ -87,6 +87,23 @@ void ecrt_slave_config_watchdog(ec_slave_config_t *sc,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc,
|
||||
uint8_t allow_overlapping_pdos)
|
||||
{
|
||||
ec_ioctl_config_t data;
|
||||
|
||||
memset(&data, 0x00, sizeof(ec_ioctl_config_t));
|
||||
data.config_index = sc->index;
|
||||
data.allow_overlapping_pdos = allow_overlapping_pdos;
|
||||
|
||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_OVERLAPPING_IO, &data) == -1) {
|
||||
fprintf(stderr, "Failed to config overlapping PDOs: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
|
||||
uint8_t sync_index, uint16_t pdo_index)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2031,6 +2031,50 @@ out_return:
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Configure wether a slave allows overlapping PDOs.
|
||||
*/
|
||||
int ec_cdev_ioctl_sc_allow_overlapping_pdos(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
unsigned long arg, /**< ioctl() argument. */
|
||||
ec_cdev_priv_t *priv /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
ec_ioctl_config_t data;
|
||||
ec_slave_config_t *sc;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!priv->requested)) {
|
||||
ret = -EPERM;
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
|
||||
ret = -EFAULT;
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
if (down_interruptible(&master->master_sem)) {
|
||||
ret = -EINTR;
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
if (!(sc = ec_master_get_config(master, data.config_index))) {
|
||||
ret = -ENOENT;
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
ecrt_slave_config_overlapping_pdos(sc,
|
||||
data.allow_overlapping_pdos);
|
||||
|
||||
out_up:
|
||||
up(&master->master_sem);
|
||||
out_return:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Add a PDO to the assignment.
|
||||
|
|
@ -3725,6 +3769,10 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
return ec_cdev_ioctl_sc_watchdog(master, arg, priv);
|
||||
case EC_IOCTL_SC_OVERLAPPING_IO:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
return ec_cdev_ioctl_sc_allow_overlapping_pdos(master,arg,priv);
|
||||
case EC_IOCTL_SC_ADD_PDO:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram. */)
|
|||
datagram->data_origin = EC_ORIG_INTERNAL;
|
||||
datagram->mem_size = 0;
|
||||
datagram->data_size = 0;
|
||||
datagram->domain = NULL;
|
||||
datagram->index = 0x00;
|
||||
datagram->working_counter = 0x0000;
|
||||
datagram->state = EC_DATAGRAM_INIT;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ typedef struct {
|
|||
ec_origin_t data_origin; /**< Origin of the \a data memory. */
|
||||
size_t mem_size; /**< Datagram \a data memory size. */
|
||||
size_t data_size; /**< Size of the data in \a data. */
|
||||
ec_domain_t *domain; /**< Owning domain (may be null for non-domain datagrams) */
|
||||
uint8_t index; /**< Index (set by master). */
|
||||
uint16_t working_counter; /**< Working counter. */
|
||||
ec_datagram_state_t state; /**< State. */
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ void ec_domain_init(
|
|||
domain->index = index;
|
||||
INIT_LIST_HEAD(&domain->fmmu_configs);
|
||||
domain->data_size = 0;
|
||||
domain->tx_size = 0;
|
||||
domain->data = NULL;
|
||||
domain->data_origin = EC_ORIG_INTERNAL;
|
||||
domain->logical_base_address = 0x00000000;
|
||||
|
|
@ -113,6 +114,7 @@ void ec_domain_add_fmmu_config(
|
|||
fmmu->domain = domain;
|
||||
|
||||
domain->data_size += fmmu->data_size;
|
||||
domain->tx_size += fmmu->tx_size;
|
||||
list_add_tail(&fmmu->list, &domain->fmmu_configs);
|
||||
|
||||
if (domain->master->debug_level)
|
||||
|
|
@ -178,6 +180,7 @@ int ec_domain_add_datagram(
|
|||
|
||||
ec_datagram_zero(datagram);
|
||||
list_add_tail(&datagram->list, &domain->datagrams);
|
||||
datagram->domain = domain;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -236,6 +239,7 @@ int ec_domain_finish(
|
|||
list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
|
||||
// Correct logical FMMU address
|
||||
fmmu->logical_start_address += base_address;
|
||||
fmmu->domain_address += base_address;
|
||||
|
||||
// Increment Input/Output counter to determine datagram types
|
||||
// and calculate expected working counters
|
||||
|
|
@ -247,7 +251,7 @@ int ec_domain_finish(
|
|||
|
||||
// If the current FMMU's data do not fit in the current datagram,
|
||||
// allocate a new one.
|
||||
if (datagram_size + fmmu->data_size > EC_MAX_DATA_SIZE) {
|
||||
if (datagram_size + fmmu->tx_size > EC_MAX_DATA_SIZE) {
|
||||
ret = ec_domain_add_datagram(domain,
|
||||
domain->logical_base_address + datagram_offset,
|
||||
datagram_size, domain->data + datagram_offset,
|
||||
|
|
@ -265,7 +269,7 @@ int ec_domain_finish(
|
|||
}
|
||||
}
|
||||
|
||||
datagram_size += fmmu->data_size;
|
||||
datagram_size += fmmu->tx_size;
|
||||
}
|
||||
|
||||
// Allocate last datagram, if data are left (this is also the case if the
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ struct ec_domain
|
|||
|
||||
struct list_head fmmu_configs; /**< FMMU configurations contained. */
|
||||
size_t data_size; /**< Size of the process data. */
|
||||
size_t tx_size; /**< Size of the transmitted data. */
|
||||
uint8_t *data; /**< Memory for the process data. */
|
||||
ec_origin_t data_origin; /**< Origin of the \a data memory. */
|
||||
uint32_t logical_base_address; /**< Logical offset address of the
|
||||
|
|
|
|||
|
|
@ -43,14 +43,12 @@
|
|||
|
||||
/** FMMU configuration constructor.
|
||||
*
|
||||
* Inits an FMMU configuration, sets the logical start address and adds the
|
||||
* process data size for the mapped PDOs of the given direction to the domain
|
||||
* data size.
|
||||
* Inits an FMMU configuration and the process data size forthe mapped PDOs
|
||||
* of the given direction to the domain data size.
|
||||
*/
|
||||
void ec_fmmu_config_init(
|
||||
ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
|
||||
ec_slave_config_t *sc, /**< EtherCAT slave configuration. */
|
||||
ec_domain_t *domain, /**< EtherCAT domain. */
|
||||
uint8_t sync_index, /**< Sync manager index to use. */
|
||||
ec_direction_t dir /**< PDO direction. */
|
||||
)
|
||||
|
|
@ -59,14 +57,32 @@ void ec_fmmu_config_init(
|
|||
fmmu->sc = sc;
|
||||
fmmu->sync_index = sync_index;
|
||||
fmmu->dir = dir;
|
||||
|
||||
fmmu->logical_start_address = domain->data_size;
|
||||
fmmu->data_size = ec_pdo_list_total_size(
|
||||
&sc->sync_configs[sync_index].pdos);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Sets FMMU domain
|
||||
*
|
||||
* Sets the logical start address and the size of the transmitted data
|
||||
*/
|
||||
void ec_fmmu_config_domain(
|
||||
ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
|
||||
ec_domain_t *domain, /**< EtherCAT domain. */
|
||||
uint32_t logical_start_address, /**< FMMU logical start address. */
|
||||
size_t tx_size /**< Size of transmitted data */
|
||||
)
|
||||
{
|
||||
fmmu->domain = domain;
|
||||
fmmu->domain_address = domain->data_size;
|
||||
fmmu->logical_start_address = logical_start_address;
|
||||
fmmu->tx_size = tx_size;
|
||||
ec_domain_add_fmmu_config(domain, fmmu);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Initializes an FMMU configuration page.
|
||||
|
|
@ -80,9 +96,9 @@ void ec_fmmu_config_page(
|
|||
)
|
||||
{
|
||||
if (fmmu->sc->master->debug_level) {
|
||||
EC_DBG("FMMU: LogAddr 0x%08X, Size %3u, PhysAddr 0x%04X, SM%u, "
|
||||
"Dir %s\n", fmmu->logical_start_address, fmmu->data_size,
|
||||
sync->physical_start_address, fmmu->sync_index,
|
||||
EC_DBG("FMMU: LogAddr 0x%08X, DomAddr 0x%08X, Size %3u, Tx %3u, PhysAddr 0x%04X, SM%u, "
|
||||
"Dir %s\n", fmmu->logical_start_address, fmmu->domain_address, fmmu->data_size,
|
||||
fmmu->tx_size, sync->physical_start_address, fmmu->sync_index,
|
||||
fmmu->dir == EC_DIR_INPUT ? "in" : "out");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,13 +50,18 @@ typedef struct {
|
|||
uint8_t sync_index; /**< Index of sync manager to use. */
|
||||
ec_direction_t dir; /**< FMMU direction. */
|
||||
uint32_t logical_start_address; /**< Logical start address. */
|
||||
size_t tx_size; /**< Transmitted (bus) size. */
|
||||
uint32_t domain_address; /** Domain start address */
|
||||
unsigned int data_size; /**< Covered PDO size. */
|
||||
} ec_fmmu_config_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_fmmu_config_init(ec_fmmu_config_t *, ec_slave_config_t *,
|
||||
ec_domain_t *, uint8_t, ec_direction_t);
|
||||
uint8_t, ec_direction_t);
|
||||
|
||||
void ec_fmmu_config_domain(ec_fmmu_config_t *, ec_domain_t *,
|
||||
uint32_t , size_t);
|
||||
|
||||
void ec_fmmu_config_page(const ec_fmmu_config_t *, const ec_sync_t *,
|
||||
uint8_t *);
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@
|
|||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x45, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x46, size_t)
|
||||
#define EC_IOCTL_MASTER_SC_STATE EC_IOR(0x47, ec_master_state_t)
|
||||
#define EC_IOCTL_SC_OVERLAPPING_IO EC_IOW(0x48, ec_ioctl_config_t)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -455,6 +456,7 @@ typedef struct {
|
|||
} syncs[EC_MAX_SYNC_MANAGERS];
|
||||
uint16_t watchdog_divider;
|
||||
uint16_t watchdog_intervals;
|
||||
uint8_t allow_overlapping_pdos;
|
||||
uint32_t sdo_count;
|
||||
int32_t slave_position;
|
||||
uint16_t dc_assign_activate;
|
||||
|
|
|
|||
|
|
@ -902,7 +902,7 @@ void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
|||
{
|
||||
ec_datagram_t *datagram, *next;
|
||||
size_t datagram_size;
|
||||
uint8_t *frame_data, *cur_data;
|
||||
uint8_t *frame_data, *cur_data, *frame_datagram_data;
|
||||
void *follows_word;
|
||||
#ifdef EC_HAVE_CYCLES
|
||||
cycles_t cycles_start, cycles_sent, cycles_end;
|
||||
|
|
@ -910,6 +910,7 @@ void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
|||
unsigned long jiffies_sent;
|
||||
unsigned int frame_count, more_datagrams_waiting;
|
||||
struct list_head sent_datagrams;
|
||||
ec_fmmu_config_t* domain_fmmu;
|
||||
|
||||
#ifdef EC_HAVE_CYCLES
|
||||
cycles_start = get_cycles();
|
||||
|
|
@ -959,7 +960,28 @@ void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
|||
cur_data += EC_DATAGRAM_HEADER_SIZE;
|
||||
|
||||
// EtherCAT datagram data
|
||||
memcpy(cur_data, datagram->data, datagram->data_size);
|
||||
frame_datagram_data = cur_data;
|
||||
if (datagram->domain) {
|
||||
unsigned int datagram_address = EC_READ_U32(datagram->address);
|
||||
int i = 0;
|
||||
uint8_t *domain_data = datagram->data;
|
||||
list_for_each_entry(domain_fmmu, &datagram->domain->fmmu_configs, list) {
|
||||
if (domain_fmmu->dir == EC_DIR_OUTPUT ) {
|
||||
unsigned int frame_offset = domain_fmmu->logical_start_address-datagram_address;
|
||||
memcpy(frame_datagram_data+frame_offset, domain_data, domain_fmmu->data_size);
|
||||
if (unlikely(master->debug_level > 1)) {
|
||||
EC_DBG("sending dg 0x%02X fmmu %u fp=%u dp=%u size=%u\n",
|
||||
datagram->index, i,frame_offset,domain_data-datagram->data,domain_fmmu->data_size);
|
||||
ec_print_data(domain_data, domain_fmmu->data_size);
|
||||
}
|
||||
}
|
||||
domain_data += domain_fmmu->data_size;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
memcpy(frame_datagram_data, datagram->data, datagram->data_size);
|
||||
}
|
||||
cur_data += datagram->data_size;
|
||||
|
||||
// EtherCAT datagram footer
|
||||
|
|
@ -1031,8 +1053,9 @@ void ec_master_receive_datagrams(ec_master_t *master, /**< EtherCAT master */
|
|||
size_t frame_size, data_size;
|
||||
uint8_t datagram_type, datagram_index;
|
||||
unsigned int cmd_follows, matched;
|
||||
const uint8_t *cur_data;
|
||||
const uint8_t *cur_data, *frame_datagram_data;
|
||||
ec_datagram_t *datagram;
|
||||
ec_fmmu_config_t* domain_fmmu;
|
||||
|
||||
if (unlikely(size < EC_FRAME_HEADER_SIZE)) {
|
||||
if (master->debug_level) {
|
||||
|
|
@ -1113,9 +1136,29 @@ void ec_master_receive_datagrams(ec_master_t *master, /**< EtherCAT master */
|
|||
cur_data += data_size + EC_DATAGRAM_FOOTER_SIZE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy received data into the datagram memory
|
||||
memcpy(datagram->data, cur_data, data_size);
|
||||
frame_datagram_data = cur_data;
|
||||
if (datagram->domain) {
|
||||
size_t datagram_address = EC_READ_U32(datagram->address);
|
||||
int i = 0;
|
||||
uint8_t *domain_data = datagram->data;
|
||||
list_for_each_entry(domain_fmmu, &datagram->domain->fmmu_configs, list) {
|
||||
if (domain_fmmu->dir == EC_DIR_INPUT ) {
|
||||
unsigned int frame_offset = domain_fmmu->logical_start_address-datagram_address;
|
||||
memcpy(domain_data, frame_datagram_data+frame_offset, domain_fmmu->data_size);
|
||||
if (unlikely(master->debug_level > 1)) {
|
||||
EC_DBG("receiving dg 0x%02X fmmu %u fp=%u dp=%u size=%u\n",
|
||||
datagram->index, i,frame_offset,domain_data-datagram->data,domain_fmmu->data_size);
|
||||
ec_print_data(domain_data, domain_fmmu->data_size);
|
||||
}
|
||||
}
|
||||
domain_data += domain_fmmu->data_size;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// copy received data into the datagram memory
|
||||
memcpy(datagram->data, frame_datagram_data, data_size);
|
||||
}
|
||||
cur_data += data_size;
|
||||
|
||||
// set the datagram's working counter
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ void ec_slave_config_init(
|
|||
sc->product_code = product_code;
|
||||
sc->watchdog_divider = 0; // use default
|
||||
sc->watchdog_intervals = 0; // use default
|
||||
|
||||
sc->allow_overlapping_pdos = 0; // default not allowed
|
||||
sc->slave = NULL;
|
||||
|
||||
for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++)
|
||||
|
|
@ -164,12 +164,15 @@ int ec_slave_config_prepare_fmmu(
|
|||
{
|
||||
unsigned int i;
|
||||
ec_fmmu_config_t *fmmu;
|
||||
ec_fmmu_config_t *prev_fmmu;
|
||||
uint32_t fmmu_logical_start_address;
|
||||
size_t tx_size;
|
||||
|
||||
// FMMU configuration already prepared?
|
||||
for (i = 0; i < sc->used_fmmus; i++) {
|
||||
fmmu = &sc->fmmu_configs[i];
|
||||
if (fmmu->domain == domain && fmmu->sync_index == sync_index)
|
||||
return fmmu->logical_start_address;
|
||||
return fmmu->domain_address;
|
||||
}
|
||||
|
||||
if (sc->used_fmmus == EC_MAX_FMMUS) {
|
||||
|
|
@ -178,13 +181,25 @@ int ec_slave_config_prepare_fmmu(
|
|||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
fmmu = &sc->fmmu_configs[sc->used_fmmus++];
|
||||
fmmu = &sc->fmmu_configs[sc->used_fmmus];
|
||||
|
||||
down(&sc->master->master_sem);
|
||||
ec_fmmu_config_init(fmmu, sc, domain, sync_index, dir);
|
||||
ec_fmmu_config_init(fmmu, sc, sync_index, dir);
|
||||
fmmu_logical_start_address = domain->tx_size;
|
||||
tx_size = fmmu->data_size;
|
||||
if (sc->allow_overlapping_pdos && sc->used_fmmus > 0) {
|
||||
prev_fmmu = &sc->fmmu_configs[sc->used_fmmus-1];
|
||||
if (fmmu->dir != prev_fmmu->dir) {
|
||||
prev_fmmu->tx_size = max(fmmu->data_size,prev_fmmu->data_size);
|
||||
tx_size = 0;
|
||||
fmmu_logical_start_address = prev_fmmu->logical_start_address;
|
||||
}
|
||||
}
|
||||
ec_fmmu_config_domain(fmmu,domain,fmmu_logical_start_address,tx_size);
|
||||
up(&sc->master->master_sem);
|
||||
|
||||
return fmmu->logical_start_address;
|
||||
++sc->used_fmmus;
|
||||
return fmmu->domain_address;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -465,6 +480,18 @@ void ecrt_slave_config_watchdog(ec_slave_config_t *sc,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc,
|
||||
uint8_t allow_overlapping_pdos )
|
||||
{
|
||||
if (sc->master->debug_level)
|
||||
EC_DBG("%s(sc = 0x%p, allow_overlapping_pdos = %u)\n",
|
||||
__func__, sc, allow_overlapping_pdos);
|
||||
|
||||
sc->allow_overlapping_pdos = allow_overlapping_pdos;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
|
||||
uint8_t sync_index, uint16_t pdo_index)
|
||||
{
|
||||
|
|
@ -1005,6 +1032,7 @@ int ecrt_slave_config_idn(ec_slave_config_t *sc, uint16_t idn,
|
|||
|
||||
EXPORT_SYMBOL(ecrt_slave_config_sync_manager);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_watchdog);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_overlapping_pdos);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_add);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_clear);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_pdo_mapping_add);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ struct ec_slave_config {
|
|||
intervals (see spec. reg. 0x0400). */
|
||||
uint16_t watchdog_intervals; /**< Process data watchdog intervals (see
|
||||
spec. reg. 0x0420). */
|
||||
|
||||
uint8_t allow_overlapping_pdos; /**< Allow input PDOs use the same frame space
|
||||
as output PDOs. */
|
||||
ec_slave_t *slave; /**< Slave pointer. This is \a NULL, if the slave is
|
||||
offline. */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue