Newer
Older
/******************************************************************************
*
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
* The IgH EtherCAT Master is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The IgH EtherCAT Master is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the IgH EtherCAT Master; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* The right to use EtherCAT Technology is granted and comes free of
* charge under condition of compatibility of product made by
* Licensee. People intending to distribute/sell products based on the
* code, have to sign an agreement to guarantee that products using
* software based on IgH EtherCAT master stay compatible with the actual
* EtherCAT specification (which are released themselves as an open
* standard) as the (only) precondition to have the right to use EtherCAT
* Technology, IP and trade marks.
*
*****************************************************************************/
/** \file
*
* EtherCAT Real-Time Interface.
*
* \defgroup RealtimeInterface EtherCAT Real-Time Interface
*
* EtherCAT interface for realtime modules. This interface is designed for
* realtime modules that want to use EtherCAT. There are functions to request
* a master, to map process data, to communicate with slaves via CoE and to
* configure and activate the bus.
*
* Changes in Version 1.4:
*
* - Replaced ec_slave_t with ec_slave_config_t, separating the slave objects
* from the requested bus configuration. Therefore, renamed
* ecrt_master_get_slave() to ecrt_master_slave_config().
* - Replaced slave address string with alias and position values. See
* ecrt_master_slave_config().
* - Removed ecrt_master_get_slave_by_pos(), because it is no longer
* necessary due to alias/position addressing.
* - Added ec_slave_config_state_t for the new method
* ecrt_slave_config_state().
* - Process data memory for a domain can now be allocated externally. This
* offers the possibility to use a shared-memory region. Therefore,
* added the domain methods ecrt_domain_size() and
* ecrt_domain_external_memory().
* - Replaced the process data pointers in the Pdo entry registration
* functions with a process data offset, that is now returned by
* ecrt_slave_config_reg_pdo_entry(). This was necessary for the external
* domain memory. An additional advantage is, that the returned offset value
* is directly usable. If the domain's process data is allocated internally,
* the start address can be retrieved with ecrt_domain_data().
* - Replaced ecrt_slave_pdo_mapping/add/clear() with
* ecrt_slave_config_pdo() to add a Pdo to the mapping and
* ecrt_slave_config_pdo_entry() to add a Pdo entry to a Pdo configuration.
* ecrt_slave_config_mapping() is a convenience function for
* both, that uses the new data types ec_pdo_info_t and ec_pdo_entry_info_t.
* Mapped Pdo entries can now immediately be registered.
* - Renamed ec_bus_status_t, ec_master_status_t to ec_bus_state_t and
* ec_master_state_t, respectively. Renamed ecrt_master_get_status() to
* ecrt_master_state(), for consistency reasons.
* - Added ec_domain_state_t and ec_wc_state_t for a new output parameter
* of ecrt_domain_state(). The domain state object does now contain
* information, if the process data was exchanged completely.
* - Former "Pdo registration" meant Pdo entry registration in fact, therefore
* renamed ec_pdo_reg_t to ec_pdo_entry_reg_t and ecrt_domain_register_pdo()
* to ecrt_slave_config_reg_pdo_entry().
* - Removed ecrt_domain_register_pdo_range(), because it's functionality can
* be reached by specifying an explicit Pdo mapping and registering those
* Pdo entries.
*
* @{
/*****************************************************************************/
#include <asm/byteorder.h>
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
/******************************************************************************
* Global definitions
*****************************************************************************/
/** EtherCAT real-time interface major version number.
#define ECRT_VER_MAJOR 1
/** EtherCAT real-time interface minor version number.
/** EtherCAT real-time interface version word generator.
/** EtherCAT real-time interface version word.
#define ECRT_VERSION_MAGIC ECRT_VERSION(ECRT_VER_MAJOR, ECRT_VER_MINOR)
/******************************************************************************
* Data types
*****************************************************************************/
struct ec_master;
typedef struct ec_master ec_master_t; /**< \see ec_master */
struct ec_slave_config;
typedef struct ec_slave_config ec_slave_config_t; /**< \see ec_slave_config */
struct ec_domain;
typedef struct ec_domain ec_domain_t; /**< \see ec_domain */
/*****************************************************************************/
/** Bus state.
*
* This is used in ec_master_state_t.
typedef enum {
EC_BUS_FAILURE = -1, /**< At least one configured slave is offline. */
EC_BUS_OK /**< All configured slaves are online. */
} ec_bus_state_t;
/*****************************************************************************/
/** Master state.
*
* This is used for the output parameter of ecrt_master_state().
*/
typedef struct {
ec_bus_state_t bus_state; /**< \see ec_bus_state_t */
unsigned int bus_tainted; /**< Non-zero, if the bus topology differs from
the requested configuration. */
unsigned int slaves_responding; /**< Number of slaves in the bus. */
} ec_master_state_t;
/*****************************************************************************/
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/** Slave configuration state.
*
* \see ecrt_slave_config_state().
*/
typedef struct {
unsigned int online : 1; /**< The slave is online. */
unsigned int configured : 1; /**< The slave was configured according to
the specified configuration. */
} ec_slave_config_state_t;
/*****************************************************************************/
/** Domain working counter interpretation.
*
* This is used in ec_domain_state_t.
*/
typedef enum {
EC_WC_ZERO = 0, /**< No Pdos were exchanged. */
EC_WC_INCOMPLETE, /**< Some of the registered Pdos were exchanged. */
EC_WC_COMPLETE /**< All registered Pdos were exchanged. */
} ec_wc_state_t;
/*****************************************************************************/
/** Domain state.
*
* This is used for the output parameter of ecrt_domain_state().
*/
typedef struct {
unsigned int working_counter; /**< Value of the last working counter. */
ec_wc_state_t wc_state; /**< Working counter interpretation. */
} ec_domain_state_t;
/*****************************************************************************/
/** Direction type for Pdo mapping functions.
typedef enum {
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
EC_DIR_OUTPUT, /**< Values written by the master. */
EC_DIR_INPUT /**< Values read by the master. */
} ec_direction_t;
/*****************************************************************************/
/** Pdo entry mapping.
*
* \see ecrt_slave_config_mapping().
*/
typedef struct {
uint16_t index; /**< Index of the Pdo entry to add to the Pdo
configuration. */
uint8_t subindex; /**< Subindex of the Pdo entry to add to the
Pdo configuration. */
uint8_t bit_length; /**< Size of the Pdo entry in bit. */
} ec_pdo_entry_info_t;
/*****************************************************************************/
/** Pdo information.
*
* \see ecrt_slave_config_mapping().
*/
typedef struct {
ec_direction_t dir; /**< Pdo direction (input/output). */
uint16_t index; /**< Index of the Pdo to map. */
unsigned int n_entries; /**< Number of Pdo entries for the Pdo
configuration. Zero means, that the default Pdo
configuration shall be used. */
const ec_pdo_entry_info_t *entries; /**< Pdo configuration array. This
array must contain at least \a
n_entries values. */
} ec_pdo_info_t;
/*****************************************************************************/
/** List record type for Pdo entry mass-registration.
*
* This type is used for the array parameter of the
* ecrt_domain_reg_pdo_entry_list() convenience function.
*/
typedef struct {
uint16_t alias; /**< Slave alias address. */
uint16_t position; /**< Slave position. */
uint32_t vendor_id; /**< Slave vendor ID. */
uint32_t product_code; /**< Slave product code. */
uint16_t index; /**< Pdo entry index. */
uint8_t subindex; /**< Pdo entry subindex. */
unsigned int *offset; /**< Pointer to a variable to store the Pdo's
offset in the process data. */
} ec_pdo_entry_reg_t;
/******************************************************************************
*****************************************************************************/
/** Returns the version magic of the realtime interface.
*
* \return Value of ECRT_VERSION_MAGIC() at EtherCAT master compile time.
*/
unsigned int ecrt_version_magic(void);
/** Requests an EtherCAT master for realtime operation.
*
* \return pointer to reserved master, or NULL on error
*/
ec_master_t *ecrt_request_master(
unsigned int master_index /**< Index of the master to request. */
);
/** Releases a requested EtherCAT master.
*/
void ecrt_release_master(
ec_master_t *master /**< EtherCAT master */
);
/******************************************************************************
*****************************************************************************/
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/** Sets the locking callbacks.
*
* The request_cb function must return zero, to allow another instance
* (the EoE process for example) to access the master. Non-zero means,
* that access is forbidden at this time.
*/
void ecrt_master_callbacks(
ec_master_t *master, /**< EtherCAT master */
int (*request_cb)(void *), /**< Lock request function. */
void (*release_cb)(void *), /**< Lock release function. */
void *cb_data /**< Arbitrary user data. */
);
/** Creates a new domain.
*
* \return Pointer to the new domain on success, else NULL.
*/
ec_domain_t *ecrt_master_create_domain(
ec_master_t *master /**< EtherCAT master. */
);
/** Obtains a slave configuration.
*
* Creates a slave configuration object for the given \a alias and \a position
* tuple and returns it. If a configuration with the same \a alias and \a
* position already exists, it will be re-used. In the latter case, the given
* vendor ID and product code are compared to the stored ones. On mismatch, an
* error message is raised and the function returns \a NULL.
*
* Slaves are addressed with the \a alias and \a position parameters.
* - If \a alias is zero, \a position is interpreted as the desired slave's
* ring position.
* - If \a alias is non-zero, it matches a slave with the given alias. In this
* case, \a position is interpreted as ring offset, starting from the
* aliased slave, so a position of zero means the aliased slave itself and a
* positive value matches the n-th slave behind the aliased one.
*
* If the slave with the given address is found during the bus configuration,
* its vendor ID and product code are matched against the given value. On
* mismatch, the slave is not configured and an error message is raised.
*
* If different slave configurations are pointing to the same slave during bus
* configuration, a warning is raised and only the first configuration is
* applied.
*
* \retval >0 Pointer to the slave configuration structure.
* \retval NULL in the error case.
*/
ec_slave_config_t *ecrt_master_slave_config(
ec_master_t *master, /**< EtherCAT master */
uint16_t alias, /**< Slave alias. */
uint16_t position, /**< Slave position. */
uint32_t vendor_id, /**< Expected vendor ID. */
uint32_t product_code /**< Expected product code. */
);
/** Applies the bus configuration and switches to realtime mode.
*
* 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
*/
int ecrt_master_activate(
ec_master_t *master /**< EtherCAT master. */
);
/** Sends all datagrams in the queue.
*
* \todo doc
*/
void ecrt_master_send(
ec_master_t *master /**< EtherCAT master. */
);
/** Fetches received frames from the hardware and processes the datagrams.
*/
void ecrt_master_receive(
ec_master_t *master /**< EtherCAT master. */
);
/** Reads the current master state.
*
* Stores the master state information in the given \a state structure.
*/
void ecrt_master_state(
const ec_master_t *master, /**< EtherCAT master. */
ec_master_state_t *state /**< Structure to store the information. */
);
/******************************************************************************
* Slave configuration methods
*****************************************************************************/
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/** Add a Pdo to the slave's Pdo mapping for the given direction.
*
* The first call of this function for a given \a dir will clear the default
* mapping.
*
* \see ecrt_slave_config_mapping()
* \return zero on success, else non-zero
*/
int ecrt_slave_config_pdo(
ec_slave_config_t *sc, /**< Slave configuration. */
ec_direction_t dir, /**< Pdo direction (input/output). */
uint16_t index /**< Index of the Pdo to map. */
);
/** Add a Pdo entry to the given Pdo's configuration.
*
* The first call of this function for a given \a pdo_index will clear the
* default Pdo configuration.
*
* \see ecrt_slave_config_mapping()
* \return zero on success, else non-zero
*/
int ecrt_slave_config_pdo_entry(
ec_slave_config_t *sc, /**< Slave configuration. */
uint16_t pdo_index, /**< Index of the Pdo to configure. */
uint16_t entry_index, /**< Index of the Pdo entry to add to the Pdo's
configuration. */
uint8_t entry_subindex, /**< Subindex of the Pdo entry to add to the
Pdo's configuration. */
uint8_t entry_bit_length /**< Size of the Pdo entry in bit. */
);
/** Specify the Pdo mapping and (optionally) the Pdo configuration.
*
* This function is a convenience function for the ecrt_slave_config_pdo()
* and ecrt_slave_config_pdo_entry() functions, that are better suitable
* for automatic code generation.
*
* The following example shows, how to specify a complete Pdo mapping
* including the Pdo configuration. With this information, the master is able
* to reserve the complete process data, even if the slave is not present
* at configuration time:
*
* \code
* const ec_pdo_entry_info_t el3162_channel1[] = {
* {0x3101, 1, 8}, // status
* {0x3101, 2, 16} // value
* };
*
* const ec_pdo_entry_info_t el3162_channel2[] = {
* {0x3102, 1, 8}, // status
* {0x3102, 2, 16} // value
* };
*
* const ec_pdo_info_t el3162_mapping[] = {
* {EC_DIR_INPUT, 0x1A00, 2, el3162_channel1},
* {EC_DIR_INPUT, 0x1A01, 2, el3162_channel2},
* };
*
* if (ecrt_slave_config_mapping(sc, 2, el3162_mapping))
* return -1; // error
* \endcode
*
* The next example shows, how to configure only the Pdo mapping. The entries
* for each mapped Pdo are taken from the default Pdo configuration. Please
* note, that Pdo entry registration will fail, if the Pdo configuration is
* left empty and the slave is offline.
*
* \code
* const ec_pdo_info_t pdo_mapping[] = {
* {EC_DIR_INPUT, 0x1600}, // Channel 1
* {EC_DIR_INPUT, 0x1601} // Channel 2
* };
*
* if (ecrt_slave_config_mapping(slave_config_ana_in, 2, pdo_mapping))
* return -1; // error
* \endcode
*
* \return zero on success, else non-zero
*/
int ecrt_slave_config_mapping(
ec_slave_config_t *sc, /**< Slave configuration. */
unsigned int n_infos, /**< Number of Pdo infos in \a pdo_infos. */
const ec_pdo_info_t pdo_infos[] /**< List with Pdo mapping. */
);
/** Registers a Pdo entry for process data exchange in a domain.
* Searches the current mapping and Pdo configurations for the given Pdo
* entry. An error is raised, if the given entry is not mapped. Otherwise, the
* corresponding sync manager and FMMU configurations are provided for slave
* configuration and the respective sync manager's Pdos are appended to the
* given domain, if not already done. The offset of the requested Pdo entry's
* data inside the domain's process data is returned.
* \retval >=0 Success: Offset of the Pdo entry's process data.
* \retval -1 Error: Pdo entry not found.
* \retval -2 Error: Failed to register Pdo entry.
*/
int ecrt_slave_config_reg_pdo_entry(
ec_slave_config_t *sc, /**< Slave configuration. */
uint16_t entry_index, /**< Index of the Pdo entry to register. */
uint8_t entry_subindex, /**< Subindex of the Pdo entry to register. */
ec_domain_t *domain /**< Domain. */
);
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
/** Add a configuration value for an 8-bit SDO.
*
* \todo doc
* \return 0 in case of success, else < 0
*/
int ecrt_slave_config_sdo8(
ec_slave_config_t *sc, /**< Slave configuration */
uint16_t sdo_index, /**< Index of the SDO to configure. */
uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
uint8_t value /**< Value to set. */
);
/** Add a configuration value for a 16-bit SDO.
*
* \todo doc
* \return 0 in case of success, else < 0
*/
int ecrt_slave_config_sdo16(
ec_slave_config_t *sc, /**< Slave configuration */
uint16_t sdo_index, /**< Index of the SDO to configure. */
uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
uint16_t value /**< Value to set. */
);
/** Add a configuration value for a 32-bit SDO.
*
* \todo doc
* \return 0 in case of success, else < 0
*/
int ecrt_slave_config_sdo32(
ec_slave_config_t *sc, /**< Slave configuration */
uint16_t sdo_index, /**< Index of the SDO to configure. */
uint8_t sdo_subindex, /**< Subindex of the SDO to configure. */
uint32_t value /**< Value to set. */
);
/** Outputs the state of the slave configuration.
*
* Stores the state information in the given \a state structure.
*/
void ecrt_slave_config_state(
const ec_slave_config_t *sc, /**< Slave configuration */
ec_slave_config_state_t *state /**< State object to write to. */
);
/******************************************************************************
*****************************************************************************/
/** Registers a bunch of Pdo entries for a domain.
*
* \todo doc
* \attention The registration array has to be terminated with an empty
* structure, or one with the \a index field set to zero!
* \return 0 on success, else non-zero.
*/
int ecrt_domain_reg_pdo_entry_list(
ec_domain_t *domain, /**< Domain. */
const ec_pdo_entry_reg_t *pdo_entry_regs /**< Array of Pdo
registrations. */
);
/** Returns the current size of the domain's process data.
*
* \return Size of the process data image.
*/
size_t ecrt_domain_size(
ec_domain_t *domain /**< Domain. */
);
/** Provide external memory to store the domain's process data.
* Call this after all Pdo entries have been registered and before activating
* the master.
* The size of the allocated memory must be at least ecrt_domain_size(), after
* all Pdo entries have been registered.
ec_domain_t *domain, /**< Domain. */
uint8_t *memory /**< Address of the memory to store the process
data in. */
);
/** Returns the domain's process data.
*
* If external memory was provided with ecrt_domain_external_memory(), the
* returned pointer will contain the address of that memory. Otherwise it will
* point to the internally allocated memory.
*
* \return Pointer to the process data memory.
*/
uint8_t *ecrt_domain_data(
ec_domain_t *domain /**< Domain. */
);
/** Processes received datagrams.
*
* \todo doc
*/
void ecrt_domain_process(
ec_domain_t *domain /**< Domain. */
);
/** (Re-)queues all domain datagrams in the master's datagram queue.
*
* \todo doc
*/
void ecrt_domain_queue(
ec_domain_t *domain /**< Domain. */
);
/** Reads the state of a domain.
*
* Stores the domain state in the giveb \a state structure.
*/
void ecrt_domain_state(
const ec_domain_t *domain, /**< Domain. */
ec_domain_state_t *state /**< Pointer to a state object to store the
information. */
);
/******************************************************************************
*****************************************************************************/
/** 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
*/
#define EC_WRITE_BIT(DATA, POS, VAL) \
if (VAL) *((uint8_t *) (DATA)) |= (1 << (POS)); \
else *((uint8_t *) (DATA)) &= ~(1 << (POS)); \
} while (0)
/******************************************************************************
*****************************************************************************/
/** 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
*/
#define EC_READ_S8(DATA) \
/** 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
*/
#define EC_READ_S16(DATA) \
/** 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
*/
#define EC_READ_S32(DATA) \
/******************************************************************************
*****************************************************************************/
/** Write an 8-bit unsigned value to EtherCAT data.
* \param DATA EtherCAT data pointer
* \param VAL new value
*/
#define EC_WRITE_U8(DATA, VAL) \
*((uint8_t *)(DATA)) = ((uint8_t) (VAL)); \
} while (0)
/** 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
*/
#define EC_WRITE_U16(DATA, VAL) \
*((uint16_t *) (DATA)) = (uint16_t) (VAL); \
cpu_to_le16s((uint16_t *) (DATA)); \
} while (0)
/** 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
*/
#define EC_WRITE_U32(DATA, VAL) \
*((uint32_t *) (DATA)) = (uint32_t) (VAL); \
cpu_to_le32s((uint32_t *) (DATA)); \
} while (0)
/** 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)
/*****************************************************************************/
/** @} */