--- a/include/ecrt.h Thu May 06 11:56:35 2010 +0200
+++ b/include/ecrt.h Tue May 11 13:57:58 2010 +0200
@@ -5,7 +5,7 @@
* Copyright (C) 2006-2008 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
@@ -19,9 +19,9 @@
* 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/>.
- *
+ *
* ---
- *
+ *
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
@@ -47,7 +47,7 @@
* ecrt_master_sync_slave_clocks() for offset and drift compensation. The
* EC_TIMEVAL2NANO() macro can be used for epoch time conversion, while the
* ecrt_master_sync_monitor_queue() and ecrt_master_sync_monitor_process()
- * methods can be used to monitor the synchrony.
+ * methods can be used to monitor the synchrony.
* - Improved the callback mechanism. ecrt_master_callbacks() now takes two
* callback functions for sending and receiving datagrams.
* ecrt_master_send_ext() is used to execute the sending of non-application
@@ -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.
+ *
*
* @{
*/
@@ -135,6 +138,9 @@
*/
#define EC_MAX_STRING_LENGTH 64
+/** Maximum number of slave ports. */
+#define EC_MAX_PORTS 4
+
/** Timeval to nanoseconds conversion.
*
* This macro converts a Unix epoch time to EtherCAT DC time.
@@ -147,7 +153,7 @@
(((TV).tv_sec - 946684800ULL) * 1000000000ULL + (TV).tv_usec * 1000ULL)
/******************************************************************************
- * Data types
+ * Data types
*****************************************************************************/
struct ec_master;
@@ -192,7 +198,7 @@
/** Slave configuration state.
*
* This is used as an output parameter of ecrt_slave_config_state().
- *
+ *
* \see ecrt_slave_config_state().
*/
typedef struct {
@@ -220,12 +226,33 @@
typedef struct {
unsigned int slave_count; /**< Number of slaves in the bus. */
unsigned int link_up : 1; /**< \a true, if the network link is up. */
- uint8_t scan_busy; /**< \a true, while the master is scanning the bus */
+ uint8_t scan_busy; /**< \a true, while the master is scanning the bus */
uint64_t app_time; /**< Application time. */
} ec_master_info_t;
/*****************************************************************************/
+/** EtherCAT slave port descriptor.
+ */
+typedef enum {
+ EC_PORT_NOT_IMPLEMENTED, /**< Port is not implemented. */
+ EC_PORT_NOT_CONFIGURED, /**< Port is not configured. */
+ EC_PORT_EBUS, /**< Port is an e-bus. */
+ EC_PORT_MII /**< Port is a mii. */
+} ec_slave_port_desc_t;
+
+/*****************************************************************************/
+
+/** EtherCAT slave port information.
+ */
+typedef struct {
+ uint8_t link_up; /**< Link detected. */
+ uint8_t loop_closed; /**< Loop closed. */
+ uint8_t signal_detected; /**< Detected signal on RX port. */
+} ec_slave_port_link_t;
+
+/*****************************************************************************/
+
/** Slave information.
*
* This is used as an output parameter of ecrt_master_get_slave().
@@ -240,6 +267,13 @@
uint32_t serial_number; /**< Serial-Number stored on the slave. */
uint16_t alias; /**< The slaves alias if not equal to 0. */
int16_t current_on_ebus; /**< Used current in mA. */
+ struct {
+ ec_slave_port_desc_t desc;
+ ec_slave_port_link_t link;
+ uint32_t receive_time;
+ uint16_t next_slave;
+ uint32_t delay_to_next_dc;
+ } ports[EC_MAX_PORTS];
uint8_t al_state; /**< Current state of the slave. */
uint8_t error_flag; /**< Error flag for that slave. */
uint8_t sync_count; /**< Number of sync managers. */
@@ -311,9 +345,9 @@
/*****************************************************************************/
/** PDO configuration information.
- *
+ *
* This is the data type of the \a pdos field in ec_sync_info_t.
- *
+ *
* \see ecrt_slave_config_pdos().
*/
typedef struct {
@@ -362,7 +396,7 @@
uint8_t subindex; /**< PDO entry subindex. */
unsigned int *offset; /**< Pointer to a variable to store the PDO entry's
(byte-)offset in the process data. */
- unsigned int *bit_position; /**< Pointer to a variable to store a bit
+ unsigned int *bit_position; /**< Pointer to a variable to store a bit
position (0-7) within the \a offset. Can be
NULL, in which case an error is raised if the
PDO entry does not byte-align. */
@@ -397,7 +431,7 @@
unsigned int ecrt_version_magic(void);
/** Requests an EtherCAT master for realtime operation.
- *
+ *
* Before an application can access an EtherCAT master, it has to reserve one
* for exclusive use.
*
@@ -788,17 +822,29 @@
ec_master_state_t *state /**< Structure to store the information. */
);
+/** Reads the current master state and the al_state of all configured slaves.
+ *
+ * use this function instead of ecrt_master_state if there are unused
+ * slaves on the bus
+ * Stores the master state information in the given \a state structure.
+ * \see ecrt_master_state()
+ */
+void ecrt_master_configured_slaves_state(
+ const ec_master_t *master, /**< EtherCAT master. */
+ ec_master_state_t *state /**< Structure to store the information. */
+ );
+
/** Sets the application time.
*
* The master has to know the application's time when operating slaves with
* distributed clocks. The time is not incremented by the master itself, so
* this method has to be called cyclically.
- *
+ *
* The time is used when setting the slaves' <tt>System Time Offset</tt> and
* <tt>Cyclic Operation Start Time</tt> registers and when synchronizing the
* DC reference clock to the application time via
* ecrt_master_sync_reference_clock().
- *
+ *
* The time is defined as nanoseconds from 2000-01-01 00:00. Converting an
* epoch time can be done with the EC_TIMEVAL2NANO() macro.
*/
@@ -879,6 +925,17 @@
*/
);
+/** 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()
@@ -896,7 +953,7 @@
* This can be called before assigning PDOs via
* ecrt_slave_config_pdo_assign_add(), to clear the default assignment of a
* sync manager.
- *
+ *
* \see ecrt_slave_config_pdos()
*/
void ecrt_slave_config_pdo_assign_clear(
@@ -950,28 +1007,28 @@
* {0x3101, 1, 8}, // status
* {0x3101, 2, 16} // value
* };
- *
+ *
* ec_pdo_entry_info_t el3162_channel2[] = {
* {0x3102, 1, 8}, // status
* {0x3102, 2, 16} // value
* };
- *
+ *
* ec_pdo_info_t el3162_pdos[] = {
* {0x1A00, 2, el3162_channel1},
* {0x1A01, 2, el3162_channel2}
* };
- *
+ *
* ec_sync_info_t el3162_syncs[] = {
* {2, EC_DIR_OUTPUT},
* {3, EC_DIR_INPUT, 2, el3162_pdos},
* {0xff}
* };
- *
+ *
* if (ecrt_slave_config_pdos(sc_ana_in, EC_END, el3162_syncs)) {
* // handle error
* }
* \endcode
- *
+ *
* The next example shows, how to configure the PDO assignment only. The
* entries for each assigned PDO are taken from the PDO's default mapping.
* Please note, that PDO entry registration will fail, if the PDO
@@ -982,11 +1039,11 @@
* {0x1600}, // Channel 1
* {0x1601} // Channel 2
* };
- *
+ *
* ec_sync_info_t syncs[] = {
* {3, EC_DIR_INPUT, 2, pdos},
* };
- *
+ *
* if (ecrt_slave_config_pdos(slave_config_ana_in, 1, syncs)) {
* // handle error
* }
@@ -1028,7 +1085,7 @@
uint16_t entry_index, /**< Index of the PDO entry to register. */
uint8_t entry_subindex, /**< Subindex of the PDO entry to register. */
ec_domain_t *domain, /**< Domain. */
- unsigned int *bit_position /**< Optional address if bit addressing
+ unsigned int *bit_position /**< Optional address if bit addressing
is desired */
);
--- a/lib/master.c Thu May 06 11:56:35 2010 +0200
+++ b/lib/master.c Tue May 11 13:57:58 2010 +0200
@@ -1,11 +1,11 @@
/******************************************************************************
- *
+ *
* $Id$
- *
+ *
* Copyright (C) 2006-2009 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
@@ -19,9 +19,9 @@
* 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/>.
- *
+ *
* ---
- *
+ *
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
@@ -63,12 +63,12 @@
fprintf(stderr, "Failed to allocate memory.\n");
return 0;
}
-
+
index = ioctl(master->fd, EC_IOCTL_CREATE_DOMAIN, NULL);
if (index == -1) {
fprintf(stderr, "Failed to create domain: %s\n", strerror(errno));
free(domain);
- return 0;
+ return 0;
}
domain->index = (unsigned int) index;
@@ -92,17 +92,17 @@
fprintf(stderr, "Failed to allocate memory.\n");
return 0;
}
-
+
data.alias = alias;
data.position = position;
data.vendor_id = vendor_id;
data.product_code = product_code;
-
+
if (ioctl(master->fd, EC_IOCTL_CREATE_SLAVE_CONFIG, &data) == -1) {
fprintf(stderr, "Failed to create slave config: %s\n",
strerror(errno));
free(sc);
- return 0;
+ return 0;
}
sc->master = master;
@@ -136,7 +136,7 @@
ec_slave_info_t *slave_info)
{
ec_ioctl_slave_t data;
- int index;
+ int index, i;
data.position = slave_position;
@@ -152,6 +152,15 @@
slave_info->serial_number = data.serial_number;
slave_info->alias = data.alias;
slave_info->current_on_ebus = data.current_on_ebus;
+ for ( i = 0; i < EC_MAX_PORTS; i++ ) {
+ slave_info->ports[i].desc = data.ports[i].desc;
+ slave_info->ports[i].link.link_up = data.ports[i].link.link_up;
+ slave_info->ports[i].link.loop_closed = data.ports[i].link.loop_closed;
+ slave_info->ports[i].link.signal_detected = data.ports[i].link.signal_detected;
+ slave_info->ports[i].receive_time = data.ports[i].receive_time;
+ slave_info->ports[i].next_slave = data.ports[i].next_slave;
+ slave_info->ports[i].delay_to_next_dc = data.ports[i].delay_to_next_dc;
+ }
slave_info->al_state = data.al_state;
slave_info->error_flag = data.error_flag;
slave_info->sync_count = data.sync_count;
@@ -372,7 +381,7 @@
}
// Access the mapped region to cause the initial page fault
- printf("pd: %x\n", master->process_data[0]);
+ memset(master->process_data, 0, master->process_data_size);
}
return 0;
@@ -432,6 +441,16 @@
/*****************************************************************************/
+void ecrt_master_configured_slaves_state(const ec_master_t *master,
+ ec_master_state_t *state)
+{
+ if (ioctl(master->fd, EC_IOCTL_MASTER_SC_STATE, state) == -1) {
+ fprintf(stderr, "Failed to get master state: %s\n", strerror(errno));
+ }
+}
+
+/*****************************************************************************/
+
void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
{
ec_ioctl_app_time_t data;
--- a/lib/slave_config.c Thu May 06 11:56:35 2010 +0200
+++ b/lib/slave_config.c Tue May 11 13:57:58 2010 +0200
@@ -87,6 +87,23 @@
/*****************************************************************************/
+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)
{
--- a/master/cdev.c Thu May 06 11:56:35 2010 +0200
+++ b/master/cdev.c Tue May 11 13:57:58 2010 +0200
@@ -539,6 +539,7 @@
}
data.data_size = domain->data_size;
+ data.tx_size = domain->tx_size;
data.logical_base_address = domain->logical_base_address;
data.working_counter = domain->working_counter;
data.expected_working_counter = domain->expected_working_counter;
@@ -592,6 +593,7 @@
data.sync_index = fmmu->sync_index;
data.dir = fmmu->dir;
data.logical_address = fmmu->logical_start_address;
+ data.domain_address = fmmu->domain_address;
data.data_size = fmmu->data_size;
up(&master->master_sem);
@@ -1814,6 +1816,29 @@
/*****************************************************************************/
+/** Get the master state of all configured slaves.
+ */
+int ec_cdev_ioctl_master_sc_state(
+ ec_master_t *master, /**< EtherCAT master. */
+ unsigned long arg, /**< ioctl() argument. */
+ ec_cdev_priv_t *priv /**< Private data structure of file handle. */
+ )
+{
+ ec_master_state_t data;
+
+ if (unlikely(!priv->requested))
+ return -EPERM;
+
+ ecrt_master_configured_slaves_state(master, &data);
+
+ if (copy_to_user((void __user *) arg, &data, sizeof(data)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
/** Get the master state.
*/
int ec_cdev_ioctl_app_time(
@@ -2011,6 +2036,50 @@
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.
@@ -3660,6 +3729,8 @@
return ec_cdev_ioctl_receive(master, arg, priv);
case EC_IOCTL_MASTER_STATE:
return ec_cdev_ioctl_master_state(master, arg, priv);
+ case EC_IOCTL_MASTER_SC_STATE:
+ return ec_cdev_ioctl_master_sc_state(master, arg, priv);
case EC_IOCTL_APP_TIME:
if (!(filp->f_mode & FMODE_WRITE))
return -EPERM;
@@ -3688,6 +3759,10 @@
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;
--- a/master/datagram.c Thu May 06 11:56:35 2010 +0200
+++ b/master/datagram.c Tue May 11 13:57:58 2010 +0200
@@ -94,6 +94,7 @@
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;
--- a/master/datagram.h Thu May 06 11:56:35 2010 +0200
+++ b/master/datagram.h Tue May 11 13:57:58 2010 +0200
@@ -94,6 +94,7 @@
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. */
--- a/master/domain.c Thu May 06 11:56:35 2010 +0200
+++ b/master/domain.c Tue May 11 13:57:58 2010 +0200
@@ -60,6 +60,7 @@
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 @@
fmmu->domain = domain;
domain->data_size += fmmu->data_size;
+ domain->tx_size += fmmu->tx_size;
list_add_tail(&fmmu->list, &domain->fmmu_configs);
EC_MASTER_DBG(domain->master, 1, "Domain %u:"
@@ -179,6 +181,7 @@
ec_datagram_zero(datagram);
list_add_tail(&datagram->list, &domain->datagrams);
+ datagram->domain = domain;
return 0;
}
@@ -238,6 +241,7 @@
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
@@ -249,7 +253,7 @@
// 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,
@@ -267,7 +271,7 @@
}
}
- datagram_size += fmmu->data_size;
+ datagram_size += fmmu->tx_size;
}
// Allocate last datagram, if data are left (this is also the case if the
--- a/master/domain.h Thu May 06 11:56:35 2010 +0200
+++ b/master/domain.h Tue May 11 13:57:58 2010 +0200
@@ -59,6 +59,7 @@
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
--- a/master/fmmu_config.c Thu May 06 11:56:35 2010 +0200
+++ b/master/fmmu_config.c Tue May 11 13:57:58 2010 +0200
@@ -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 @@
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.
@@ -79,9 +95,11 @@
uint8_t *data /**> Configuration page memory. */
)
{
- EC_CONFIG_DBG(fmmu->sc, 1, "FMMU: LogAddr 0x%08X, Size %3u,"
+ EC_CONFIG_DBG(fmmu->sc, 1, "FMMU: LogAddr 0x%08X, DomAddr 0x%08X,"
+ " Size %3u, Tx %3u"
" PhysAddr 0x%04X, SM%u, Dir %s\n",
- fmmu->logical_start_address, fmmu->data_size,
+ fmmu->logical_start_address, fmmu->domain_address,
+ fmmu->data_size, fmmu->data_size,
sync->physical_start_address, fmmu->sync_index,
fmmu->dir == EC_DIR_INPUT ? "in" : "out");
--- a/master/fmmu_config.h Thu May 06 11:56:35 2010 +0200
+++ b/master/fmmu_config.h Tue May 11 13:57:58 2010 +0200
@@ -50,13 +50,18 @@
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 *);
--- a/master/fsm_master.c Thu May 06 11:56:35 2010 +0200
+++ b/master/fsm_master.c Tue May 11 13:57:58 2010 +0200
@@ -890,25 +890,26 @@
ec_fsm_master_t *fsm, /**< Master state machine. */
u64 system_time, /**< System time register. */
u64 old_offset, /**< Time offset register. */
- unsigned long jiffies_since_read /**< Jiffies for correction. */
+ u64 correction /**< Correction. */
)
{
ec_slave_t *slave = fsm->slave;
- u32 correction, system_time32, old_offset32, new_offset;
+ u32 correction32, system_time32, old_offset32, new_offset;
s32 time_diff;
- system_time32 = (u32) system_time;
- old_offset32 = (u32) old_offset;
-
- // correct read system time by elapsed time since read operation
- correction = jiffies_since_read * 1000 / HZ * 1000000;
- system_time32 += correction;
+ system_time32 = (u32) system_time;
+ // correct read system time by elapsed time between read operation
+ // and app_time set time
+ correction32 = (u32)correction;
+ system_time32 -= correction32;
+ old_offset32 = (u32) old_offset;
+
time_diff = (u32) slave->master->app_time - system_time32;
EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:"
" system_time=%u (corrected with %u),"
" app_time=%u, diff=%i\n",
- system_time32, correction,
+ system_time32, correction32,
(u32) slave->master->app_time, time_diff);
if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) {
@@ -930,17 +931,17 @@
ec_fsm_master_t *fsm, /**< Master state machine. */
u64 system_time, /**< System time register. */
u64 old_offset, /**< Time offset register. */
- unsigned long jiffies_since_read /**< Jiffies for correction. */
+ u64 correction /**< Correction. */
)
{
ec_slave_t *slave = fsm->slave;
- u64 new_offset, correction;
+ u64 new_offset;
s64 time_diff;
- // correct read system time by elapsed time since read operation
- correction = (u64) (jiffies_since_read * 1000 / HZ) * 1000000;
- system_time += correction;
- time_diff = fsm->slave->master->app_time - system_time;
+ // correct read system time by elapsed time between read operation
+ // and app_time set time
+ system_time -= correction;
+ time_diff = fsm->slave->master->app_time - system_time;
EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:"
" system_time=%llu (corrected with %llu),"
@@ -970,8 +971,7 @@
{
ec_datagram_t *datagram = fsm->datagram;
ec_slave_t *slave = fsm->slave;
- u64 system_time, old_offset, new_offset;
- unsigned long jiffies_since_read;
+ u64 system_time, old_offset, new_offset, correction;
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
return;
@@ -994,14 +994,25 @@
system_time = EC_READ_U64(datagram->data); // 0x0910
old_offset = EC_READ_U64(datagram->data + 16); // 0x0920
- jiffies_since_read = jiffies - datagram->jiffies_sent;
+ /* correct read system time by elapsed time since read operation
+ and the app_time set time */
+#ifdef EC_HAVE_CYCLES
+ correction =
+ (datagram->cycles_sent - slave->master->dc_cycles_app_time)
+ * 1000000LL;
+ do_div(correction,cpu_khz);
+#else
+ correction =
+ (u64) ((datagram->jiffies_sent-slave->master->dc_jiffies_app_time) * 1000 / HZ)
+ * 1000000;
+#endif
if (slave->base_dc_range == EC_DC_32) {
new_offset = ec_fsm_master_dc_offset32(fsm,
- system_time, old_offset, jiffies_since_read);
+ system_time, old_offset, correction);
} else {
new_offset = ec_fsm_master_dc_offset64(fsm,
- system_time, old_offset, jiffies_since_read);
+ system_time, old_offset, correction);
}
// set DC system time offset and transmission delay
--- a/master/globals.h Thu May 06 11:56:35 2010 +0200
+++ b/master/globals.h Tue May 11 13:57:58 2010 +0200
@@ -97,9 +97,6 @@
/** Word offset of first SII category. */
#define EC_FIRST_SII_CATEGORY_OFFSET 0x40
-/** Maximum number of slave ports. */
-#define EC_MAX_PORTS 4
-
/** Size of a sync manager configuration page. */
#define EC_SYNC_PAGE_SIZE 8
@@ -173,23 +170,6 @@
uint8_t enable_not_lrw : 1; /**< Slave does not support LRW. */
} ec_sii_general_flags_t;
-/** EtherCAT slave port descriptor.
- */
-typedef enum {
- EC_PORT_NOT_IMPLEMENTED,
- EC_PORT_NOT_CONFIGURED,
- EC_PORT_EBUS,
- EC_PORT_MII
-} ec_slave_port_desc_t;
-
-/** EtherCAT slave port information.
- */
-typedef struct {
- uint8_t link_up; /**< Link detected. */
- uint8_t loop_closed; /**< Loop closed. */
- uint8_t signal_detected; /**< Detected signal on RX port. */
-} ec_slave_port_link_t;
-
/** EtherCAT slave distributed clocks range.
*/
typedef enum {
--- a/master/ioctl.h Thu May 06 11:56:35 2010 +0200
+++ b/master/ioctl.h Tue May 11 13:57:58 2010 +0200
@@ -56,7 +56,7 @@
*
* Increment this when changing the ioctl interface!
*/
-#define EC_IOCTL_VERSION_MAGIC 5
+#define EC_IOCTL_VERSION_MAGIC 6
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@@ -134,6 +134,8 @@
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x44, ec_ioctl_voe_t)
#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)
/*****************************************************************************/
@@ -275,6 +277,7 @@
// outputs
uint32_t data_size;
+ uint32_t tx_size;
uint32_t logical_base_address;
uint16_t working_counter;
uint16_t expected_working_counter;
@@ -294,6 +297,7 @@
uint8_t sync_index;
ec_direction_t dir;
uint32_t logical_address;
+ uint32_t domain_address;
uint32_t data_size;
} ec_ioctl_domain_fmmu_t;
@@ -454,6 +458,7 @@
} 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;
--- a/master/master.c Thu May 06 11:56:35 2010 +0200
+++ b/master/master.c Tue May 11 13:57:58 2010 +0200
@@ -145,10 +145,14 @@
master->slaves = NULL;
master->slave_count = 0;
-
+
INIT_LIST_HEAD(&master->configs);
master->app_time = 0ULL;
+#ifdef EC_HAVE_CYCLES
+ master->dc_cycles_app_time = 0;
+#endif
+ master->dc_jiffies_app_time = 0;
master->app_start_time = 0ULL;
master->has_app_time = 0;
@@ -846,7 +850,7 @@
{
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;
@@ -854,6 +858,7 @@
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();
@@ -902,7 +907,28 @@
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
@@ -972,8 +998,9 @@
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) {
@@ -1056,9 +1083,29 @@
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
@@ -2285,12 +2332,36 @@
/*****************************************************************************/
+void ecrt_master_configured_slaves_state(const ec_master_t *master, ec_master_state_t *state)
+{
+ const ec_slave_config_t *sc;
+ ec_slave_config_state_t sc_state;
+
+ // collect al_states of all configured online slaves
+ state->al_states = 0;
+ list_for_each_entry(sc, &master->configs, list) {
+ ecrt_slave_config_state(sc,&sc_state);
+ if (sc_state.online)
+ state->al_states |= sc_state.al_state;
+ }
+
+ state->slaves_responding = master->fsm.slaves_responding;
+ state->link_up = master->main_device.link_state;
+}
+
+/*****************************************************************************/
+
void ecrt_master_application_time(ec_master_t *master, uint64_t app_time)
{
master->app_time = app_time;
+#ifdef EC_HAVE_CYCLES
+ master->dc_cycles_app_time = get_cycles();
+#endif
+ master->dc_jiffies_app_time = jiffies;
if (unlikely(!master->has_app_time)) {
- master->app_start_time = app_time;
+ EC_MASTER_DBG(master, 1, "set application start time = %llu\n",app_time);
+ master->app_start_time = app_time;
master->has_app_time = 1;
}
}
--- a/master/master.h Thu May 06 11:56:35 2010 +0200
+++ b/master/master.h Tue May 11 13:57:58 2010 +0200
@@ -186,7 +186,11 @@
ec_datagram_t sync_mon_datagram; /**< Datagram used for DC synchronisation
monitoring. */
ec_slave_t *dc_ref_clock; /**< DC reference clock slave. */
-
+#ifdef EC_HAVE_CYCLES
+ cycles_t dc_cycles_app_time; /** cycles at last ecrt_master_sync() call.*/
+#endif
+ unsigned long dc_jiffies_app_time;/** jiffies at last
+ ecrt_master_sync() call.*/
unsigned int scan_busy; /**< Current scan state. */
unsigned int allow_scan; /**< \a True, if slave scanning is allowed. */
struct semaphore scan_sem; /**< Semaphore protecting the \a scan_busy
--- a/master/slave_config.c Thu May 06 11:56:35 2010 +0200
+++ b/master/slave_config.c Tue May 11 13:57:58 2010 +0200
@@ -70,7 +70,7 @@
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 @@
{
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) {
@@ -177,13 +180,25 @@
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;
}
/*****************************************************************************/
@@ -452,6 +467,18 @@
/*****************************************************************************/
+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)
{
@@ -975,6 +1002,7 @@
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);
--- a/master/slave_config.h Thu May 06 11:56:35 2010 +0200
+++ b/master/slave_config.h Tue May 11 13:57:58 2010 +0200
@@ -126,7 +126,8 @@
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. */
--- a/tool/CommandDomains.cpp Thu May 06 11:56:35 2010 +0200
+++ b/tool/CommandDomains.cpp Tue May 11 13:57:58 2010 +0200
@@ -143,6 +143,8 @@
<< setw(8) << domain.logical_base_address
<< ", Size " << dec << setfill(' ')
<< setw(3) << domain.data_size
+ << ", TxSize " << dec << setfill(' ')
+ << setw(3) << domain.tx_size
<< ", WorkingCounter "
<< domain.working_counter << "/"
<< domain.expected_working_counter << endl;
@@ -173,7 +175,7 @@
<< setw(8) << fmmu.logical_address
<< ", Size " << dec << fmmu.data_size << endl;
- dataOffset = fmmu.logical_address - domain.logical_base_address;
+ dataOffset = fmmu.domain_address - domain.logical_base_address;
if (dataOffset + fmmu.data_size > domain.data_size) {
stringstream err;
delete [] processData;