Added ecrt_slave_config_reg_so_entry_pos() to register non-unique entries.
--- 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)