Added ecrt_slave_config_reg_so_entry_pos() to register non-unique entries. stable-1.5
authorFlorian Pose <fp@igh-essen.com>
Tue, 05 Feb 2013 16:45:34 +0100
branchstable-1.5
changeset 2505 5ef3197e5e1f
parent 2504 5ef9d5b14879
child 2506 ab9a6e109951
Added ecrt_slave_config_reg_so_entry_pos() to register non-unique entries.
include/ecrt.h
lib/slave_config.c
master/ioctl.c
master/ioctl.h
master/slave_config.c
--- a/include/ecrt.h	Tue Feb 05 15:24:45 2013 +0100
+++ b/include/ecrt.h	Tue Feb 05 16:45:34 2013 +0100
@@ -66,6 +66,9 @@
  *   clock to the reference clock.
  * - Changed the datatypes of the shift times in ecrt_slave_config_dc() to
  *   int32_t to correctly display negative shift times.
+ * - Added ecrt_slave_config_reg_pdo_entry_pos() and the feature flag
+ *   EC_HAVE_REG_BY_POS for registering PDO entries with non-unique indices
+ *   via their positions in the mapping.
  *
  * Changes in version 1.5:
  *
@@ -180,6 +183,10 @@
  */
 #define EC_HAVE_REF_CLOCK_TIME
 
+/* Defined if the method ecrt_slave_config_reg_pdo_entry_pos() is available.
+ */
+#define EC_HAVE_REG_BY_POS
+
 /*****************************************************************************/
 
 /** End of list marker.
@@ -1260,6 +1267,26 @@
                                  is desired */
         );
 
+/** Registers a PDO entry using its position.
+ *
+ * Similar to ecrt_slave_config_reg_pdo_entry(), but not using PDO indices but
+ * offsets in the PDO mapping, because PDO entry indices may not be unique
+ * inside a slave's PDO mapping. An error is raised, if
+ * one of the given positions is out of range.
+ *
+ * \retval >=0 Success: Offset of the PDO entry's process data.
+ * \retval  <0 Error code.
+ */
+int ecrt_slave_config_reg_pdo_entry_pos(
+        ec_slave_config_t *sc, /**< Slave configuration. */
+        uint8_t sync_index, /**< Sync manager index. */
+        unsigned int pdo_pos, /**< Position of the PDO inside the SM. */
+        unsigned int entry_pos, /**< Position of the entry inside the PDO. */
+        ec_domain_t *domain, /**< Domain. */
+        unsigned int *bit_position /**< Optional address if bit addressing
+                                 is desired */
+        );
+
 /** Configure distributed clocks.
  *
  * Sets the AssignActivate word and the cycle and shift times for the sync
--- a/lib/slave_config.c	Tue Feb 05 15:24:45 2013 +0100
+++ b/lib/slave_config.c	Tue Feb 05 16:45:34 2013 +0100
@@ -305,6 +305,47 @@
 
 /*****************************************************************************/
 
+int ecrt_slave_config_reg_pdo_entry_pos(
+        ec_slave_config_t *sc,
+        uint8_t sync_index,
+        unsigned int pdo_pos,
+        unsigned int entry_pos,
+        ec_domain_t *domain,
+        unsigned int *bit_position
+        )
+{
+    ec_ioctl_reg_pdo_pos_t io;
+    int ret;
+
+    io.config_index = sc->index;
+    io.sync_index = sync_index;
+    io.pdo_pos = pdo_pos;
+    io.entry_pos = entry_pos;
+    io.domain_index = domain->index;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_REG_PDO_POS, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to register PDO entry: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    if (bit_position) {
+        *bit_position = io.bit_position;
+    } else {
+        if (io.bit_position) {
+            fprintf(stderr, "PDO entry %u/%u/%u does not byte-align "
+                    "in config %u:%u.\n", sync_index, pdo_pos, entry_pos,
+                    sc->alias, sc->position);
+            return -EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/*****************************************************************************/
+
 void ecrt_slave_config_dc(ec_slave_config_t *sc, uint16_t assign_activate,
         uint32_t sync0_cycle_time, int32_t sync0_shift_time,
         uint32_t sync1_cycle_time, int32_t sync1_shift_time)
--- a/master/ioctl.c	Tue Feb 05 15:24:45 2013 +0100
+++ b/master/ioctl.c	Tue Feb 05 16:45:34 2013 +0100
@@ -2246,6 +2246,54 @@
 
 /*****************************************************************************/
 
+/** Registers a PDO entry by its position.
+ */
+static ATTRIBUTES int ec_ioctl_sc_reg_pdo_pos(
+        ec_master_t *master, /**< EtherCAT master. */
+        void *arg, /**< ioctl() argument. */
+        ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+        )
+{
+    ec_ioctl_reg_pdo_pos_t io;
+    ec_slave_config_t *sc;
+    ec_domain_t *domain;
+    int ret;
+
+    if (unlikely(!ctx->requested)) {
+        return -EPERM;
+    }
+
+    if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
+        return -EFAULT;
+    }
+
+    if (down_interruptible(&master->master_sem)) {
+        return -EINTR;
+    }
+
+    if (!(sc = ec_master_get_config(master, io.config_index))) {
+        up(&master->master_sem);
+        return -ENOENT;
+    }
+
+    if (!(domain = ec_master_find_domain(master, io.domain_index))) {
+        up(&master->master_sem);
+        return -ENOENT;
+    }
+
+    up(&master->master_sem); /** \fixme sc or domain could be invalidated */
+
+    ret = ecrt_slave_config_reg_pdo_entry_pos(sc, io.sync_index,
+            io.pdo_pos, io.entry_pos, domain, &io.bit_position);
+
+    if (copy_to_user((void __user *) arg, &io, sizeof(io)))
+        return -EFAULT;
+
+    return ret;
+}
+
+/*****************************************************************************/
+
 /** Sets the DC AssignActivate word and the sync signal times.
  */
 static ATTRIBUTES int ec_ioctl_sc_dc(
@@ -4149,6 +4197,13 @@
             }
             ret = ec_ioctl_sc_reg_pdo_entry(master, arg, ctx);
             break;
+        case EC_IOCTL_SC_REG_PDO_POS:
+            if (!ctx->writable) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_ioctl_sc_reg_pdo_pos(master, arg, ctx);
+            break;
         case EC_IOCTL_SC_DC:
             if (!ctx->writable) {
                 ret = -EPERM;
--- a/master/ioctl.h	Tue Feb 05 15:24:45 2013 +0100
+++ b/master/ioctl.h	Tue Feb 05 16:45:34 2013 +0100
@@ -56,7 +56,7 @@
  *
  * Increment this when changing the ioctl interface!
  */
-#define EC_IOCTL_VERSION_MAGIC 26
+#define EC_IOCTL_VERSION_MAGIC 27
 
 // Command-line tool
 #define EC_IOCTL_MODULE                EC_IOR(0x00, ec_ioctl_module_t)
@@ -117,40 +117,41 @@
 #define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x33, ec_ioctl_add_pdo_entry_t)
 #define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x34, ec_ioctl_config_pdo_t)
 #define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x35, ec_ioctl_reg_pdo_entry_t)
-#define EC_IOCTL_SC_DC                 EC_IOW(0x36, ec_ioctl_config_t)
-#define EC_IOCTL_SC_SDO                EC_IOW(0x37, ec_ioctl_sc_sdo_t)
-#define EC_IOCTL_SC_EMERG_SIZE         EC_IOW(0x38, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_POP         EC_IOWR(0x39, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_CLEAR        EC_IOW(0x3a, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_OVERRUNS    EC_IOWR(0x3b, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x3c, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SC_REG_REQUEST       EC_IOWR(0x3d, ec_ioctl_reg_request_t)
-#define EC_IOCTL_SC_VOE               EC_IOWR(0x3e, ec_ioctl_voe_t)
-#define EC_IOCTL_SC_STATE             EC_IOWR(0x3f, ec_ioctl_sc_state_t)
-#define EC_IOCTL_SC_IDN                EC_IOW(0x40, ec_ioctl_sc_idn_t)
-#define EC_IOCTL_DOMAIN_SIZE            EC_IO(0x41)
-#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x42)
-#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x43)
-#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x44)
-#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x45, ec_ioctl_domain_state_t)
-#define EC_IOCTL_SDO_REQUEST_INDEX    EC_IOWR(0x46, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x47, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x48, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x49, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_REG_REQUEST_DATA     EC_IOWR(0x4c, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_STATE    EC_IOWR(0x4d, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_WRITE    EC_IOWR(0x4e, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_READ     EC_IOWR(0x4f, ec_ioctl_reg_request_t)
-#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x50, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x51, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ              EC_IOW(0x52, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x53, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x54, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x55, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_DATA             EC_IOWR(0x56, ec_ioctl_voe_t)
-#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x57, size_t)
+#define EC_IOCTL_SC_REG_PDO_POS       EC_IOWR(0x36, ec_ioctl_reg_pdo_pos_t)
+#define EC_IOCTL_SC_DC                 EC_IOW(0x37, ec_ioctl_config_t)
+#define EC_IOCTL_SC_SDO                EC_IOW(0x38, ec_ioctl_sc_sdo_t)
+#define EC_IOCTL_SC_EMERG_SIZE         EC_IOW(0x39, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_POP         EC_IOWR(0x3a, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_CLEAR        EC_IOW(0x3b, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_OVERRUNS    EC_IOWR(0x3c, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x3d, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SC_REG_REQUEST       EC_IOWR(0x3e, ec_ioctl_reg_request_t)
+#define EC_IOCTL_SC_VOE               EC_IOWR(0x3f, ec_ioctl_voe_t)
+#define EC_IOCTL_SC_STATE             EC_IOWR(0x40, ec_ioctl_sc_state_t)
+#define EC_IOCTL_SC_IDN                EC_IOW(0x41, ec_ioctl_sc_idn_t)
+#define EC_IOCTL_DOMAIN_SIZE            EC_IO(0x42)
+#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x43)
+#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x44)
+#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x45)
+#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x46, ec_ioctl_domain_state_t)
+#define EC_IOCTL_SDO_REQUEST_INDEX    EC_IOWR(0x47, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x48, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x49, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_REG_REQUEST_DATA     EC_IOWR(0x4d, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_STATE    EC_IOWR(0x4e, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_WRITE    EC_IOWR(0x4f, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_READ     EC_IOWR(0x50, ec_ioctl_reg_request_t)
+#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x51, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x52, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ              EC_IOW(0x53, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x54, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x55, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x56, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_DATA             EC_IOWR(0x57, ec_ioctl_voe_t)
+#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x58, size_t)
 
 /*****************************************************************************/
 
@@ -623,6 +624,20 @@
 typedef struct {
     // inputs
     uint32_t config_index;
+    uint32_t sync_index;
+    uint32_t pdo_pos;
+    uint32_t entry_pos;
+    uint32_t domain_index;
+
+    // outputs
+    unsigned int bit_position;
+} ec_ioctl_reg_pdo_pos_t;
+
+/*****************************************************************************/
+
+typedef struct {
+    // inputs
+    uint32_t config_index;
     uint16_t index;
     uint8_t subindex;
     const uint8_t *data;
--- a/master/slave_config.c	Tue Feb 05 15:24:45 2013 +0100
+++ b/master/slave_config.c	Tue Feb 05 16:45:34 2013 +0100
@@ -781,6 +781,71 @@
 
 /*****************************************************************************/
 
+int ecrt_slave_config_reg_pdo_entry_pos(
+        ec_slave_config_t *sc,
+        uint8_t sync_index,
+        unsigned int pdo_pos,
+        unsigned int entry_pos,
+        ec_domain_t *domain,
+        unsigned int *bit_position
+        )
+{
+    const ec_sync_config_t *sync_config;
+    unsigned int bit_offset, pp, ep;
+    ec_pdo_t *pdo;
+    ec_pdo_entry_t *entry;
+
+    EC_CONFIG_DBG(sc, 1, "%s(sc = 0x%p, sync_index = %u, pdo_pos = %u,"
+            " entry_pos = %u, domain = 0x%p, bit_position = 0x%p)\n",
+            __func__, sc, sync_index, pdo_pos, entry_pos,
+            domain, bit_position);
+
+    if (sync_index >= EC_MAX_SYNC_MANAGERS) {
+        EC_CONFIG_ERR(sc, "Invalid syncmanager position %u.\n", sync_index);
+        return -EINVAL;
+    }
+
+    sync_config = &sc->sync_configs[sync_index];
+    bit_offset = 0;
+    pp = 0;
+
+    list_for_each_entry(pdo, &sync_config->pdos.list, list) {
+        ep = 0;
+        list_for_each_entry(entry, &pdo->entries, list) {
+            if (pp != pdo_pos || ep != entry_pos) {
+                bit_offset += entry->bit_length;
+            } else {
+                unsigned int bit_pos = bit_offset % 8;
+                int sync_offset;
+
+                if (bit_position) {
+                    *bit_position = bit_pos;
+                } else if (bit_pos) {
+                    EC_CONFIG_ERR(sc, "PDO entry 0x%04X:%02X does"
+                            " not byte-align.\n",
+                            pdo->index, entry->subindex);
+                    return -EFAULT;
+                }
+
+                sync_offset = ec_slave_config_prepare_fmmu(
+                        sc, domain, sync_index, sync_config->dir);
+                if (sync_offset < 0)
+                    return sync_offset;
+
+                return sync_offset + bit_offset / 8;
+            }
+            ep++;
+        }
+        pp++;
+    }
+
+    EC_CONFIG_ERR(sc, "PDO entry specification %u/%u/%u out of range.\n",
+           sync_index, pdo_pos, entry_pos);
+    return -ENOENT;
+}
+
+/*****************************************************************************/
+
 void ecrt_slave_config_dc(ec_slave_config_t *sc, uint16_t assign_activate,
         uint32_t sync0_cycle_time, int32_t sync0_shift_time,
         uint32_t sync1_cycle_time, int32_t sync1_shift_time)