# HG changeset patch # User Florian Pose # Date 1173435890 0 # Node ID 16e9ad7d8e12c615084f1bf7d3cbf5a05079330c # Parent aa23c48dca2da296287d9d1e6565ec3f0c154cd3 Added parameters for vendor ID and product code to ecrt_get_slave(); PDO registration functions now take a slave pointer as argument; changed values for ec_bus_status_t. diff -r aa23c48dca2d -r 16e9ad7d8e12 NEWS --- a/NEWS Thu Mar 08 18:15:25 2007 +0000 +++ b/NEWS Fri Mar 09 10:24:50 2007 +0000 @@ -17,6 +17,12 @@ * 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 -r aa23c48dca2d -r 16e9ad7d8e12 TODO --- a/TODO Thu Mar 08 18:15:25 2007 +0000 +++ b/TODO Fri Mar 09 10:24:50 2007 +0000 @@ -9,8 +9,6 @@ * 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 -r aa23c48dca2d -r 16e9ad7d8e12 include/ecdb.h --- a/include/ecdb.h Thu Mar 08 18:15:25 2007 +0000 +++ b/include/ecdb.h Fri Mar 09 10:24:50 2007 +0000 @@ -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 -r aa23c48dca2d -r 16e9ad7d8e12 include/ecrt.h --- a/include/ecrt.h Thu Mar 08 18:15:25 2007 +0000 +++ b/include/ecrt.h Fri Mar 09 10:24:50 2007 +0000 @@ -81,9 +81,10 @@ */ 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 @@ */ 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. -*/ - -typedef struct -{ - const char *slave_address; /**< slave address string (see - ecrt_master_get_slave()) */ + * 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 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 @@ 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 @@ 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 @@ *****************************************************************************/ /** - 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 @@ *****************************************************************************/ /** - 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 @@ } 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 @@ } 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 @@ } 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 -r aa23c48dca2d -r 16e9ad7d8e12 master/domain.c --- a/master/domain.c Thu Mar 08 18:15:25 2007 +0000 +++ b/master/domain.c Fri Mar 09 10:24:50 2007 +0000 @@ -236,64 +236,6 @@ /*****************************************************************************/ /** - 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 @@ /** * 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 @@ 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 -*/ - -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 */ - ) -{ - ec_slave_t *slave; - ec_master_t *master; - - 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; - } - - return slave; + * Registers a PDO range in a domain. + * \return 0 on success, else non-zero + * \ingroup RealtimeInterface + */ + +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_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; } /*****************************************************************************/ diff -r aa23c48dca2d -r 16e9ad7d8e12 master/master.c --- a/master/master.c Thu Mar 08 18:15:25 2007 +0000 +++ b/master/master.c Fri Mar 09 10:24:50 2007 +0000 @@ -1384,215 +1384,24 @@ } } -/****************************************************************************** - * Realtime interface - *****************************************************************************/ - -/** - Creates a domain. - \return pointer to new domain on success, else NULL - \ingroup RealtimeInterface -*/ - -ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */) -{ - ec_domain_t *domain, *last_domain; - unsigned int index; - - if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) { - EC_ERR("Error allocating domain memory!\n"); - return NULL; - } - - if (list_empty(&master->domains)) index = 0; - else { - last_domain = list_entry(master->domains.prev, ec_domain_t, list); - index = last_domain->index + 1; - } - - if (ec_domain_init(domain, master, index)) { - EC_ERR("Failed to init domain.\n"); - return NULL; - } - - list_add_tail(&domain->list, &master->domains); - - return domain; -} - -/*****************************************************************************/ - -/** - Configures all slaves and leads them to the OP state. - Does the complete configuration and activation for all slaves. Sets sync - managers and FMMUs, and does the appropriate transitions, until the slave - is operational. - \return 0 in case of success, else < 0 - \ingroup RealtimeInterface -*/ - -int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */) -{ - uint32_t domain_offset; - ec_domain_t *domain; - ec_fsm_slave_t fsm_slave; - ec_slave_t *slave; - - // allocate all domains - domain_offset = 0; - list_for_each_entry(domain, &master->domains, list) { - if (ec_domain_alloc(domain, domain_offset)) { - EC_ERR("Failed to allocate domain %X!\n", (u32) domain); - return -1; - } - domain_offset += domain->data_size; - } - - ec_fsm_slave_init(&fsm_slave, &master->fsm_datagram); - - // configure all slaves - list_for_each_entry(slave, &master->slaves, list) { - ec_fsm_slave_start_conf(&fsm_slave, slave); - while (ec_fsm_slave_exec(&fsm_slave)) { - ec_master_queue_datagram(master, &master->fsm_datagram); - ec_master_sync_io(master); - } - - if (!ec_fsm_slave_success(&fsm_slave)) { - ec_fsm_slave_clear(&fsm_slave); - EC_ERR("Failed to configure slave %i!\n", slave->ring_position); - return -1; - } - } - - ec_fsm_slave_clear(&fsm_slave); - ec_master_prepare(master); // prepare asynchronous IO - - if (master->debug_level) - EC_DBG("FSM datagram is %x.\n", (unsigned int) &master->fsm_datagram); - - if (ec_master_thread_start(master)) { - EC_ERR("Failed to start master thread!\n"); - return -1; - } - - return 0; -} - -/*****************************************************************************/ - -/** - Sends queued datagrams and waits for their reception. -*/ - -void ec_master_sync_io(ec_master_t *master /**< EtherCAT master */) -{ - ec_datagram_t *datagram; - unsigned int datagrams_sent; - - // send all datagrams - ecrt_master_send(master); - - while (1) { // active waiting - schedule(); // schedule other processes while waiting. - ecrt_master_receive(master); // receive and dequeue datagrams - - // count number of datagrams still waiting for response - datagrams_sent = 0; - list_for_each_entry(datagram, &master->datagram_queue, queue) { - // there may be another process that queued commands - // in the meantime. - if (datagram->state == EC_DATAGRAM_QUEUED) continue; - datagrams_sent++; - } - - // abort loop if there are no more datagrams marked as sent. - if (!datagrams_sent) break; - } -} - -/*****************************************************************************/ - -/** - Asynchronous sending of datagrams. - \ingroup RealtimeInterface -*/ - -void ecrt_master_send(ec_master_t *master /**< EtherCAT master */) -{ - ec_datagram_t *datagram, *n; - - if (master->injection_seq_rt != master->injection_seq_fsm) { - // inject datagram produced by master FSM - ec_master_queue_datagram(master, &master->fsm_datagram); - master->injection_seq_rt = master->injection_seq_fsm; - } - - if (unlikely(!master->main_device.link_state)) { - // link is down, no datagram can be sent - list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) { - datagram->state = EC_DATAGRAM_ERROR; - list_del_init(&datagram->queue); - } - - // query link state - ec_device_poll(&master->main_device); - return; - } - - // send frames - ec_master_send_datagrams(master); -} - -/*****************************************************************************/ - -/** - Asynchronous receiving of datagrams. - \ingroup RealtimeInterface -*/ - -void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */) -{ - ec_datagram_t *datagram, *next; - cycles_t cycles_timeout; - - // receive datagrams - ec_device_poll(&master->main_device); - - cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000); - - // dequeue all datagrams that timed out - list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) { - if (datagram->state != EC_DATAGRAM_SENT) continue; - - if (master->main_device.cycles_poll - datagram->cycles_sent - > cycles_timeout) { - list_del_init(&datagram->queue); - datagram->state = EC_DATAGRAM_TIMED_OUT; - master->stats.timeouts++; - ec_master_output_stats(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 -*/ - -ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */ - const char *address /**< address string */ - ) +/*****************************************************************************/ + +/** + * 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; @@ -1685,6 +1494,224 @@ return NULL; } + +/****************************************************************************** + * Realtime interface + *****************************************************************************/ + +/** + Creates a domain. + \return pointer to new domain on success, else NULL + \ingroup RealtimeInterface +*/ + +ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */) +{ + ec_domain_t *domain, *last_domain; + unsigned int index; + + if (!(domain = (ec_domain_t *) kmalloc(sizeof(ec_domain_t), GFP_KERNEL))) { + EC_ERR("Error allocating domain memory!\n"); + return NULL; + } + + if (list_empty(&master->domains)) index = 0; + else { + last_domain = list_entry(master->domains.prev, ec_domain_t, list); + index = last_domain->index + 1; + } + + if (ec_domain_init(domain, master, index)) { + EC_ERR("Failed to init domain.\n"); + return NULL; + } + + list_add_tail(&domain->list, &master->domains); + + return domain; +} + +/*****************************************************************************/ + +/** + Configures all slaves and leads them to the OP state. + Does the complete configuration and activation for all slaves. Sets sync + managers and FMMUs, and does the appropriate transitions, until the slave + is operational. + \return 0 in case of success, else < 0 + \ingroup RealtimeInterface +*/ + +int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */) +{ + uint32_t domain_offset; + ec_domain_t *domain; + ec_fsm_slave_t fsm_slave; + ec_slave_t *slave; + + // allocate all domains + domain_offset = 0; + list_for_each_entry(domain, &master->domains, list) { + if (ec_domain_alloc(domain, domain_offset)) { + EC_ERR("Failed to allocate domain %X!\n", (u32) domain); + return -1; + } + domain_offset += domain->data_size; + } + + ec_fsm_slave_init(&fsm_slave, &master->fsm_datagram); + + // configure all slaves + list_for_each_entry(slave, &master->slaves, list) { + ec_fsm_slave_start_conf(&fsm_slave, slave); + while (ec_fsm_slave_exec(&fsm_slave)) { + ec_master_queue_datagram(master, &master->fsm_datagram); + ec_master_sync_io(master); + } + + if (!ec_fsm_slave_success(&fsm_slave)) { + ec_fsm_slave_clear(&fsm_slave); + EC_ERR("Failed to configure slave %i!\n", slave->ring_position); + return -1; + } + } + + ec_fsm_slave_clear(&fsm_slave); + ec_master_prepare(master); // prepare asynchronous IO + + if (master->debug_level) + EC_DBG("FSM datagram is %x.\n", (unsigned int) &master->fsm_datagram); + + if (ec_master_thread_start(master)) { + EC_ERR("Failed to start master thread!\n"); + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +/** + Sends queued datagrams and waits for their reception. +*/ + +void ec_master_sync_io(ec_master_t *master /**< EtherCAT master */) +{ + ec_datagram_t *datagram; + unsigned int datagrams_sent; + + // send all datagrams + ecrt_master_send(master); + + while (1) { // active waiting + schedule(); // schedule other processes while waiting. + ecrt_master_receive(master); // receive and dequeue datagrams + + // count number of datagrams still waiting for response + datagrams_sent = 0; + list_for_each_entry(datagram, &master->datagram_queue, queue) { + // there may be another process that queued commands + // in the meantime. + if (datagram->state == EC_DATAGRAM_QUEUED) continue; + datagrams_sent++; + } + + // abort loop if there are no more datagrams marked as sent. + if (!datagrams_sent) break; + } +} + +/*****************************************************************************/ + +/** + Asynchronous sending of datagrams. + \ingroup RealtimeInterface +*/ + +void ecrt_master_send(ec_master_t *master /**< EtherCAT master */) +{ + ec_datagram_t *datagram, *n; + + if (master->injection_seq_rt != master->injection_seq_fsm) { + // inject datagram produced by master FSM + ec_master_queue_datagram(master, &master->fsm_datagram); + master->injection_seq_rt = master->injection_seq_fsm; + } + + if (unlikely(!master->main_device.link_state)) { + // link is down, no datagram can be sent + list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) { + datagram->state = EC_DATAGRAM_ERROR; + list_del_init(&datagram->queue); + } + + // query link state + ec_device_poll(&master->main_device); + return; + } + + // send frames + ec_master_send_datagrams(master); +} + +/*****************************************************************************/ + +/** + Asynchronous receiving of datagrams. + \ingroup RealtimeInterface +*/ + +void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */) +{ + ec_datagram_t *datagram, *next; + cycles_t cycles_timeout; + + // receive datagrams + ec_device_poll(&master->main_device); + + cycles_timeout = (cycles_t) EC_IO_TIMEOUT /* us */ * (cpu_khz / 1000); + + // dequeue all datagrams that timed out + list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) { + if (datagram->state != EC_DATAGRAM_SENT) continue; + + if (master->main_device.cycles_poll - datagram->cycles_sent + > cycles_timeout) { + list_del_init(&datagram->queue); + datagram->state = EC_DATAGRAM_TIMED_OUT; + master->stats.timeouts++; + ec_master_output_stats(master); + } + } +} + +/*****************************************************************************/ + +/** + * 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, /**< 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 */ + ) +{ + ec_slave_t *slave = ec_master_parse_slave_address(master, address); + + if (!slave) + return NULL; + + return ec_slave_validate(slave, vendor_id, product_code) ? NULL : slave; +} + /*****************************************************************************/ /**