merged
authorMartin Troxler <martin.troxler@komaxgroup.com>
Tue, 11 May 2010 13:57:58 +0200
changeset 1989 6aa393418fb3
parent 1988 ea38efeeb7b3 (diff)
parent 1927 365a90e93161 (current diff)
child 1990 b0dcdfbd4238
merged
master/cdev.c
master/domain.c
master/fmmu_config.c
master/fsm_master.c
master/fsm_slave_config.c
master/master.c
master/master.h
master/slave_config.c
master/slave_config.h
--- 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;