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.
This commit is contained in:
Florian Pose 2007-03-09 10:24:50 +00:00
parent 8ac6516b4e
commit 70482be0ac
6 changed files with 364 additions and 350 deletions

6
NEWS
View File

@ -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

2
TODO
View File

@ -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.

View File

@ -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 */

View File

@ -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)

View File

@ -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;
}
/*****************************************************************************/

View File

@ -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;
}
/*****************************************************************************/