# HG changeset patch # User Florian Pose # Date 1360079134 -3600 # Node ID 5ef3197e5e1fe22553b63bb4c79aed8c95bf3fb2 # Parent 5ef9d5b14879dc895578f1708a65ed7f99b151a4 Added ecrt_slave_config_reg_so_entry_pos() to register non-unique entries. diff -r 5ef9d5b14879 -r 5ef3197e5e1f include/ecrt.h --- 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 diff -r 5ef9d5b14879 -r 5ef3197e5e1f lib/slave_config.c --- 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) diff -r 5ef9d5b14879 -r 5ef3197e5e1f master/ioctl.c --- 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; diff -r 5ef9d5b14879 -r 5ef3197e5e1f master/ioctl.h --- 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; diff -r 5ef9d5b14879 -r 5ef3197e5e1f master/slave_config.c --- 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)