diff --git a/NEWS b/NEWS index 4d63bf83..960e9e9f 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,12 @@ Changes in version 1.3.0: * Realtime interface changes: - ecrt_master_run() became obsolete, because the master state machine is now run in process context. + - Parameter changes in PDO registration functions ecrt_domain_register_pdo() + and ecrt_register_pdo_range(): Replaced slave_address, vendor ID and + product code arguments with a slave pointer, which has to be optained with + a prior call to ecrt_master_get_slave(). + - ecrt_master_get_slave() got additional parameters to check for vendor ID + and product code. - Added ecrt_master_get_status() to get information about the bus. - Added functions to set up an alternative PDO mapping, i. e. ec_slave_pdo_mapping_clear(), ec_slave_pdo_mapping_add() and diff --git a/TODO b/TODO index 753603ae..998f1bdc 100644 --- a/TODO +++ b/TODO @@ -9,8 +9,6 @@ $Id$ * Release 1.3: - Remove addressing scheme "X:Y". - Remove ugly ec_slave_is_coupler(). - - Replace Vendor ID and product code arguments of ec_domain_register_pdo() - by slave pointer. - Reset topology_change_pending on successful validation. - Dynamic creation of EoE handlers. diff --git a/include/ecdb.h b/include/ecdb.h index f9261066..4c4b6a03 100644 --- a/include/ecdb.h +++ b/include/ecdb.h @@ -47,46 +47,87 @@ #define Beckhoff_BK1120 0x00000002, 0x04602C22 -#define Beckhoff_EL1004_Inputs 0x00000002, 0x03EC3052, 0x3101, 1 +#define Beckhoff_EL1004 0x00000002, 0x03EC3052 +#define Beckhoff_EL1004_PDO_Inputs 0x3101, 1 +#define Beckhoff_EL1004_Inputs Beckhoff_EL1004, Beckhoff_EL1004_PDO_Inputs -#define Beckhoff_EL1014_Inputs 0x00000002, 0x03F63052, 0x3101, 1 +#define Beckhoff_EL1014 0x00000002, 0x03F63052 +#define Beckhoff_EL1014_PDO_Inputs 0x3101, 1 +#define Beckhoff_EL1014_Inputs Beckhoff_EL1014, Beckhoff_EL1014_PDO_Inputs -#define Beckhoff_EL2004_Outputs 0x00000002, 0x07D43052, 0x3001, 1 +#define Beckhoff_EL2004 0x00000002, 0x07D43052 +#define Beckhoff_EL2004_PDO_Outputs 0x3001, 1 +#define Beckhoff_EL2004_Outputs Beckhoff_EL2004, Beckhoff_EL2004_PDO_Outputs -#define Beckhoff_EL2032_Outputs 0x00000002, 0x07F03052, 0x3001, 1 +#define Beckhoff_EL2032 0x00000002, 0x07F03052 +#define Beckhoff_EL2032_PDO_Outputs 0x3001, 1 +#define Beckhoff_EL2032_Outputs Beckhoff_EL2032, Beckhoff_EL2032_PDO_Outputs -#define Beckhoff_EL3102_Status1 0x00000002, 0x0C1E3052, 0x3101, 1 -#define Beckhoff_EL3102_Input1 0x00000002, 0x0C1E3052, 0x3101, 2 -#define Beckhoff_EL3102_Status2 0x00000002, 0x0C1E3052, 0x3102, 1 -#define Beckhoff_EL3102_Input2 0x00000002, 0x0C1E3052, 0x3102, 2 +#define Beckhoff_EL3102 0x00000002, 0x0C1E3052 +#define Beckhoff_EL3102_PDO_Status1 0x3101, 1 +#define Beckhoff_EL3102_PDO_Input1 0x3101, 2 +#define Beckhoff_EL3102_PDO_Status2 0x3102, 1 +#define Beckhoff_EL3102_PDO_Input2 0x3102, 2 +#define Beckhoff_EL3102_Status1 Beckhoff_EL3102, Beckhoff_EL3102_PDO_Status1 +#define Beckhoff_EL3102_Input1 Beckhoff_EL3102, Beckhoff_EL3102_PDO_Input1 +#define Beckhoff_EL3102_Status2 Beckhoff_EL3102, Beckhoff_EL3102_PDO_Status2 +#define Beckhoff_EL3102_Input2 Beckhoff_EL3102, Beckhoff_EL3102_PDO_Input2 -#define Beckhoff_EL3152_Status1 0x00000002, 0x0C503052, 0x3101, 1 -#define Beckhoff_EL3152_Input1 0x00000002, 0x0C503052, 0x3101, 2 -#define Beckhoff_EL3152_Status2 0x00000002, 0x0C503052, 0x3102, 1 -#define Beckhoff_EL3152_Input2 0x00000002, 0x0C503052, 0x3102, 2 +#define Beckhoff_EL3152 0x00000002, 0x0C503052 +#define Beckhoff_EL3152_PDO_Status1 0x3101, 1 +#define Beckhoff_EL3152_PDO_Input1 0x3101, 2 +#define Beckhoff_EL3152_PDO_Status2 0x3102, 1 +#define Beckhoff_EL3152_PDO_Input2 0x3102, 2 +#define Beckhoff_EL3152_Status1 Beckhoff_EL3152, Beckhoff_EL3152_PDO_Status1 +#define Beckhoff_EL3152_Input1 Beckhoff_EL3152, Beckhoff_EL3152_PDO_Input1 +#define Beckhoff_EL3152_Status2 Beckhoff_EL3152, Beckhoff_EL3152_PDO_Status2 +#define Beckhoff_EL3152_Input2 Beckhoff_EL3152, Beckhoff_EL3152_PDO_Input2 -#define Beckhoff_EL3162_Status1 0x00000002, 0x0C5A3052, 0x3101, 1 -#define Beckhoff_EL3162_Input1 0x00000002, 0x0C5A3052, 0x3101, 2 -#define Beckhoff_EL3162_Status2 0x00000002, 0x0C5A3052, 0x3102, 1 -#define Beckhoff_EL3162_Input2 0x00000002, 0x0C5A3052, 0x3102, 2 +#define Beckhoff_EL3162 0x00000002, 0x0C5A3052 +#define Beckhoff_EL3162_PDO_Status1 0x3101, 1 +#define Beckhoff_EL3162_PDO_Input1 0x3101, 2 +#define Beckhoff_EL3162_PDO_Status2 0x3102, 1 +#define Beckhoff_EL3162_PDO_Input2 0x3102, 2 +#define Beckhoff_EL3162_Status1 Beckhoff_EL3162, Beckhoff_EL3162_PDO_Status1 +#define Beckhoff_EL3162_Input1 Beckhoff_EL3162, Beckhoff_EL3162_PDO_Input1 +#define Beckhoff_EL3162_Status2 Beckhoff_EL3162, Beckhoff_EL3162_PDO_Status2 +#define Beckhoff_EL3162_Input2 Beckhoff_EL3162, Beckhoff_EL3162_PDO_Input2 -#define Beckhoff_EL4102_Output1 0x00000002, 0x10063052, 0x6411, 1 -#define Beckhoff_EL4102_Output2 0x00000002, 0x10063052, 0x6411, 2 +#define Beckhoff_EL4102 0x00000002, 0x10063052 +#define Beckhoff_EL4102_PDO_Output1 0x6411, 1 +#define Beckhoff_EL4102_PDO_Output2 0x6411, 2 +#define Beckhoff_EL4102_Output1 Beckhoff_EL4102, Beckhoff_EL4102_PDO_Output1 +#define Beckhoff_EL4102_Output2 Beckhoff_EL4102, Beckhoff_EL4102_PDO_Output2 -#define Beckhoff_EL4132_Output1 0x00000002, 0x10243052, 0x6411, 1 -#define Beckhoff_EL4132_Output2 0x00000002, 0x10243052, 0x6411, 2 +#define Beckhoff_EL4132 0x00000002, 0x10243052 +#define Beckhoff_EL4132_PDO_Output1 0x6411, 1 +#define Beckhoff_EL4132_PDO_Output2 0x6411, 2 +#define Beckhoff_EL4132_Output1 Beckhoff_EL4132, Beckhoff_EL4132_PDO_Output1 +#define Beckhoff_EL4132_Output2 Beckhoff_EL4132, Beckhoff_EL4132_PDO_Output2 -#define Beckhoff_EL5001_Status 0x00000002, 0x13893052, 0x3101, 1 -#define Beckhoff_EL5001_Value 0x00000002, 0x13893052, 0x3101, 2 +#define Beckhoff_EL5001 0x00000002, 0x13893052 +#define Beckhoff_EL5001_PDO_Status 0x3101, 1 +#define Beckhoff_EL5001_PDO_Value 0x3101, 2 +#define Beckhoff_EL5001_Status Beckhoff_EL5001, Beckhoff_EL5001_PDO_Status +#define Beckhoff_EL5001_Value Beckhoff_EL5001, Beckhoff_EL5001_PDO_Value -#define Beckhoff_EL5101_Status 0x00000002, 0x13ED3052, 0x6000, 1 -#define Beckhoff_EL5101_Value 0x00000002, 0x13ED3052, 0x6000, 2 -#define Beckhoff_EL5101_Latch 0x00000002, 0x13ED3052, 0x6000, 3 -#define Beckhoff_EL5101_Frequency 0x00000002, 0x13ED3052, 0x6000, 4 -#define Beckhoff_EL5101_Period 0x00000002, 0x13ED3052, 0x6000, 5 -#define Beckhoff_EL5101_Window 0x00000002, 0x13ED3052, 0x6000, 6 -#define Beckhoff_EL5101_Ctrl 0x00000002, 0x13ED3052, 0x7000, 1 -#define Beckhoff_EL5101_OutputValue 0x00000002, 0x13ED3052, 0x7000, 2 +#define Beckhoff_EL5101 0x00000002, 0x13ED3052 +#define Beckhoff_EL5101_PDO_Status 0x6000, 1 +#define Beckhoff_EL5101_PDO_Value 0x6000, 2 +#define Beckhoff_EL5101_PDO_Latch 0x6000, 3 +#define Beckhoff_EL5101_PDO_Frequency 0x6000, 4 +#define Beckhoff_EL5101_PDO_Period 0x6000, 5 +#define Beckhoff_EL5101_PDO_Window 0x6000, 6 +#define Beckhoff_EL5101_PDO_Ctrl 0x7000, 1 +#define Beckhoff_EL5101_PDO_OutputValue 0x7000, 2 +#define Beckhoff_EL5101_Status Beckhoff_EL5101, Beckhoff_EL5101_PDO_Status +#define Beckhoff_EL5101_Value Beckhoff_EL5101, Beckhoff_EL5101_PDO_Value +#define Beckhoff_EL5101_Latch Beckhoff_EL5101, Beckhoff_EL5101_PDO_Latch +#define Beckhoff_EL5101_Frequency Beckhoff_EL5101, Beckhoff_EL5101_PDO_Frequency +#define Beckhoff_EL5101_Period Beckhoff_EL5101, Beckhoff_EL5101_PDO_Period +#define Beckhoff_EL5101_Window Beckhoff_EL5101, Beckhoff_EL5101_PDO_Window +#define Beckhoff_EL5101_Ctrl Beckhoff_EL5101, Beckhoff_EL5101_PDO_Ctrl +#define Beckhoff_EL5101_OutputValue Beckhoff_EL5101, Beckhoff_EL5101_PDO_OutputValue /** \endcond */ diff --git a/include/ecrt.h b/include/ecrt.h index a7bc0732..57829301 100644 --- a/include/ecrt.h +++ b/include/ecrt.h @@ -81,9 +81,10 @@ typedef struct ec_slave ec_slave_t; /**< \see ec_slave */ */ typedef enum { - EC_BUS_FAILURE, // some slaves offline - EC_BUS_OK, // all slaves online - EC_BUS_REDUNDANCY // bus interrupted, but redundancy active + EC_BUS_FAILURE = -1, /**< At least one slave with process data exchange + is offline. */ + EC_BUS_OK /**< All slaves with process data exchange are + online. */ } ec_bus_status_t; @@ -93,22 +94,21 @@ ec_bus_status_t; */ typedef struct { - ec_bus_status_t bus_status; - unsigned int bus_tainted; - unsigned int slaves_responding; + ec_bus_status_t bus_status; /**< \see ec_bus_status_t */ + unsigned int bus_tainted; /**< non-zero, if the bus topology is invalid */ + unsigned int slaves_responding; /**< number of responging slaves */ } ec_master_status_t; /** - Initialization type for PDO registrations. - This type is used as a parameter for the ecrt_domain_register_pdo_list() - function. -*/ + * List entry for domain PDO registrations. + * This type is used as a parameter for the ecrt_domain_register_pdo_list() + * convenience function. + */ -typedef struct -{ - const char *slave_address; /**< slave address string (see - ecrt_master_get_slave()) */ +typedef struct { + const char *slave_address; /**< slave address string + \see ec_master_parse_slave_address() */ uint32_t vendor_id; /**< vendor ID */ uint32_t product_code; /**< product code */ uint16_t pdo_entry_index; /**< PDO entry index */ @@ -118,17 +118,17 @@ typedef struct ec_pdo_reg_t; /** - Direction type for ecrt_domain_register_pdo_range() -*/ + * Direction type for PDO mapping and range registration functions. + */ typedef enum { - EC_DIR_OUTPUT, - EC_DIR_INPUT + EC_DIR_OUTPUT, /**< values written by master */ + EC_DIR_INPUT /**< values read by master */ } ec_direction_t; /****************************************************************************** - * Master request functions + * Global functions *****************************************************************************/ ec_master_t *ecrt_request_master(unsigned int master_index); @@ -145,41 +145,33 @@ void ecrt_master_callbacks(ec_master_t *master, int (*request_cb)(void *), ec_domain_t *ecrt_master_create_domain(ec_master_t *master); +ec_slave_t *ecrt_master_get_slave(const ec_master_t *, const char *, + uint32_t vendor_id, uint32_t product_code); + int ecrt_master_activate(ec_master_t *master); void ecrt_master_send(ec_master_t *master); void ecrt_master_receive(ec_master_t *master); -ec_slave_t *ecrt_master_get_slave(const ec_master_t *, const char *); - void ecrt_master_get_status(const ec_master_t *master, ec_master_status_t *); /****************************************************************************** * Domain Methods *****************************************************************************/ -ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain, - const char *address, - uint32_t vendor_id, - uint32_t product_code, - uint16_t pdo_index, - uint8_t pdo_subindex, - void **data_ptr); +int ecrt_domain_register_pdo(ec_domain_t *domain, ec_slave_t *slave, + uint16_t pdo_index, uint8_t pdo_subindex, void **data_ptr); + +int ecrt_domain_register_pdo_range(ec_domain_t *domain, ec_slave_t *slave, + ec_direction_t direction, uint16_t offset, uint16_t length, + void **data_ptr); int ecrt_domain_register_pdo_list(ec_domain_t *domain, - const ec_pdo_reg_t *pdos); - -ec_slave_t *ecrt_domain_register_pdo_range(ec_domain_t *domain, - const char *address, - uint32_t vendor_id, - uint32_t product_code, - ec_direction_t direction, - uint16_t offset, - uint16_t length, - void **data_ptr); + const ec_pdo_reg_t *pdos); void ecrt_domain_process(ec_domain_t *domain); void ecrt_domain_queue(ec_domain_t *domain); + int ecrt_domain_state(const ec_domain_t *domain); /****************************************************************************** @@ -202,19 +194,19 @@ int ecrt_slave_pdo_mapping(ec_slave_t *, ec_direction_t, unsigned int, ...); *****************************************************************************/ /** - Read a certain bit of an EtherCAT data byte. - \param DATA EtherCAT data pointer - \param POS bit position -*/ + * Read a certain bit of an EtherCAT data byte. + * \param DATA EtherCAT data pointer + * \param POS bit position + */ #define EC_READ_BIT(DATA, POS) ((*((uint8_t *) (DATA)) >> (POS)) & 0x01) /** - Write a certain bit of an EtherCAT data byte. - \param DATA EtherCAT data pointer - \param POS bit position - \param VAL new bit value -*/ + * Write a certain bit of an EtherCAT data byte. + * \param DATA EtherCAT data pointer + * \param POS bit position + * \param VAL new bit value + */ #define EC_WRITE_BIT(DATA, POS, VAL) \ do { \ @@ -227,68 +219,67 @@ int ecrt_slave_pdo_mapping(ec_slave_t *, ec_direction_t, unsigned int, ...); *****************************************************************************/ /** - Read an 8-bit unsigned value from EtherCAT data. - \return EtherCAT data value -*/ + * Read an 8-bit unsigned value from EtherCAT data. + * \return EtherCAT data value + */ #define EC_READ_U8(DATA) \ ((uint8_t) *((uint8_t *) (DATA))) /** - Read an 8-bit signed value from EtherCAT data. - \param DATA EtherCAT data pointer - \return EtherCAT data value -*/ + * Read an 8-bit signed value from EtherCAT data. + * \param DATA EtherCAT data pointer + * \return EtherCAT data value + */ #define EC_READ_S8(DATA) \ ((int8_t) *((uint8_t *) (DATA))) /** - Read a 16-bit unsigned value from EtherCAT data. - \param DATA EtherCAT data pointer - \return EtherCAT data value -*/ + * Read a 16-bit unsigned value from EtherCAT data. + * \param DATA EtherCAT data pointer + * \return EtherCAT data value + */ #define EC_READ_U16(DATA) \ ((uint16_t) le16_to_cpup((void *) (DATA))) /** - Read a 16-bit signed value from EtherCAT data. - \param DATA EtherCAT data pointer - \return EtherCAT data value -*/ + * Read a 16-bit signed value from EtherCAT data. + * \param DATA EtherCAT data pointer + * \return EtherCAT data value + */ #define EC_READ_S16(DATA) \ ((int16_t) le16_to_cpup((void *) (DATA))) /** - Read a 32-bit unsigned value from EtherCAT data. - \param DATA EtherCAT data pointer - \return EtherCAT data value -*/ + * Read a 32-bit unsigned value from EtherCAT data. + * \param DATA EtherCAT data pointer + * \return EtherCAT data value + */ #define EC_READ_U32(DATA) \ ((uint32_t) le32_to_cpup((void *) (DATA))) /** - Read a 32-bit signed value from EtherCAT data. - \param DATA EtherCAT data pointer - \return EtherCAT data value -*/ + * Read a 32-bit signed value from EtherCAT data. + * \param DATA EtherCAT data pointer + * \return EtherCAT data value + */ #define EC_READ_S32(DATA) \ ((int32_t) le32_to_cpup((void *) (DATA))) - /****************************************************************************** * Write macros *****************************************************************************/ /** - Write an 8-bit unsigned value to EtherCAT data. - \param DATA EtherCAT data pointer - \param VAL new value -*/ + * Write an 8-bit unsigned value to EtherCAT data. + * \param DATA EtherCAT data pointer + * \param VAL new value + */ #define EC_WRITE_U8(DATA, VAL) \ do { \ @@ -296,18 +287,18 @@ int ecrt_slave_pdo_mapping(ec_slave_t *, ec_direction_t, unsigned int, ...); } while (0) /** - Write an 8-bit signed value to EtherCAT data. - \param DATA EtherCAT data pointer - \param VAL new value -*/ + * Write an 8-bit signed value to EtherCAT data. + * \param DATA EtherCAT data pointer + * \param VAL new value + */ #define EC_WRITE_S8(DATA, VAL) EC_WRITE_U8(DATA, VAL) /** - Write a 16-bit unsigned value to EtherCAT data. - \param DATA EtherCAT data pointer - \param VAL new value -*/ + * Write a 16-bit unsigned value to EtherCAT data. + * \param DATA EtherCAT data pointer + * \param VAL new value + */ #define EC_WRITE_U16(DATA, VAL) \ do { \ @@ -316,18 +307,18 @@ int ecrt_slave_pdo_mapping(ec_slave_t *, ec_direction_t, unsigned int, ...); } while (0) /** - Write a 16-bit signed value to EtherCAT data. - \param DATA EtherCAT data pointer - \param VAL new value -*/ + * Write a 16-bit signed value to EtherCAT data. + * \param DATA EtherCAT data pointer + * \param VAL new value + */ #define EC_WRITE_S16(DATA, VAL) EC_WRITE_U16(DATA, VAL) /** - Write a 32-bit unsigned value to EtherCAT data. - \param DATA EtherCAT data pointer - \param VAL new value -*/ + * Write a 32-bit unsigned value to EtherCAT data. + * \param DATA EtherCAT data pointer + * \param VAL new value + */ #define EC_WRITE_U32(DATA, VAL) \ do { \ @@ -336,10 +327,10 @@ int ecrt_slave_pdo_mapping(ec_slave_t *, ec_direction_t, unsigned int, ...); } while (0) /** - Write a 32-bit signed value to EtherCAT data. - \param DATA EtherCAT data pointer - \param VAL new value -*/ + * Write a 32-bit signed value to EtherCAT data. + * \param DATA EtherCAT data pointer + * \param VAL new value + */ #define EC_WRITE_S32(DATA, VAL) EC_WRITE_U32(DATA, VAL) diff --git a/master/domain.c b/master/domain.c index 37bebfce..2eeaa768 100644 --- a/master/domain.c +++ b/master/domain.c @@ -235,64 +235,6 @@ int ec_domain_reg_pdo_entry( /*****************************************************************************/ -/** - Registeres a PDO range. - \return 0 in case of success, else < 0 -*/ - -int ec_domain_reg_pdo_range(ec_domain_t *domain, /**< EtherCAT domain */ - ec_slave_t *slave, /**< slave */ - ec_direction_t dir, /**< data direction */ - uint16_t offset, /**< offset */ - uint16_t length, /**< length */ - void **data_ptr /**< pointer to the process data - pointer */ - ) -{ - ec_data_reg_t *data_reg; - ec_sync_t *sync; - uint16_t sync_length; - - if (!(sync = ec_slave_get_pdo_sync(slave, dir))) { - EC_ERR("No sync manager found for PDO range.\n"); - return -1; - } - - // Allocate memory for data registration object - if (!(data_reg = - (ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) { - EC_ERR("Failed to allocate data registration.\n"); - return -1; - } - - if (ec_slave_prepare_fmmu(slave, domain, sync)) { - EC_ERR("FMMU configuration failed.\n"); - kfree(data_reg); - return -1; - } - - data_reg->slave = slave; - data_reg->sync = sync; - data_reg->sync_offset = offset; - data_reg->data_ptr = data_ptr; - - // estimate sync manager length - sync_length = offset + length; - if (sync->est_length < sync_length) { - sync->est_length = sync_length; - if (domain->master->debug_level) { - EC_DBG("Estimating length of sync manager %i of slave %i to %i.\n", - sync->index, slave->ring_position, sync_length); - } - } - - list_add_tail(&data_reg->list, &domain->data_regs); - - return 0; -} - -/*****************************************************************************/ - /** Clears the list of the data registrations. */ @@ -460,53 +402,44 @@ ssize_t ec_show_domain_attribute(struct kobject *kobj, /**< kobject */ /** * Registers a PDO for a domain. - * \return pointer to the slave on success, else NULL + * \return 0 on success, else non-zero * \ingroup RealtimeInterface */ -ec_slave_t *ecrt_domain_register_pdo( +int ecrt_domain_register_pdo( ec_domain_t *domain, /**< EtherCAT domain */ - const char *address, /**< ASCII address of the slave, - see ecrt_master_get_slave() */ - uint32_t vendor_id, /**< vendor ID */ - uint32_t product_code, /**< product code */ - uint16_t entry_index, /**< PDO entry index */ - uint8_t entry_subindex, /**< PDO entry subindex */ + ec_slave_t *slave, /**< EtherCAT slave */ + uint16_t pdo_entry_index, /**< PDO entry index */ + uint8_t pdo_entry_subindex, /**< PDO entry subindex */ void **data_ptr /**< address of the process data pointer */ ) { - ec_slave_t *slave; - ec_master_t *master; ec_sync_t *sync; const ec_pdo_t *pdo; const ec_pdo_entry_t *entry; unsigned int i; - master = domain->master; - - // translate address and validate slave - if (!(slave = ecrt_master_get_slave(master, address))) return NULL; - if (ec_slave_validate(slave, vendor_id, product_code)) return NULL; - + // search for PDO entry for (i = 0; i < slave->sii_sync_count; i++) { sync = &slave->sii_syncs[i]; list_for_each_entry(pdo, &sync->pdos, list) { list_for_each_entry(entry, &pdo->entries, list) { - if (entry->index != entry_index || - entry->subindex != entry_subindex) continue; + if (entry->index != pdo_entry_index || + entry->subindex != pdo_entry_subindex) continue; + // PDO entry found if (ec_domain_reg_pdo_entry(domain, sync, entry, data_ptr)) { - return NULL; + return -1; } - return slave; + return 0; } } } EC_ERR("PDO entry 0x%04X:%u is not mapped in slave %u.\n", - entry_index, entry_subindex, slave->ring_position); - return NULL; + pdo_entry_index, pdo_entry_subindex, slave->ring_position); + return -1; } /*****************************************************************************/ @@ -520,64 +453,82 @@ ec_slave_t *ecrt_domain_register_pdo( int ecrt_domain_register_pdo_list( ec_domain_t *domain, /**< EtherCAT domain */ - const ec_pdo_reg_t *pdos /**< array of PDO registrations */ + const ec_pdo_reg_t *pdo_regs /**< array of PDO registrations */ ) { - const ec_pdo_reg_t *pdo; - - for (pdo = pdos; pdo->slave_address; pdo++) - if (!ecrt_domain_register_pdo(domain, pdo->slave_address, - pdo->vendor_id, pdo->product_code, - pdo->pdo_entry_index, pdo->pdo_entry_subindex, - pdo->data_ptr)) + const ec_pdo_reg_t *reg; + ec_slave_t *slave; + + for (reg = pdo_regs; reg->slave_address; reg++) { + if (!(slave = ecrt_master_get_slave(domain->master, + reg->slave_address, reg->vendor_id, + reg->product_code))) return -1; + if (ecrt_domain_register_pdo(domain, slave, reg->pdo_entry_index, + reg->pdo_entry_subindex, reg->data_ptr)) + return -1; + } + return 0; } /*****************************************************************************/ /** - Registers a PDO range in a domain. - \return pointer to the slave on success, else NULL - \ingroup RealtimeInterface -*/ + * Registers a PDO range in a domain. + * \return 0 on success, else non-zero + * \ingroup RealtimeInterface + */ -ec_slave_t *ecrt_domain_register_pdo_range(ec_domain_t *domain, - /**< EtherCAT domain */ - const char *address, - /**< ASCII address of the slave, - see ecrt_master_get_slave() */ - uint32_t vendor_id, - /**< vendor ID */ - uint32_t product_code, - /**< product code */ - ec_direction_t direction, - /**< data direction */ - uint16_t offset, - /**< offset in slave's PDO range */ - uint16_t length, - /**< length of this range */ - void **data_ptr - /**< address of the process data - pointer */ - ) +int ecrt_domain_register_pdo_range( + ec_domain_t *domain, /**< EtherCAT domain */ + ec_slave_t *slave, /**< EtherCAT slave */ + ec_direction_t dir, /**< data direction */ + uint16_t offset, /**< offset in slave's PDO range */ + uint16_t length, /**< length of this range */ + void **data_ptr /**< address of the process data pointer */ + ) { - ec_slave_t *slave; - ec_master_t *master; + ec_data_reg_t *data_reg; + ec_sync_t *sync; + uint16_t sync_length; - master = domain->master; - - // translate address and validate slave - if (!(slave = ecrt_master_get_slave(master, address))) return NULL; - if (ec_slave_validate(slave, vendor_id, product_code)) return NULL; - - if (ec_domain_reg_pdo_range(domain, slave, - direction, offset, length, data_ptr)) { - return NULL; + if (!(sync = ec_slave_get_pdo_sync(slave, dir))) { + EC_ERR("No sync manager found for PDO range.\n"); + return -1; } - return slave; + // Allocate memory for data registration object + if (!(data_reg = + (ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) { + EC_ERR("Failed to allocate data registration.\n"); + return -1; + } + + if (ec_slave_prepare_fmmu(slave, domain, sync)) { + EC_ERR("FMMU configuration failed.\n"); + kfree(data_reg); + return -1; + } + + data_reg->slave = slave; + data_reg->sync = sync; + data_reg->sync_offset = offset; + data_reg->data_ptr = data_ptr; + + // estimate sync manager length + sync_length = offset + length; + if (sync->est_length < sync_length) { + sync->est_length = sync_length; + if (domain->master->debug_level) { + EC_DBG("Estimating length of sync manager %i of slave %i to %i.\n", + sync->index, slave->ring_position, sync_length); + } + } + + list_add_tail(&data_reg->list, &domain->data_regs); + return 0; } /*****************************************************************************/ diff --git a/master/master.c b/master/master.c index 85b890e6..12a903c0 100644 --- a/master/master.c +++ b/master/master.c @@ -1384,6 +1384,117 @@ void ec_master_prepare(ec_master_t *master /**< EtherCAT master */) } } +/*****************************************************************************/ + +/** + * Translates an ASCII coded bus-address to a slave pointer. + * These are the valid addressing schemes: + * - \a "X" = the X. slave on the bus (ring position), + * - \a "X:Y" = the Y. slave after the X. branch (bus coupler), + * - \a "#X" = the slave with alias X, + * - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X. + * X and Y are zero-based indices and may be provided in hexadecimal or octal + * notation (with respective prefix). + * \return pointer to the slave on success, else NULL + */ + +ec_slave_t *ec_master_parse_slave_address( + const ec_master_t *master, /**< EtherCAT master */ + const char *address /**< address string */ + ) +{ + unsigned long first, second; + char *remainder, *remainder2; + const char *original; + unsigned int alias_requested, alias_found; + ec_slave_t *alias_slave = NULL, *slave; + + original = address; + + if (!address || address[0] == 0) return NULL; + + alias_requested = 0; + if (address[0] == '#') { + alias_requested = 1; + address++; + } + + first = simple_strtoul(address, &remainder, 0); + if (remainder == address) { + EC_ERR("Slave address \"%s\" - First number empty!\n", original); + return NULL; + } + + if (alias_requested) { + alias_found = 0; + list_for_each_entry(alias_slave, &master->slaves, list) { + if (alias_slave->sii_alias == first) { + alias_found = 1; + break; + } + } + if (!alias_found) { + EC_ERR("Slave address \"%s\" - Alias not found!\n", original); + return NULL; + } + } + + if (!remainder[0]) { // absolute position + if (alias_requested) { + return alias_slave; + } + else { + list_for_each_entry(slave, &master->slaves, list) { + if (slave->ring_position == first) return slave; + } + EC_ERR("Slave address \"%s\" - Absolute position invalid!\n", + original); + } + } + else if (remainder[0] == ':') { // field position + remainder++; + second = simple_strtoul(remainder, &remainder2, 0); + + if (remainder2 == remainder) { + EC_ERR("Slave address \"%s\" - Second number empty!\n", original); + return NULL; + } + + if (remainder2[0]) { + EC_ERR("Slave address \"%s\" - Invalid trailer!\n", original); + return NULL; + } + + if (alias_requested) { + if (!ec_slave_is_coupler(alias_slave)) { + EC_ERR("Slave address \"%s\": Alias slave must be bus coupler" + " in colon mode.\n", original); + return NULL; + } + list_for_each_entry(slave, &master->slaves, list) { + if (slave->coupler_index == alias_slave->coupler_index + && slave->coupler_subindex == second) + return slave; + } + EC_ERR("Slave address \"%s\" - Bus coupler %i has no %lu. slave" + " following!\n", original, alias_slave->ring_position, + second); + return NULL; + } + else { + list_for_each_entry(slave, &master->slaves, list) { + if (slave->coupler_index == first + && slave->coupler_subindex == second) return slave; + } + } + } + else + EC_ERR("Slave address \"%s\" - Invalid format!\n", original); + + return NULL; +} + + /****************************************************************************** * Realtime interface *****************************************************************************/ @@ -1578,111 +1689,27 @@ void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */) /*****************************************************************************/ /** - Translates an ASCII coded bus-address to a slave pointer. - These are the valid addressing schemes: - - \a "X" = the X. slave on the bus, - - \a "X:Y" = the Y. slave after the X. branch (bus coupler), - - \a "#X" = the slave with alias X, - - \a "#X:Y" = the Y. slave after the branch (bus coupler) with alias X. - X and Y are zero-based indices and may be provided in hexadecimal or octal - notation (with respective prefix). - \return pointer to the slave on success, else NULL - \ingroup RealtimeInterface -*/ + * Obtains a slave pointer by its bus address. + * A valid slave pointer is only returned, if vendor ID and product code are + * matching. + * \return pointer to the slave on success, else NULL + * \ingroup RealtimeInterface + */ -ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */ - const char *address /**< address string */ - ) +ec_slave_t *ecrt_master_get_slave( + const ec_master_t *master, /**< EtherCAT master */ + const char *address, /**< address string + \see ec_master_parse_slave_address() */ + uint32_t vendor_id, /**< vendor ID */ + uint32_t product_code /**< product code */ + ) { - unsigned long first, second; - char *remainder, *remainder2; - const char *original; - unsigned int alias_requested, alias_found; - ec_slave_t *alias_slave = NULL, *slave; + ec_slave_t *slave = ec_master_parse_slave_address(master, address); - original = address; - - if (!address || address[0] == 0) return NULL; - - alias_requested = 0; - if (address[0] == '#') { - alias_requested = 1; - address++; - } - - first = simple_strtoul(address, &remainder, 0); - if (remainder == address) { - EC_ERR("Slave address \"%s\" - First number empty!\n", original); + if (!slave) return NULL; - } - if (alias_requested) { - alias_found = 0; - list_for_each_entry(alias_slave, &master->slaves, list) { - if (alias_slave->sii_alias == first) { - alias_found = 1; - break; - } - } - if (!alias_found) { - EC_ERR("Slave address \"%s\" - Alias not found!\n", original); - return NULL; - } - } - - if (!remainder[0]) { // absolute position - if (alias_requested) { - return alias_slave; - } - else { - list_for_each_entry(slave, &master->slaves, list) { - if (slave->ring_position == first) return slave; - } - EC_ERR("Slave address \"%s\" - Absolute position invalid!\n", - original); - } - } - else if (remainder[0] == ':') { // field position - remainder++; - second = simple_strtoul(remainder, &remainder2, 0); - - if (remainder2 == remainder) { - EC_ERR("Slave address \"%s\" - Second number empty!\n", original); - return NULL; - } - - if (remainder2[0]) { - EC_ERR("Slave address \"%s\" - Invalid trailer!\n", original); - return NULL; - } - - if (alias_requested) { - if (!ec_slave_is_coupler(alias_slave)) { - EC_ERR("Slave address \"%s\": Alias slave must be bus coupler" - " in colon mode.\n", original); - return NULL; - } - list_for_each_entry(slave, &master->slaves, list) { - if (slave->coupler_index == alias_slave->coupler_index - && slave->coupler_subindex == second) - return slave; - } - EC_ERR("Slave address \"%s\" - Bus coupler %i has no %lu. slave" - " following!\n", original, alias_slave->ring_position, - second); - return NULL; - } - else { - list_for_each_entry(slave, &master->slaves, list) { - if (slave->coupler_index == first - && slave->coupler_subindex == second) return slave; - } - } - } - else - EC_ERR("Slave address \"%s\" - Invalid format!\n", original); - - return NULL; + return ec_slave_validate(slave, vendor_id, product_code) ? NULL : slave; } /*****************************************************************************/